1 diff -up openssh-5.8p1/auth2-pubkey.c.akc openssh-5.8p1/auth2-pubkey.c
2 --- openssh-5.8p1/auth2-pubkey.c.akc 2011-02-10 13:21:27.000000000 +0100
3 +++ openssh-5.8p1/auth2-pubkey.c 2011-02-10 13:21:28.000000000 +0100
12 @@ -268,27 +269,15 @@ match_principals_file(char *file, struct
14 /* return 1 if user allows given key */
16 -user_key_allowed2(struct passwd *pw, Key *key, char *file)
17 +user_search_key_in_file(FILE *f, char *file, Key* key, struct passwd *pw)
19 char line[SSH_MAX_PUBKEY_BYTES];
27 - /* Temporarily use the user's uid. */
28 - temporarily_use_uid(pw);
30 - debug("trying public key file %s", file);
31 - f = auth_openkeyfile(file, pw, options.strict_modes);
39 found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type);
41 @@ -381,8 +370,6 @@ user_key_allowed2(struct passwd *pw, Key
49 debug2("key not found");
50 @@ -444,13 +431,191 @@ user_cert_trusted_ca(struct passwd *pw,
54 -/* check whether given key is in .ssh/authorized_keys* */
55 +/* return 1 if user allows given key */
57 +user_key_allowed2(struct passwd *pw, Key *key, char *file)
62 + /* Temporarily use the user's uid. */
63 + temporarily_use_uid(pw);
65 + debug("trying public key file %s", file);
66 + f = auth_openkeyfile(file, pw, options.strict_modes);
69 + found_key = user_search_key_in_file (f, file, key, pw);
77 +#ifdef WITH_AUTHORIZED_KEYS_COMMAND
79 +#define WHITESPACE " \t\r\n"
81 +/* return 1 if user allows given key */
83 +user_key_via_command_allowed2(struct passwd *pw, Key *key)
87 + char *progname = NULL;
89 + struct passwd *runas_pw;
91 + int childdescriptors[2], i;
92 + pid_t pstat, pid, child;
94 + if (options.authorized_keys_command == NULL || options.authorized_keys_command[0] != '/')
97 + /* get the run as identity from config */
98 + runas_pw = (options.authorized_keys_command_runas == NULL)? pw
99 + : getpwnam (options.authorized_keys_command_runas);
101 + error("%s: getpwnam(\"%s\"): %s", __func__,
102 + options.authorized_keys_command_runas, strerror(errno));
106 + /* Temporarily use the specified uid. */
107 + if (runas_pw->pw_uid != 0)
108 + temporarily_use_uid(runas_pw);
110 + progname = xstrdup(options.authorized_keys_command);
112 + debug3("%s: checking program '%s'", __func__, progname);
114 + if (stat (progname, &st) < 0) {
115 + error("%s: stat(\"%s\"): %s", __func__,
116 + progname, strerror(errno));
120 + if (st.st_uid != 0 || (st.st_mode & 022) != 0) {
121 + error("bad ownership or modes for AuthorizedKeysCommand \"%s\"",
126 + if (!S_ISREG(st.st_mode)) {
127 + error("AuthorizedKeysCommand \"%s\" is not a regular file",
133 + * Descend the path, checking that each component is a
134 + * root-owned directory with strict permissions.
137 + if ((cp = strrchr(progname, '/')) == NULL)
142 + debug3("%s: checking component '%s'", __func__, (*progname == '\0' ? "/" : progname));
144 + if (stat((*progname == '\0' ? "/" : progname), &st) != 0) {
145 + error("%s: stat(\"%s\"): %s", __func__,
146 + progname, strerror(errno));
149 + if (st.st_uid != 0 || (st.st_mode & 022) != 0) {
150 + error("bad ownership or modes for AuthorizedKeysCommand path component \"%s\"",
154 + if (!S_ISDIR(st.st_mode)) {
155 + error("AuthorizedKeysCommand path component \"%s\" is not a directory",
161 + /* open the pipe and read the keys */
162 + if (pipe(childdescriptors)) {
163 + error("failed to pipe(2) for AuthorizedKeysCommand: %s",
170 + error("failed to fork(2) for AuthorizedKeysCommand: %s",
173 + } else if (child == 0) {
174 + /* we're in the child process here -- we should never return from this block. */
175 + /* permanently drop privs in child process */
176 + if (runas_pw->pw_uid != 0) {
178 + permanently_set_uid(runas_pw);
181 + close(childdescriptors[0]);
182 + /* put the write end of the pipe on stdout (FD 1) */
183 + if (dup2(childdescriptors[1], 1) == -1) {
184 + error("failed to dup2(2) from AuthorizedKeysCommand: %s",
189 + debug3("about to execl() AuthorizedKeysCommand: \"%s\" \"%s\"", options.authorized_keys_command, pw->pw_name);
190 + /* see session.c:child_close_fds() */
191 + for (i = 3; i < 64; ++i) {
195 + execl(options.authorized_keys_command, options.authorized_keys_command, pw->pw_name, NULL);
197 + /* if we got here, it didn't work */
198 + error("failed to execl AuthorizedKeysCommand: %s", strerror(errno)); /* this won't work because we closed the fds above */
202 + close(childdescriptors[1]);
203 + f = fdopen(childdescriptors[0], "r");
205 + error("%s: could not buffer FDs from AuthorizedKeysCommand (\"%s\", \"r\"): %s", __func__,
206 + options.authorized_keys_command, strerror (errno));
210 + found_key = user_search_key_in_file (f, options.authorized_keys_command, key, pw);
213 + pid = waitpid(child, &pstat, 0);
214 + } while (pid == -1 && errno == EINTR);
216 + /* what about the return value from the child process? */
221 + if (runas_pw->pw_uid != 0)
227 +/* check whether given key is in <AuthorizedKeysCommand or .ssh/authorized_keys* */
229 user_key_allowed(struct passwd *pw, Key *key)
234 +#ifdef WITH_AUTHORIZED_KEYS_COMMAND
235 + success = user_key_via_command_allowed2(pw, key);
240 if (auth_key_is_revoked(key))
242 if (key_is_cert(key) && auth_key_is_revoked(key->cert->signature_key))
243 diff -up openssh-5.8p1/configure.ac.akc openssh-5.8p1/configure.ac
244 --- openssh-5.8p1/configure.ac.akc 2011-02-10 13:21:28.000000000 +0100
245 +++ openssh-5.8p1/configure.ac 2011-02-10 13:21:28.000000000 +0100
246 @@ -1422,6 +1422,18 @@ AC_ARG_WITH(audit,
250 +# Check whether user wants AuthorizedKeysCommand support
252 +AC_ARG_WITH(authorized-keys-command,
253 + [ --with-authorized-keys-command Enable AuthorizedKeysCommand support],
255 + if test "x$withval" != "xno" ; then
256 + AC_DEFINE([WITH_AUTHORIZED_KEYS_COMMAND], 1, [Enable AuthorizedKeysCommand support])
262 dnl Checks for library functions. Please keep in alphabetical order
265 @@ -4325,6 +4337,7 @@ echo " SELinux support
266 echo " Smartcard support: $SCARD_MSG"
267 echo " S/KEY support: $SKEY_MSG"
268 echo " TCP Wrappers support: $TCPW_MSG"
269 +echo " AuthorizedKeysCommand support: $AKC_MSG"
270 echo " MD5 password support: $MD5_MSG"
271 echo " libedit support: $LIBEDIT_MSG"
272 echo " Solaris process contract support: $SPC_MSG"
273 diff -up openssh-5.8p1/servconf.c.akc openssh-5.8p1/servconf.c
274 --- openssh-5.8p1/servconf.c.akc 2011-02-10 13:21:28.000000000 +0100
275 +++ openssh-5.8p1/servconf.c 2011-02-10 13:28:21.000000000 +0100
276 @@ -134,6 +134,8 @@ initialize_server_options(ServerOptions
277 options->num_permitted_opens = -1;
278 options->adm_forced_command = NULL;
279 options->chroot_directory = NULL;
280 + options->authorized_keys_command = NULL;
281 + options->authorized_keys_command_runas = NULL;
282 options->zero_knowledge_password_authentication = -1;
283 options->revoked_keys_file = NULL;
284 options->trusted_user_ca_keys = NULL;
285 @@ -331,6 +333,7 @@ typedef enum {
286 sZeroKnowledgePasswordAuthentication, sHostCertificate,
287 sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
288 sKexAlgorithms, sIPQoS,
289 + sAuthorizedKeysCommand, sAuthorizedKeysCommandRunAs,
290 sDeprecated, sUnsupported
293 @@ -456,6 +459,13 @@ static struct {
294 { "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL },
295 { "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL },
296 { "ipqos", sIPQoS, SSHCFG_ALL },
297 +#ifdef WITH_AUTHORIZED_KEYS_COMMAND
298 + { "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL },
299 + { "authorizedkeyscommandrunas", sAuthorizedKeysCommandRunAs, SSHCFG_ALL },
301 + { "authorizedkeyscommand", sUnsupported, SSHCFG_ALL },
302 + { "authorizedkeyscommandrunas", sUnsupported, SSHCFG_ALL },
304 { NULL, sBadOption, 0 }
307 @@ -1406,6 +1416,20 @@ process_server_config_line(ServerOptions
311 + case sAuthorizedKeysCommand:
312 + len = strspn(cp, WHITESPACE);
313 + if (*activep && options->authorized_keys_command == NULL)
314 + options->authorized_keys_command = xstrdup(cp + len);
317 + case sAuthorizedKeysCommandRunAs:
318 + charptr = &options->authorized_keys_command_runas;
320 + arg = strdelim(&cp);
321 + if (*activep && *charptr == NULL)
322 + *charptr = xstrdup(arg);
326 logit("%s line %d: Deprecated option %s",
327 filename, linenum, arg);
328 @@ -1499,6 +1523,8 @@ copy_set_server_options(ServerOptions *d
329 M_CP_INTOPT(gss_authentication);
330 M_CP_INTOPT(rsa_authentication);
331 M_CP_INTOPT(pubkey_authentication);
332 + M_CP_STROPT(authorized_keys_command);
333 + M_CP_STROPT(authorized_keys_command_runas);
334 M_CP_INTOPT(kerberos_authentication);
335 M_CP_INTOPT(hostbased_authentication);
336 M_CP_INTOPT(hostbased_uses_name_from_packet_only);
337 @@ -1753,6 +1779,8 @@ dump_config(ServerOptions *o)
338 dump_cfg_string(sRevokedKeys, o->revoked_keys_file);
339 dump_cfg_string(sAuthorizedPrincipalsFile,
340 o->authorized_principals_file);
341 + dump_cfg_string(sAuthorizedKeysCommand, o->authorized_keys_command);
342 + dump_cfg_string(sAuthorizedKeysCommandRunAs, o->authorized_keys_command_runas);
344 /* string arguments requiring a lookup */
345 dump_cfg_string(sLogLevel, log_level_name(o->log_level));
346 diff -up openssh-5.8p1/servconf.h.akc openssh-5.8p1/servconf.h
347 --- openssh-5.8p1/servconf.h.akc 2011-02-10 13:21:28.000000000 +0100
348 +++ openssh-5.8p1/servconf.h 2011-02-10 13:21:28.000000000 +0100
349 @@ -161,6 +161,8 @@ typedef struct {
350 char *revoked_keys_file;
351 char *trusted_user_ca_keys;
352 char *authorized_principals_file;
353 + char *authorized_keys_command;
354 + char *authorized_keys_command_runas;
357 void initialize_server_options(ServerOptions *);
358 diff -up openssh-5.8p1/sshd_config.0.akc openssh-5.8p1/sshd_config.0
359 --- openssh-5.8p1/sshd_config.0.akc 2011-02-10 13:21:28.000000000 +0100
360 +++ openssh-5.8p1/sshd_config.0 2011-02-10 13:21:28.000000000 +0100
361 @@ -71,6 +71,23 @@ DESCRIPTION
363 See PATTERNS in ssh_config(5) for more information on patterns.
365 + AuthorizedKeysCommand
367 + Specifies a program to be used for lookup of the user's
368 + public keys. The program will be invoked with its first
369 + argument the name of the user being authorized, and should produce
370 + on standard output AuthorizedKeys lines (see AUTHORIZED_KEYS
371 + in sshd(8)). By default (or when set to the empty string) there is no
372 + AuthorizedKeysCommand run. If the AuthorizedKeysCommand does not successfully
373 + authorize the user, authorization falls through to the
374 + AuthorizedKeysFile. Note that this option has an effect
375 + only with PubkeyAuthentication turned on.
377 + AuthorizedKeysCommandRunAs
378 + Specifies the user under whose account the AuthorizedKeysCommand is run.
379 + Empty string (the default value) means the user being authorized
383 Specifies the file that contains the public keys that can be used
384 for user authentication. The format is described in the
385 @@ -398,7 +415,8 @@ DESCRIPTION
387 Only a subset of keywords may be used on the lines following a
388 Match keyword. Available keywords are AllowAgentForwarding,
389 - AllowTcpForwarding, AuthorizedKeysFile, AuthorizedPrincipalsFile,
390 + AllowTcpForwarding, AuthorizedKeysFile, AuthorizedKeysCommand,
391 + AuthorizedKeysCommandRunAs, AuthorizedPrincipalsFile,
392 Banner, ChrootDirectory, ForceCommand, GatewayPorts,
393 GSSAPIAuthentication, HostbasedAuthentication,
394 HostbasedUsesNameFromPacketOnly, KbdInteractiveAuthentication,
395 diff -up openssh-5.8p1/sshd_config.5.akc openssh-5.8p1/sshd_config.5
396 --- openssh-5.8p1/sshd_config.5.akc 2011-02-10 13:21:28.000000000 +0100
397 +++ openssh-5.8p1/sshd_config.5 2011-02-10 13:21:28.000000000 +0100
398 @@ -703,6 +703,8 @@ Available keywords are
399 .Cm AllowAgentForwarding ,
400 .Cm AllowTcpForwarding ,
401 .Cm AuthorizedKeysFile ,
402 +.Cm AuthorizedKeysCommand ,
403 +.Cm AuthorizedKeysCommandRunAs ,
404 .Cm AuthorizedPrincipalsFile ,
406 .Cm ChrootDirectory ,
407 @@ -715,6 +717,7 @@ Available keywords are
408 .Cm KerberosAuthentication ,
411 +.Cm PubkeyAuthentication ,
412 .Cm PasswordAuthentication ,
413 .Cm PermitEmptyPasswords ,
415 @@ -917,6 +920,20 @@ Specifies a list of revoked public keys.
416 Keys listed in this file will be refused for public key authentication.
417 Note that if this file is not readable, then public key authentication will
418 be refused for all users.
419 +.It Cm AuthorizedKeysCommand
420 +Specifies a program to be used for lookup of the user's
421 +public keys. The program will be invoked with its first
422 +argument the name of the user being authorized, and should produce
423 +on standard output AuthorizedKeys lines (see AUTHORIZED_KEYS
424 +in sshd(8)). By default (or when set to the empty string) there is no
425 +AuthorizedKeysCommand run. If the AuthorizedKeysCommand does not successfully
426 +authorize the user, authorization falls through to the
427 +AuthorizedKeysFile. Note that this option has an effect
428 +only with PubkeyAuthentication turned on.
429 +.It Cm AuthorizedKeysCommandRunAs
430 +Specifies the user under whose account the AuthorizedKeysCommand is run. Empty
431 +string (the default value) means the user being authorized is used.
433 .It Cm RhostsRSAAuthentication
434 Specifies whether rhosts or /etc/hosts.equiv authentication together
435 with successful RSA host authentication is allowed.
436 diff -up openssh-5.8p1/sshd_config.akc openssh-5.8p1/sshd_config
437 --- openssh-5.8p1/sshd_config.akc 2011-02-10 13:21:28.000000000 +0100
438 +++ openssh-5.8p1/sshd_config 2011-02-10 13:21:28.000000000 +0100
439 @@ -46,6 +46,8 @@ SyslogFacility AUTHPRIV
440 #RSAAuthentication yes
441 #PubkeyAuthentication yes
442 #AuthorizedKeysFile .ssh/authorized_keys
443 +#AuthorizedKeysCommand none
444 +#AuthorizedKeysCommandRunAs nobody
446 # For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
447 #RhostsRSAAuthentication no