1 diff -up openssh-5.9p1/auth2-pubkey.c.akc openssh-5.9p1/auth2-pubkey.c
2 --- openssh-5.9p1/auth2-pubkey.c.akc 2011-09-14 07:24:40.876512251 +0200
3 +++ openssh-5.9p1/auth2-pubkey.c 2011-09-14 07:24:43.318458515 +0200
12 @@ -276,27 +277,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 @@ -389,8 +378,6 @@ user_key_allowed2(struct passwd *pw, Key
49 debug2("key not found");
50 @@ -452,13 +439,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.9p1/configure.ac.akc openssh-5.9p1/configure.ac
244 --- openssh-5.9p1/configure.ac.akc 2011-09-14 07:24:42.863494886 +0200
245 +++ openssh-5.9p1/configure.ac 2011-09-14 07:24:43.441583848 +0200
246 @@ -1421,6 +1421,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 @@ -4239,6 +4251,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.9p1/servconf.c.akc openssh-5.9p1/servconf.c
274 --- openssh-5.9p1/servconf.c.akc 2011-09-14 07:24:29.402475399 +0200
275 +++ openssh-5.9p1/servconf.c 2011-09-14 07:56:27.158585590 +0200
276 @@ -139,6 +139,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 @@ -348,6 +350,7 @@ typedef enum {
286 sZeroKnowledgePasswordAuthentication, sHostCertificate,
287 sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
288 sKexAlgorithms, sIPQoS,
289 + sAuthorizedKeysCommand, sAuthorizedKeysCommandRunAs,
290 sDeprecated, sUnsupported
293 @@ -487,6 +490,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 @@ -1462,6 +1472,24 @@ 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 (!arg || *arg == '\0')
322 + fatal("%s line %d: missing account.",
323 + filename, linenum);
325 + if (*activep && *charptr == NULL)
326 + *charptr = xstrdup(arg);
330 logit("%s line %d: Deprecated option %s",
331 filename, linenum, arg);
332 @@ -1573,6 +1601,8 @@ copy_set_server_options(ServerOptions *d
333 M_CP_INTOPT(zero_knowledge_password_authentication);
334 M_CP_INTOPT(second_zero_knowledge_password_authentication);
335 M_CP_INTOPT(two_factor_authentication);
336 + M_CP_STROPT(authorized_keys_command);
337 + M_CP_STROPT(authorized_keys_command_runas);
338 M_CP_INTOPT(permit_root_login);
339 M_CP_INTOPT(permit_empty_passwd);
341 @@ -1839,6 +1869,8 @@ dump_config(ServerOptions *o)
342 dump_cfg_string(sRevokedKeys, o->revoked_keys_file);
343 dump_cfg_string(sAuthorizedPrincipalsFile,
344 o->authorized_principals_file);
345 + dump_cfg_string(sAuthorizedKeysCommand, o->authorized_keys_command);
346 + dump_cfg_string(sAuthorizedKeysCommandRunAs, o->authorized_keys_command_runas);
348 /* string arguments requiring a lookup */
349 dump_cfg_string(sLogLevel, log_level_name(o->log_level));
350 diff -up openssh-5.9p1/servconf.h.akc openssh-5.9p1/servconf.h
351 --- openssh-5.9p1/servconf.h.akc 2011-09-14 07:24:29.511480441 +0200
352 +++ openssh-5.9p1/servconf.h 2011-09-14 07:24:43.678459183 +0200
353 @@ -174,6 +174,8 @@ typedef struct {
354 char *revoked_keys_file;
355 char *trusted_user_ca_keys;
356 char *authorized_principals_file;
357 + char *authorized_keys_command;
358 + char *authorized_keys_command_runas;
362 diff -up openssh-5.9p1/sshd_config.0.akc openssh-5.9p1/sshd_config.0
363 --- openssh-5.9p1/sshd_config.0.akc 2011-09-07 01:16:30.000000000 +0200
364 +++ openssh-5.9p1/sshd_config.0 2011-09-14 07:24:43.791460201 +0200
365 @@ -71,6 +71,23 @@ DESCRIPTION
367 See PATTERNS in ssh_config(5) for more information on patterns.
369 + AuthorizedKeysCommand
371 + Specifies a program to be used for lookup of the user's
372 + public keys. The program will be invoked with its first
373 + argument the name of the user being authorized, and should produce
374 + on standard output AuthorizedKeys lines (see AUTHORIZED_KEYS
375 + in sshd(8)). By default (or when set to the empty string) there is no
376 + AuthorizedKeysCommand run. If the AuthorizedKeysCommand does not successfully
377 + authorize the user, authorization falls through to the
378 + AuthorizedKeysFile. Note that this option has an effect
379 + only with PubkeyAuthentication turned on.
381 + AuthorizedKeysCommandRunAs
382 + Specifies the user under whose account the AuthorizedKeysCommand is run.
383 + Empty string (the default value) means the user being authorized
387 Specifies the file that contains the public keys that can be used
388 for user authentication. The format is described in the
389 @@ -401,7 +418,8 @@ DESCRIPTION
391 Only a subset of keywords may be used on the lines following a
392 Match keyword. Available keywords are AllowAgentForwarding,
393 - AllowTcpForwarding, AuthorizedKeysFile, AuthorizedPrincipalsFile,
394 + AllowTcpForwarding, AuthorizedKeysFile, AuthorizedKeysCommand,
395 + AuthorizedKeysCommandRunAs, AuthorizedPrincipalsFile,
396 Banner, ChrootDirectory, ForceCommand, GatewayPorts,
397 GSSAPIAuthentication, HostbasedAuthentication,
398 HostbasedUsesNameFromPacketOnly, KbdInteractiveAuthentication,
399 diff -up openssh-5.9p1/sshd_config.5.akc openssh-5.9p1/sshd_config.5
400 --- openssh-5.9p1/sshd_config.5.akc 2011-09-14 07:24:29.793520372 +0200
401 +++ openssh-5.9p1/sshd_config.5 2011-09-14 07:24:43.912583678 +0200
402 @@ -706,6 +706,8 @@ Available keywords are
403 .Cm AllowAgentForwarding ,
404 .Cm AllowTcpForwarding ,
405 .Cm AuthorizedKeysFile ,
406 +.Cm AuthorizedKeysCommand ,
407 +.Cm AuthorizedKeysCommandRunAs ,
408 .Cm AuthorizedPrincipalsFile ,
410 .Cm ChrootDirectory ,
411 @@ -718,6 +720,7 @@ Available keywords are
412 .Cm KerberosAuthentication ,
415 +.Cm PubkeyAuthentication ,
416 .Cm PasswordAuthentication ,
417 .Cm PermitEmptyPasswords ,
419 @@ -926,6 +929,20 @@ Specifies a list of revoked public keys.
420 Keys listed in this file will be refused for public key authentication.
421 Note that if this file is not readable, then public key authentication will
422 be refused for all users.
423 +.It Cm AuthorizedKeysCommand
424 +Specifies a program to be used for lookup of the user's
425 +public keys. The program will be invoked with its first
426 +argument the name of the user being authorized, and should produce
427 +on standard output AuthorizedKeys lines (see AUTHORIZED_KEYS
428 +in sshd(8)). By default (or when set to the empty string) there is no
429 +AuthorizedKeysCommand run. If the AuthorizedKeysCommand does not successfully
430 +authorize the user, authorization falls through to the
431 +AuthorizedKeysFile. Note that this option has an effect
432 +only with PubkeyAuthentication turned on.
433 +.It Cm AuthorizedKeysCommandRunAs
434 +Specifies the user under whose account the AuthorizedKeysCommand is run. Empty
435 +string (the default value) means the user being authorized is used.
437 .It Cm RhostsRSAAuthentication
438 Specifies whether rhosts or /etc/hosts.equiv authentication together
439 with successful RSA host authentication is allowed.
440 diff -up openssh-5.9p1/sshd_config.akc openssh-5.9p1/sshd_config
441 --- openssh-5.9p1/sshd_config.akc 2011-09-14 07:24:29.620461608 +0200
442 +++ openssh-5.9p1/sshd_config 2011-09-14 07:24:44.034462546 +0200
444 # but this is overridden so installations will only check .ssh/authorized_keys
445 AuthorizedKeysFile .ssh/authorized_keys
447 +#AuthorizedKeysCommand none
448 +#AuthorizedKeysCommandRunAs nobody
450 # For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
451 #RhostsRSAAuthentication no
452 # similar for protocol version 2