summaryrefslogtreecommitdiff
path: root/auth2-pubkey.c
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2013-05-07 11:47:26 +0100
committerColin Watson <cjwatson@debian.org>2013-05-07 11:47:26 +0100
commit2ea3f720daeb1ca9f765365fce3a9546961fe624 (patch)
treec4fb7d1f51fa51e7677232de806aae150e29e2ac /auth2-pubkey.c
parentf5efcd3450bbf8261915e0c4a6f851229dddaa79 (diff)
parentecebda56da46a03dafff923d91c382f31faa9eec (diff)
* New upstream release (http://www.openssh.com/txt/release-6.2).
- Add support for multiple required authentication in SSH protocol 2 via an AuthenticationMethods option (closes: #195716). - Fix Sophie Germain formula in moduli(5) (closes: #698612). - Update ssh-copy-id to Phil Hands' greatly revised version (closes: #99785, #322228, #620428; LP: #518883, #835901, #1074798).
Diffstat (limited to 'auth2-pubkey.c')
-rw-r--r--auth2-pubkey.c216
1 files changed, 196 insertions, 20 deletions
diff --git a/auth2-pubkey.c b/auth2-pubkey.c
index d42ba14b8..f980b0dad 100644
--- a/auth2-pubkey.c
+++ b/auth2-pubkey.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: auth2-pubkey.c,v 1.30 2011/09/25 05:44:47 djm Exp $ */ 1/* $OpenBSD: auth2-pubkey.c,v 1.34 2013/02/14 21:35:59 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * 4 *
@@ -27,9 +27,15 @@
27 27
28#include <sys/types.h> 28#include <sys/types.h>
29#include <sys/stat.h> 29#include <sys/stat.h>
30#include <sys/wait.h>
30 31
32#include <errno.h>
31#include <fcntl.h> 33#include <fcntl.h>
34#ifdef HAVE_PATHS_H
35# include <paths.h>
36#endif
32#include <pwd.h> 37#include <pwd.h>
38#include <signal.h>
33#include <stdio.h> 39#include <stdio.h>
34#include <stdarg.h> 40#include <stdarg.h>
35#include <string.h> 41#include <string.h>
@@ -241,7 +247,7 @@ match_principals_file(char *file, struct passwd *pw, struct KeyCert *cert)
241 if (strcmp(cp, cert->principals[i]) == 0) { 247 if (strcmp(cp, cert->principals[i]) == 0) {
242 debug3("matched principal \"%.100s\" " 248 debug3("matched principal \"%.100s\" "
243 "from file \"%s\" on line %lu", 249 "from file \"%s\" on line %lu",
244 cert->principals[i], file, linenum); 250 cert->principals[i], file, linenum);
245 if (auth_parse_options(pw, line_opts, 251 if (auth_parse_options(pw, line_opts,
246 file, linenum) != 1) 252 file, linenum) != 1)
247 continue; 253 continue;
@@ -254,31 +260,22 @@ match_principals_file(char *file, struct passwd *pw, struct KeyCert *cert)
254 fclose(f); 260 fclose(f);
255 restore_uid(); 261 restore_uid();
256 return 0; 262 return 0;
257} 263}
258 264
259/* return 1 if user allows given key */ 265/*
266 * Checks whether key is allowed in authorized_keys-format file,
267 * returns 1 if the key is allowed or 0 otherwise.
268 */
260static int 269static int
261user_key_allowed2(struct passwd *pw, Key *key, char *file) 270check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw)
262{ 271{
263 char line[SSH_MAX_PUBKEY_BYTES]; 272 char line[SSH_MAX_PUBKEY_BYTES];
264 const char *reason; 273 const char *reason;
265 int found_key = 0; 274 int found_key = 0;
266 FILE *f;
267 u_long linenum = 0; 275 u_long linenum = 0;
268 Key *found; 276 Key *found;
269 char *fp; 277 char *fp;
270 278
271 /* Temporarily use the user's uid. */
272 temporarily_use_uid(pw);
273
274 debug("trying public key file %s", file);
275 f = auth_openkeyfile(file, pw, options.strict_modes);
276
277 if (!f) {
278 restore_uid();
279 return 0;
280 }
281
282 found_key = 0; 279 found_key = 0;
283 found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type); 280 found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type);
284 281
@@ -373,8 +370,6 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file)
373 break; 370 break;
374 } 371 }
375 } 372 }
376 restore_uid();
377 fclose(f);
378 key_free(found); 373 key_free(found);
379 if (!found_key) 374 if (!found_key)
380 debug2("key not found"); 375 debug2("key not found");
@@ -437,7 +432,180 @@ user_cert_trusted_ca(struct passwd *pw, Key *key)
437 return ret; 432 return ret;
438} 433}
439 434
440/* check whether given key is in .ssh/authorized_keys* */ 435/*
436 * Checks whether key is allowed in file.
437 * returns 1 if the key is allowed or 0 otherwise.
438 */
439static int
440user_key_allowed2(struct passwd *pw, Key *key, char *file)
441{
442 FILE *f;
443 int found_key = 0;
444
445 /* Temporarily use the user's uid. */
446 temporarily_use_uid(pw);
447
448 debug("trying public key file %s", file);
449 if ((f = auth_openkeyfile(file, pw, options.strict_modes)) != NULL) {
450 found_key = check_authkeys_file(f, file, key, pw);
451 fclose(f);
452 }
453
454 restore_uid();
455 return found_key;
456}
457
458/*
459 * Checks whether key is allowed in output of command.
460 * returns 1 if the key is allowed or 0 otherwise.
461 */
462static int
463user_key_command_allowed2(struct passwd *user_pw, Key *key)
464{
465 FILE *f;
466 int ok, found_key = 0;
467 struct passwd *pw;
468 struct stat st;
469 int status, devnull, p[2], i;
470 pid_t pid;
471 char *username, errmsg[512];
472
473 if (options.authorized_keys_command == NULL ||
474 options.authorized_keys_command[0] != '/')
475 return 0;
476
477 if (options.authorized_keys_command_user == NULL) {
478 error("No user for AuthorizedKeysCommand specified, skipping");
479 return 0;
480 }
481
482 username = percent_expand(options.authorized_keys_command_user,
483 "u", user_pw->pw_name, (char *)NULL);
484 pw = getpwnam(username);
485 if (pw == NULL) {
486 error("AuthorizedKeysCommandUser \"%s\" not found: %s",
487 username, strerror(errno));
488 free(username);
489 return 0;
490 }
491 free(username);
492
493 temporarily_use_uid(pw);
494
495 if (stat(options.authorized_keys_command, &st) < 0) {
496 error("Could not stat AuthorizedKeysCommand \"%s\": %s",
497 options.authorized_keys_command, strerror(errno));
498 goto out;
499 }
500 if (auth_secure_path(options.authorized_keys_command, &st, NULL, 0,
501 errmsg, sizeof(errmsg)) != 0) {
502 error("Unsafe AuthorizedKeysCommand: %s", errmsg);
503 goto out;
504 }
505
506 if (pipe(p) != 0) {
507 error("%s: pipe: %s", __func__, strerror(errno));
508 goto out;
509 }
510
511 debug3("Running AuthorizedKeysCommand: \"%s %s\" as \"%s\"",
512 options.authorized_keys_command, user_pw->pw_name, pw->pw_name);
513
514 /*
515 * Don't want to call this in the child, where it can fatal() and
516 * run cleanup_exit() code.
517 */
518 restore_uid();
519
520 switch ((pid = fork())) {
521 case -1: /* error */
522 error("%s: fork: %s", __func__, strerror(errno));
523 close(p[0]);
524 close(p[1]);
525 return 0;
526 case 0: /* child */
527 for (i = 0; i < NSIG; i++)
528 signal(i, SIG_DFL);
529
530 if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) {
531 error("%s: open %s: %s", __func__, _PATH_DEVNULL,
532 strerror(errno));
533 _exit(1);
534 }
535 /* Keep stderr around a while longer to catch errors */
536 if (dup2(devnull, STDIN_FILENO) == -1 ||
537 dup2(p[1], STDOUT_FILENO) == -1) {
538 error("%s: dup2: %s", __func__, strerror(errno));
539 _exit(1);
540 }
541 closefrom(STDERR_FILENO + 1);
542
543 /* Don't use permanently_set_uid() here to avoid fatal() */
544 if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) {
545 error("setresgid %u: %s", (u_int)pw->pw_gid,
546 strerror(errno));
547 _exit(1);
548 }
549 if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0) {
550 error("setresuid %u: %s", (u_int)pw->pw_uid,
551 strerror(errno));
552 _exit(1);
553 }
554 /* stdin is pointed to /dev/null at this point */
555 if (dup2(STDIN_FILENO, STDERR_FILENO) == -1) {
556 error("%s: dup2: %s", __func__, strerror(errno));
557 _exit(1);
558 }
559
560 execl(options.authorized_keys_command,
561 options.authorized_keys_command, user_pw->pw_name, NULL);
562
563 error("AuthorizedKeysCommand %s exec failed: %s",
564 options.authorized_keys_command, strerror(errno));
565 _exit(127);
566 default: /* parent */
567 break;
568 }
569
570 temporarily_use_uid(pw);
571
572 close(p[1]);
573 if ((f = fdopen(p[0], "r")) == NULL) {
574 error("%s: fdopen: %s", __func__, strerror(errno));
575 close(p[0]);
576 /* Don't leave zombie child */
577 kill(pid, SIGTERM);
578 while (waitpid(pid, NULL, 0) == -1 && errno == EINTR)
579 ;
580 goto out;
581 }
582 ok = check_authkeys_file(f, options.authorized_keys_command, key, pw);
583 fclose(f);
584
585 while (waitpid(pid, &status, 0) == -1) {
586 if (errno != EINTR) {
587 error("%s: waitpid: %s", __func__, strerror(errno));
588 goto out;
589 }
590 }
591 if (WIFSIGNALED(status)) {
592 error("AuthorizedKeysCommand %s exited on signal %d",
593 options.authorized_keys_command, WTERMSIG(status));
594 goto out;
595 } else if (WEXITSTATUS(status) != 0) {
596 error("AuthorizedKeysCommand %s returned status %d",
597 options.authorized_keys_command, WEXITSTATUS(status));
598 goto out;
599 }
600 found_key = ok;
601 out:
602 restore_uid();
603 return found_key;
604}
605
606/*
607 * Check whether key authenticates and authorises the user.
608 */
441int 609int
442user_key_allowed(struct passwd *pw, Key *key) 610user_key_allowed(struct passwd *pw, Key *key)
443{ 611{
@@ -454,9 +622,17 @@ user_key_allowed(struct passwd *pw, Key *key)
454 if (success) 622 if (success)
455 return success; 623 return success;
456 624
625 success = user_key_command_allowed2(pw, key);
626 if (success > 0)
627 return success;
628
457 for (i = 0; !success && i < options.num_authkeys_files; i++) { 629 for (i = 0; !success && i < options.num_authkeys_files; i++) {
630
631 if (strcasecmp(options.authorized_keys_files[i], "none") == 0)
632 continue;
458 file = expand_authorized_keys( 633 file = expand_authorized_keys(
459 options.authorized_keys_files[i], pw); 634 options.authorized_keys_files[i], pw);
635
460 success = user_key_allowed2(pw, key, file); 636 success = user_key_allowed2(pw, key, file);
461 xfree(file); 637 xfree(file);
462 } 638 }