]> git.ipfire.org Git - people/ms/ipfire-3.x.git/blame - openssh/patches/openssh-6.1p1-akc.patch
openssh: Update to 6.1p1.
[people/ms/ipfire-3.x.git] / openssh / patches / openssh-6.1p1-akc.patch
CommitLineData
43c69e28
SS
1diff -up openssh-6.1p1/auth2-pubkey.c.akc openssh-6.1p1/auth2-pubkey.c
2--- openssh-6.1p1/auth2-pubkey.c.akc 2012-11-28 17:12:43.238524384 +0100
3+++ openssh-6.1p1/auth2-pubkey.c 2012-11-28 17:12:43.263524297 +0100
4@@ -27,9 +27,13 @@
5
6 #include <sys/types.h>
7 #include <sys/stat.h>
8+#include <sys/wait.h>
9
10+#include <errno.h>
11 #include <fcntl.h>
12+#include <paths.h>
13 #include <pwd.h>
14+#include <signal.h>
15 #include <stdio.h>
16 #include <stdarg.h>
17 #include <string.h>
18@@ -260,7 +264,7 @@ match_principals_file(char *file, struct
19 if (strcmp(cp, cert->principals[i]) == 0) {
20 debug3("matched principal \"%.100s\" "
21 "from file \"%s\" on line %lu",
22- cert->principals[i], file, linenum);
23+ cert->principals[i], file, linenum);
24 if (auth_parse_options(pw, line_opts,
25 file, linenum) != 1)
26 continue;
27@@ -273,31 +277,22 @@ match_principals_file(char *file, struct
28 fclose(f);
29 restore_uid();
30 return 0;
31-}
32+}
33
34-/* return 1 if user allows given key */
35+/*
36+ * Checks whether key is allowed in authorized_keys-format file,
37+ * returns 1 if the key is allowed or 0 otherwise.
38+ */
39 static int
40-user_key_allowed2(struct passwd *pw, Key *key, char *file)
41+check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw)
42 {
43 char line[SSH_MAX_PUBKEY_BYTES];
44 const char *reason;
45 int found_key = 0;
46- FILE *f;
47 u_long linenum = 0;
48 Key *found;
49 char *fp;
50
51- /* Temporarily use the user's uid. */
52- temporarily_use_uid(pw);
53-
54- debug("trying public key file %s", file);
55- f = auth_openkeyfile(file, pw, options.strict_modes);
56-
57- if (!f) {
58- restore_uid();
59- return 0;
60- }
61-
62 found_key = 0;
63 found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type);
64
65@@ -390,8 +385,6 @@ user_key_allowed2(struct passwd *pw, Key
66 break;
67 }
68 }
69- restore_uid();
70- fclose(f);
71 key_free(found);
72 if (!found_key)
73 debug2("key not found");
74@@ -453,7 +446,173 @@ user_cert_trusted_ca(struct passwd *pw,
75 return ret;
76 }
77
78-/* check whether given key is in .ssh/authorized_keys* */
79+/*
80+ * Checks whether key is allowed in file.
81+ * returns 1 if the key is allowed or 0 otherwise.
82+ */
83+static int
84+user_key_allowed2(struct passwd *pw, Key *key, char *file)
85+{
86+ FILE *f;
87+ int found_key = 0;
88+
89+ /* Temporarily use the user's uid. */
90+ temporarily_use_uid(pw);
91+
92+ debug("trying public key file %s", file);
93+ if ((f = auth_openkeyfile(file, pw, options.strict_modes)) != NULL) {
94+ found_key = check_authkeys_file(f, file, key, pw);
95+ fclose(f);
96+ }
97+
98+ restore_uid();
99+ return found_key;
100+}
101+
102+/*
103+ * Checks whether key is allowed in output of command.
104+ * returns 1 if the key is allowed or 0 otherwise.
105+ */
106+static int
107+user_key_command_allowed2(struct passwd *user_pw, Key *key)
108+{
109+ FILE *f;
110+ int ok, found_key = 0;
111+ struct passwd *pw;
112+ struct stat st;
113+ int status, devnull, p[2], i;
114+ pid_t pid;
115+ char errmsg[512];
116+
117+ if (options.authorized_keys_command == NULL ||
118+ options.authorized_keys_command[0] != '/')
119+ return 0;
120+
121+ /* If no user specified to run commands the default to target user */
122+ if (options.authorized_keys_command_user == NULL)
123+ pw = user_pw;
124+ else {
125+ pw = getpwnam(options.authorized_keys_command_user);
126+ if (pw == NULL) {
127+ error("AuthorizedKeyCommandUser \"%s\" not found: %s",
128+ options.authorized_keys_command, strerror(errno));
129+ return 0;
130+ }
131+ }
132+
133+ temporarily_use_uid(pw);
134+ if (stat(options.authorized_keys_command, &st) < 0) {
135+ error("Could not stat AuthorizedKeysCommand \"%s\": %s",
136+ options.authorized_keys_command, strerror(errno));
137+ goto out;
138+ }
139+
140+ if (auth_secure_path(options.authorized_keys_command, &st, NULL, 0,
141+ errmsg, sizeof(errmsg)) != 0) {
142+ error("Unsafe AuthorizedKeysCommand: %s", errmsg);
143+ goto out;
144+ }
145+
146+ /* open the pipe and read the keys */
147+ if (pipe(p) != 0) {
148+ error("%s: pipe: %s", __func__, strerror(errno));
149+ goto out;
150+ }
151+
152+ debug3("Running AuthorizedKeysCommand: \"%s\" as \"%s\"",
153+ options.authorized_keys_command, pw->pw_name);
154+
155+ /*
156+ * Don't want to call this in the child, where it can fatal() and
157+ * run cleanup_exit() code.
158+ */
159+ restore_uid();
160+
161+ switch ((pid = fork())) {
162+ case -1: /* error */
163+ error("%s: fork: %s", __func__, strerror(errno));
164+ close(p[0]);
165+ close(p[1]);
166+ return 0;
167+ case 0: /* child */
168+ for (i = 0; i < NSIG; i++)
169+ signal(i, SIG_DFL);
170+
171+ /* Don't use permanently_set_uid() here to avoid fatal() */
172+ if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) {
173+ error("setresgid %u: %s", (u_int)pw->pw_gid,
174+ strerror(errno));
175+ _exit(1);
176+ }
177+ if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0) {
178+ error("setresuid %u: %s", (u_int)pw->pw_uid,
179+ strerror(errno));
180+ _exit(1);
181+ }
182+
183+ close(p[0]);
184+ if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) {
185+ error("%s: open %s: %s", __func__, _PATH_DEVNULL,
186+ strerror(errno));
187+ _exit(1);
188+ }
189+ if (dup2(devnull, STDIN_FILENO) == -1 ||
190+ dup2(p[1], STDOUT_FILENO) == -1 ||
191+ dup2(devnull, STDERR_FILENO) == -1) {
192+ error("%s: dup2: %s", __func__, strerror(errno));
193+ _exit(1);
194+ }
195+ closefrom(STDERR_FILENO + 1);
196+
197+ execl(options.authorized_keys_command,
198+ options.authorized_keys_command, pw->pw_name, NULL);
199+
200+ error("AuthorizedKeysCommand %s exec failed: %s",
201+ options.authorized_keys_command, strerror(errno));
202+ _exit(127);
203+ default: /* parent */
204+ break;
205+ }
206+
207+ temporarily_use_uid(pw);
208+
209+ close(p[1]);
210+ if ((f = fdopen(p[0], "r")) == NULL) {
211+ error("%s: fdopen: %s", __func__, strerror(errno));
212+ close(p[0]);
213+ /* Don't leave zombie child */
214+ while (waitpid(pid, NULL, 0) == -1 && errno == EINTR)
215+ ;
216+ goto out;
217+ }
218+ ok = check_authkeys_file(f, options.authorized_keys_command, key, pw);
219+ fclose(f);
220+
221+ while (waitpid(pid, &status, 0) == -1) {
222+ if (errno != EINTR) {
223+ error("%s: waitpid: %s", __func__, strerror(errno));
224+ goto out;
225+ }
226+ }
227+ if (WIFSIGNALED(status)) {
228+ error("AuthorizedKeysCommand %s exited on signal %d",
229+ options.authorized_keys_command, WTERMSIG(status));
230+ goto out;
231+ } else if (WEXITSTATUS(status) != 0) {
232+ error("AuthorizedKeysCommand %s returned status %d",
233+ options.authorized_keys_command, WEXITSTATUS(status));
234+ goto out;
235+ }
236+ found_key = ok;
237+ out:
238+ restore_uid();
239+
240+ return found_key;
241+}
242+
243+/*
244+ * Check whether key authenticates and authorises the user.
245+ */
246 int
247 user_key_allowed(struct passwd *pw, Key *key)
248 {
249@@ -469,6 +628,10 @@ user_key_allowed(struct passwd *pw, Key
250 if (success)
251 return success;
252
253+ success = user_key_command_allowed2(pw, key);
254+ if (success > 0)
255+ return success;
256+
257 for (i = 0; !success && i < options.num_authkeys_files; i++) {
258 file = expand_authorized_keys(
259 options.authorized_keys_files[i], pw);
260diff -up openssh-6.1p1/auth.c.akc openssh-6.1p1/auth.c
261--- openssh-6.1p1/auth.c.akc 2012-11-28 17:12:43.187524558 +0100
262+++ openssh-6.1p1/auth.c 2012-11-28 17:12:43.263524297 +0100
263@@ -411,39 +411,41 @@ check_key_in_hostfiles(struct passwd *pw
264
265
266 /*
267- * Check a given file for security. This is defined as all components
268+ * Check a given path for security. This is defined as all components
269 * of the path to the file must be owned by either the owner of
270 * of the file or root and no directories must be group or world writable.
271 *
272 * XXX Should any specific check be done for sym links ?
273 *
274- * Takes an open file descriptor, the file name, a uid and and
275+ * Takes an the file name, its stat information (preferably from fstat() to
276+ * avoid races), the uid of the expected owner, their home directory and an
277 * error buffer plus max size as arguments.
278 *
279 * Returns 0 on success and -1 on failure
280 */
281-static int
282-secure_filename(FILE *f, const char *file, struct passwd *pw,
283- char *err, size_t errlen)
284+int
285+auth_secure_path(const char *name, struct stat *stp, const char *pw_dir,
286+ uid_t uid, char *err, size_t errlen)
287 {
288- uid_t uid = pw->pw_uid;
289 char buf[MAXPATHLEN], homedir[MAXPATHLEN];
290 char *cp;
291 int comparehome = 0;
292 struct stat st;
293
294- if (realpath(file, buf) == NULL) {
295- snprintf(err, errlen, "realpath %s failed: %s", file,
296+ if (realpath(name, buf) == NULL) {
297+ snprintf(err, errlen, "realpath %s failed: %s", name,
298 strerror(errno));
299 return -1;
300 }
301- if (realpath(pw->pw_dir, homedir) != NULL)
302+ if (pw_dir != NULL && realpath(pw_dir, homedir) != NULL)
303 comparehome = 1;
304
305- /* check the open file to avoid races */
306- if (fstat(fileno(f), &st) < 0 ||
307- (st.st_uid != 0 && st.st_uid != uid) ||
308- (st.st_mode & 022) != 0) {
309+ if (!S_ISREG(stp->st_mode)) {
310+ snprintf(err, errlen, "%s is not a regular file", buf);
311+ return -1;
312+ }
313+ if ((stp->st_uid != 0 && stp->st_uid != uid) ||
314+ (stp->st_mode & 022) != 0) {
315 snprintf(err, errlen, "bad ownership or modes for file %s",
316 buf);
317 return -1;
318@@ -479,6 +481,31 @@ secure_filename(FILE *f, const char *fil
319 return 0;
320 }
321
322+/*
323+ * Version of secure_path() that accepts an open file descriptor to
324+ * avoid races.
325+ *
326+ * Returns 0 on success and -1 on failure
327+ */
328+static int
329+secure_filename(FILE *f, const char *file, struct passwd *pw,
330+ char *err, size_t errlen)
331+{
332+ uid_t uid = pw->pw_uid;
333+ char buf[MAXPATHLEN], homedir[MAXPATHLEN];
334+ char *cp;
335+ int comparehome = 0;
336+ struct stat st;
337+
338+ /* check the open file to avoid races */
339+ if (fstat(fileno(f), &st) < 0) {
340+ snprintf(err, errlen, "cannot stat file %s: %s",
341+ buf, strerror(errno));
342+ return -1;
343+ }
344+ return auth_secure_path(file, &st, pw->pw_dir, pw->pw_uid, err, errlen);
345+}
346+
347 static FILE *
348 auth_openfile(const char *file, struct passwd *pw, int strict_modes,
349 int log_missing, char *file_type)
350diff -up openssh-6.1p1/auth.h.akc openssh-6.1p1/auth.h
351--- openssh-6.1p1/auth.h.akc 2012-11-28 17:12:43.239524381 +0100
352+++ openssh-6.1p1/auth.h 2012-11-28 17:12:43.263524297 +0100
353@@ -125,6 +125,10 @@ int auth_rhosts_rsa_key_allowed(struct
354 int hostbased_key_allowed(struct passwd *, const char *, char *, Key *);
355 int user_key_allowed(struct passwd *, Key *);
356
357+struct stat;
358+int auth_secure_path(const char *, struct stat *, const char *, uid_t,
359+ char *, size_t);
360+
361 #ifdef KRB5
362 int auth_krb5(Authctxt *authctxt, krb5_data *auth, char **client, krb5_data *);
363 int auth_krb5_tgt(Authctxt *authctxt, krb5_data *tgt);
364diff -up openssh-6.1p1/servconf.c.akc openssh-6.1p1/servconf.c
365--- openssh-6.1p1/servconf.c.akc 2012-11-28 17:12:43.198524521 +0100
366+++ openssh-6.1p1/servconf.c 2012-11-28 17:14:50.314005026 +0100
367@@ -137,6 +137,8 @@ initialize_server_options(ServerOptions
368 options->num_permitted_opens = -1;
369 options->adm_forced_command = NULL;
370 options->chroot_directory = NULL;
371+ options->authorized_keys_command = NULL;
372+ options->authorized_keys_command_user = NULL;
373 options->zero_knowledge_password_authentication = -1;
374 options->revoked_keys_file = NULL;
375 options->trusted_user_ca_keys = NULL;
376@@ -331,6 +333,7 @@ typedef enum {
377 sZeroKnowledgePasswordAuthentication, sHostCertificate,
378 sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
379 sKexAlgorithms, sIPQoS, sVersionAddendum,
380+ sAuthorizedKeysCommand, sAuthorizedKeysCommandUser,
381 sAuthenticationMethods,
382 sDeprecated, sUnsupported
383 } ServerOpCodes;
384@@ -457,6 +460,9 @@ static struct {
385 { "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL },
386 { "ipqos", sIPQoS, SSHCFG_ALL },
387 { "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL },
388+ { "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL },
389+ { "authorizedkeyscommandrunas", sAuthorizedKeysCommandUser, SSHCFG_ALL },
390+ { "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL },
391 { "authenticationmethods", sAuthenticationMethods, SSHCFG_ALL },
392 { NULL, sBadOption, 0 }
393 };
394@@ -1520,6 +1526,26 @@ process_server_config_line(ServerOptions
395 }
396 return 0;
397
398+ case sAuthorizedKeysCommand:
399+ len = strspn(cp, WHITESPACE);
400+ if (*activep && options->authorized_keys_command == NULL) {
401+ options->authorized_keys_command = xstrdup(cp + len);
402+ if (*options->authorized_keys_command != '/') {
403+ fatal("%.200s line %d: AuthorizedKeysCommand "
404+ "must be an absolute path",
405+ filename, linenum);
406+ }
407+ }
408+ return 0;
409+
410+ case sAuthorizedKeysCommandUser:
411+ charptr = &options->authorized_keys_command_user;
412+
413+ arg = strdelim(&cp);
414+ if (*activep && *charptr == NULL)
415+ *charptr = xstrdup(arg);
416+ break;
417+
418 case sDeprecated:
419 logit("%s line %d: Deprecated option %s",
420 filename, linenum, arg);
421@@ -1670,6 +1696,8 @@ copy_set_server_options(ServerOptions *d
422 M_CP_INTOPT(hostbased_uses_name_from_packet_only);
423 M_CP_INTOPT(kbd_interactive_authentication);
424 M_CP_INTOPT(zero_knowledge_password_authentication);
425+ M_CP_STROPT(authorized_keys_command);
426+ M_CP_STROPT(authorized_keys_command_user);
427 M_CP_INTOPT(permit_root_login);
428 M_CP_INTOPT(permit_empty_passwd);
429
430@@ -1930,6 +1958,8 @@ dump_config(ServerOptions *o)
431 dump_cfg_string(sAuthorizedPrincipalsFile,
432 o->authorized_principals_file);
433 dump_cfg_string(sVersionAddendum, o->version_addendum);
434+ dump_cfg_string(sAuthorizedKeysCommand, o->authorized_keys_command);
435+ dump_cfg_string(sAuthorizedKeysCommandUser, o->authorized_keys_command_user);
436
437 /* string arguments requiring a lookup */
438 dump_cfg_string(sLogLevel, log_level_name(o->log_level));
439diff -up openssh-6.1p1/servconf.h.akc openssh-6.1p1/servconf.h
440--- openssh-6.1p1/servconf.h.akc 2012-11-28 17:12:43.000000000 +0100
441+++ openssh-6.1p1/servconf.h 2012-11-28 17:18:41.217055157 +0100
442@@ -167,6 +167,8 @@ typedef struct {
443 char *revoked_keys_file;
444 char *trusted_user_ca_keys;
445 char *authorized_principals_file;
446+ char *authorized_keys_command;
447+ char *authorized_keys_command_user;
448
449 char *version_addendum; /* Appended to SSH banner */
450
451diff -up openssh-6.1p1/sshd.c.akc openssh-6.1p1/sshd.c
452--- openssh-6.1p1/sshd.c.akc 2012-11-28 17:12:43.245524360 +0100
453+++ openssh-6.1p1/sshd.c 2012-11-28 17:12:43.265524291 +0100
454@@ -366,9 +366,20 @@ main_sigchld_handler(int sig)
455 static void
456 grace_alarm_handler(int sig)
457 {
458+ pid_t pgid;
459+
460 if (use_privsep && pmonitor != NULL && pmonitor->m_pid > 0)
461 kill(pmonitor->m_pid, SIGALRM);
462
463+ /*
464+ * Try to kill any processes that we have spawned, E.g. authorized
465+ * keys command helpers.
466+ */
467+ if ((pgid = getpgid(0)) == getpid()) {
468+ signal(SIGTERM, SIG_IGN);
469+ killpg(pgid, SIGTERM);
470+ }
471+
472 /* Log error and exit. */
473 sigdie("Timeout before authentication for %s", get_remote_ipaddr());
474 }
475diff -up openssh-6.1p1/sshd_config.0.akc openssh-6.1p1/sshd_config.0
476--- openssh-6.1p1/sshd_config.0.akc 2012-08-29 02:53:04.000000000 +0200
477+++ openssh-6.1p1/sshd_config.0 2012-11-28 17:12:43.265524291 +0100
478@@ -71,6 +71,23 @@ DESCRIPTION
479
480 See PATTERNS in ssh_config(5) for more information on patterns.
481
482+ AuthorizedKeysCommand
483+
484+ Specifies a program to be used for lookup of the user's
485+ public keys. The program will be invoked with its first
486+ argument the name of the user being authorized, and should produce
487+ on standard output AuthorizedKeys lines (see AUTHORIZED_KEYS
488+ in sshd(8)). By default (or when set to the empty string) there is no
489+ AuthorizedKeysCommand run. If the AuthorizedKeysCommand does not successfully
490+ authorize the user, authorization falls through to the
491+ AuthorizedKeysFile. Note that this option has an effect
492+ only with PubkeyAuthentication turned on.
493+
494+ AuthorizedKeysCommandRunAs
495+ Specifies the user under whose account the AuthorizedKeysCommand is run.
496+ Empty string (the default value) means the user being authorized
497+ is used.
498+
499 AuthorizedKeysFile
500 Specifies the file that contains the public keys that can be used
501 for user authentication. The format is described in the
502@@ -402,7 +419,8 @@ DESCRIPTION
503 Only a subset of keywords may be used on the lines following a
504 Match keyword. Available keywords are AcceptEnv,
505 AllowAgentForwarding, AllowGroups, AllowTcpForwarding,
506- AllowUsers, AuthorizedKeysFile, AuthorizedPrincipalsFile, Banner,
507+ AllowUsers, AuthorizedKeysFile, AuthorizedKeysCommand,
508+ AuthorizedKeysCommandRunAs, AuthorizedPrincipalsFile, Banner,
509 ChrootDirectory, DenyGroups, DenyUsers, ForceCommand,
510 GatewayPorts, GSSAPIAuthentication, HostbasedAuthentication,
511 HostbasedUsesNameFromPacketOnly, KbdInteractiveAuthentication,
512diff -up openssh-6.1p1/sshd_config.5.akc openssh-6.1p1/sshd_config.5
513--- openssh-6.1p1/sshd_config.5.akc 2012-11-28 17:12:43.199524517 +0100
514+++ openssh-6.1p1/sshd_config.5 2012-11-28 17:16:23.736624980 +0100
515@@ -173,6 +173,20 @@ Note that each authentication method lis
516 in the configuration.
517 The default is not to require multiple authentication; successful completion
518 of a single authentication method is sufficient.
519+.It Cm AuthorizedKeysCommand
520+Specifies a program to be used for lookup of the user's public keys.
521+The program will be invoked with a single argument of the username
522+being authenticated, and should produce on standard output zero or
523+more lines of authorized_keys output (see AUTHORIZED_KEYS in
524+.Xr sshd 8 )
525+If a key supplied by AuthorizedKeysCommand does not successfully authenticate
526+and authorize the user then public key authentication continues using the usual
527+.Cm AuthorizedKeysFile
528+files.
529+By default, no AuthorizedKeysCommand is run.
530+.It Cm AuthorizedKeysCommandUser
531+Specifies the user under whose account the AuthorizedKeysCommand is run.
532+The default is the user being authenticated.
533 .It Cm AuthorizedKeysFile
534 Specifies the file that contains the public keys that can be used
535 for user authentication.
536@@ -734,6 +748,8 @@ Available keywords are
537 .Cm AllowTcpForwarding ,
538 .Cm AllowUsers ,
539 .Cm AuthenticationMethods ,
540+.Cm AuthorizedKeysCommand ,
541+.Cm AuthorizedKeysCommandUser ,
542 .Cm AuthorizedKeysFile ,
543 .Cm AuthorizedPrincipalsFile ,
544 .Cm Banner ,
545@@ -749,6 +765,7 @@ Available keywords are
546 .Cm KerberosAuthentication ,
547 .Cm MaxAuthTries ,
548 .Cm MaxSessions ,
549+.Cm PubkeyAuthentication ,
550 .Cm PasswordAuthentication ,
551 .Cm PermitEmptyPasswords ,
552 .Cm PermitOpen ,
553diff -up openssh-6.1p1/sshd_config.akc openssh-6.1p1/sshd_config
554--- openssh-6.1p1/sshd_config.akc 2012-07-31 04:21:34.000000000 +0200
555+++ openssh-6.1p1/sshd_config 2012-11-28 17:12:43.265524291 +0100
556@@ -49,6 +49,9 @@
557 # but this is overridden so installations will only check .ssh/authorized_keys
558 AuthorizedKeysFile .ssh/authorized_keys
559
560+#AuthorizedKeysCommand none
561+#AuthorizedKeysCommandUser nobody
562+
563 #AuthorizedPrincipalsFile none
564
565 # For this to work you will also need host keys in /etc/ssh/ssh_known_hosts