diff options
author | Colin Watson <cjwatson@debian.org> | 2017-10-04 11:23:58 +0100 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2017-10-04 11:23:58 +0100 |
commit | 62f54f20bf351468e0124f63cc2902ee40d9b0e9 (patch) | |
tree | 3e090f2711b94ca5029d3fa3e8047b1ed1448b1f /auth.c | |
parent | 6fabaf6fd9b07cc8bc6a17c9c4a5b76849cfc874 (diff) | |
parent | 66bf74a92131b7effe49fb0eefe5225151869dc5 (diff) |
Import openssh_7.6p1.orig.tar.gz
Diffstat (limited to 'auth.c')
-rw-r--r-- | auth.c | 165 |
1 files changed, 49 insertions, 116 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth.c,v 1.119 2016/12/15 21:29:05 dtucker Exp $ */ | 1 | /* $OpenBSD: auth.c,v 1.124 2017/09/12 06:32:07 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -43,9 +43,6 @@ | |||
43 | #ifdef USE_SHADOW | 43 | #ifdef USE_SHADOW |
44 | #include <shadow.h> | 44 | #include <shadow.h> |
45 | #endif | 45 | #endif |
46 | #ifdef HAVE_LIBGEN_H | ||
47 | #include <libgen.h> | ||
48 | #endif | ||
49 | #include <stdarg.h> | 46 | #include <stdarg.h> |
50 | #include <stdio.h> | 47 | #include <stdio.h> |
51 | #include <string.h> | 48 | #include <string.h> |
@@ -267,21 +264,41 @@ allowed_user(struct passwd * pw) | |||
267 | return 1; | 264 | return 1; |
268 | } | 265 | } |
269 | 266 | ||
270 | void | 267 | /* |
271 | auth_info(Authctxt *authctxt, const char *fmt, ...) | 268 | * Formats any key left in authctxt->auth_method_key for inclusion in |
269 | * auth_log()'s message. Also includes authxtct->auth_method_info if present. | ||
270 | */ | ||
271 | static char * | ||
272 | format_method_key(Authctxt *authctxt) | ||
272 | { | 273 | { |
273 | va_list ap; | 274 | const struct sshkey *key = authctxt->auth_method_key; |
274 | int i; | 275 | const char *methinfo = authctxt->auth_method_info; |
275 | 276 | char *fp, *ret = NULL; | |
276 | free(authctxt->info); | ||
277 | authctxt->info = NULL; | ||
278 | 277 | ||
279 | va_start(ap, fmt); | 278 | if (key == NULL) |
280 | i = vasprintf(&authctxt->info, fmt, ap); | 279 | return NULL; |
281 | va_end(ap); | ||
282 | 280 | ||
283 | if (i < 0 || authctxt->info == NULL) | 281 | if (key_is_cert(key)) { |
284 | fatal("vasprintf failed"); | 282 | fp = sshkey_fingerprint(key->cert->signature_key, |
283 | options.fingerprint_hash, SSH_FP_DEFAULT); | ||
284 | xasprintf(&ret, "%s ID %s (serial %llu) CA %s %s%s%s", | ||
285 | sshkey_type(key), key->cert->key_id, | ||
286 | (unsigned long long)key->cert->serial, | ||
287 | sshkey_type(key->cert->signature_key), | ||
288 | fp == NULL ? "(null)" : fp, | ||
289 | methinfo == NULL ? "" : ", ", | ||
290 | methinfo == NULL ? "" : methinfo); | ||
291 | free(fp); | ||
292 | } else { | ||
293 | fp = sshkey_fingerprint(key, options.fingerprint_hash, | ||
294 | SSH_FP_DEFAULT); | ||
295 | xasprintf(&ret, "%s %s%s%s", sshkey_type(key), | ||
296 | fp == NULL ? "(null)" : fp, | ||
297 | methinfo == NULL ? "" : ", ", | ||
298 | methinfo == NULL ? "" : methinfo); | ||
299 | free(fp); | ||
300 | } | ||
301 | return ret; | ||
285 | } | 302 | } |
286 | 303 | ||
287 | void | 304 | void |
@@ -290,7 +307,8 @@ auth_log(Authctxt *authctxt, int authenticated, int partial, | |||
290 | { | 307 | { |
291 | struct ssh *ssh = active_state; /* XXX */ | 308 | struct ssh *ssh = active_state; /* XXX */ |
292 | void (*authlog) (const char *fmt,...) = verbose; | 309 | void (*authlog) (const char *fmt,...) = verbose; |
293 | char *authmsg; | 310 | const char *authmsg; |
311 | char *extra = NULL; | ||
294 | 312 | ||
295 | if (use_privsep && !mm_is_monitor() && !authctxt->postponed) | 313 | if (use_privsep && !mm_is_monitor() && !authctxt->postponed) |
296 | return; | 314 | return; |
@@ -309,6 +327,11 @@ auth_log(Authctxt *authctxt, int authenticated, int partial, | |||
309 | else | 327 | else |
310 | authmsg = authenticated ? "Accepted" : "Failed"; | 328 | authmsg = authenticated ? "Accepted" : "Failed"; |
311 | 329 | ||
330 | if ((extra = format_method_key(authctxt)) == NULL) { | ||
331 | if (authctxt->auth_method_info != NULL) | ||
332 | extra = xstrdup(authctxt->auth_method_info); | ||
333 | } | ||
334 | |||
312 | authlog("%s %s%s%s for %s%.100s from %.200s port %d ssh2%s%s", | 335 | authlog("%s %s%s%s for %s%.100s from %.200s port %d ssh2%s%s", |
313 | authmsg, | 336 | authmsg, |
314 | method, | 337 | method, |
@@ -317,10 +340,10 @@ auth_log(Authctxt *authctxt, int authenticated, int partial, | |||
317 | authctxt->user, | 340 | authctxt->user, |
318 | ssh_remote_ipaddr(ssh), | 341 | ssh_remote_ipaddr(ssh), |
319 | ssh_remote_port(ssh), | 342 | ssh_remote_port(ssh), |
320 | authctxt->info != NULL ? ": " : "", | 343 | extra != NULL ? ": " : "", |
321 | authctxt->info != NULL ? authctxt->info : ""); | 344 | extra != NULL ? extra : ""); |
322 | free(authctxt->info); | 345 | |
323 | authctxt->info = NULL; | 346 | free(extra); |
324 | 347 | ||
325 | #ifdef CUSTOM_FAILED_LOGIN | 348 | #ifdef CUSTOM_FAILED_LOGIN |
326 | if (authenticated == 0 && !authctxt->postponed && | 349 | if (authenticated == 0 && !authctxt->postponed && |
@@ -428,7 +451,7 @@ authorized_principals_file(struct passwd *pw) | |||
428 | 451 | ||
429 | /* return ok if key exists in sysfile or userfile */ | 452 | /* return ok if key exists in sysfile or userfile */ |
430 | HostStatus | 453 | HostStatus |
431 | check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host, | 454 | check_key_in_hostfiles(struct passwd *pw, struct sshkey *key, const char *host, |
432 | const char *sysfile, const char *userfile) | 455 | const char *sysfile, const char *userfile) |
433 | { | 456 | { |
434 | char *user_hostfile; | 457 | char *user_hostfile; |
@@ -472,98 +495,6 @@ check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host, | |||
472 | return host_status; | 495 | return host_status; |
473 | } | 496 | } |
474 | 497 | ||
475 | /* | ||
476 | * Check a given path for security. This is defined as all components | ||
477 | * of the path to the file must be owned by either the owner of | ||
478 | * of the file or root and no directories must be group or world writable. | ||
479 | * | ||
480 | * XXX Should any specific check be done for sym links ? | ||
481 | * | ||
482 | * Takes a file name, its stat information (preferably from fstat() to | ||
483 | * avoid races), the uid of the expected owner, their home directory and an | ||
484 | * error buffer plus max size as arguments. | ||
485 | * | ||
486 | * Returns 0 on success and -1 on failure | ||
487 | */ | ||
488 | int | ||
489 | auth_secure_path(const char *name, struct stat *stp, const char *pw_dir, | ||
490 | uid_t uid, char *err, size_t errlen) | ||
491 | { | ||
492 | char buf[PATH_MAX], homedir[PATH_MAX]; | ||
493 | char *cp; | ||
494 | int comparehome = 0; | ||
495 | struct stat st; | ||
496 | |||
497 | if (realpath(name, buf) == NULL) { | ||
498 | snprintf(err, errlen, "realpath %s failed: %s", name, | ||
499 | strerror(errno)); | ||
500 | return -1; | ||
501 | } | ||
502 | if (pw_dir != NULL && realpath(pw_dir, homedir) != NULL) | ||
503 | comparehome = 1; | ||
504 | |||
505 | if (!S_ISREG(stp->st_mode)) { | ||
506 | snprintf(err, errlen, "%s is not a regular file", buf); | ||
507 | return -1; | ||
508 | } | ||
509 | if ((!platform_sys_dir_uid(stp->st_uid) && stp->st_uid != uid) || | ||
510 | (stp->st_mode & 022) != 0) { | ||
511 | snprintf(err, errlen, "bad ownership or modes for file %s", | ||
512 | buf); | ||
513 | return -1; | ||
514 | } | ||
515 | |||
516 | /* for each component of the canonical path, walking upwards */ | ||
517 | for (;;) { | ||
518 | if ((cp = dirname(buf)) == NULL) { | ||
519 | snprintf(err, errlen, "dirname() failed"); | ||
520 | return -1; | ||
521 | } | ||
522 | strlcpy(buf, cp, sizeof(buf)); | ||
523 | |||
524 | if (stat(buf, &st) < 0 || | ||
525 | (!platform_sys_dir_uid(st.st_uid) && st.st_uid != uid) || | ||
526 | (st.st_mode & 022) != 0) { | ||
527 | snprintf(err, errlen, | ||
528 | "bad ownership or modes for directory %s", buf); | ||
529 | return -1; | ||
530 | } | ||
531 | |||
532 | /* If are past the homedir then we can stop */ | ||
533 | if (comparehome && strcmp(homedir, buf) == 0) | ||
534 | break; | ||
535 | |||
536 | /* | ||
537 | * dirname should always complete with a "/" path, | ||
538 | * but we can be paranoid and check for "." too | ||
539 | */ | ||
540 | if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0)) | ||
541 | break; | ||
542 | } | ||
543 | return 0; | ||
544 | } | ||
545 | |||
546 | /* | ||
547 | * Version of secure_path() that accepts an open file descriptor to | ||
548 | * avoid races. | ||
549 | * | ||
550 | * Returns 0 on success and -1 on failure | ||
551 | */ | ||
552 | static int | ||
553 | secure_filename(FILE *f, const char *file, struct passwd *pw, | ||
554 | char *err, size_t errlen) | ||
555 | { | ||
556 | struct stat st; | ||
557 | |||
558 | /* check the open file to avoid races */ | ||
559 | if (fstat(fileno(f), &st) < 0) { | ||
560 | snprintf(err, errlen, "cannot stat file %s: %s", | ||
561 | file, strerror(errno)); | ||
562 | return -1; | ||
563 | } | ||
564 | return auth_secure_path(file, &st, pw->pw_dir, pw->pw_uid, err, errlen); | ||
565 | } | ||
566 | |||
567 | static FILE * | 498 | static FILE * |
568 | auth_openfile(const char *file, struct passwd *pw, int strict_modes, | 499 | auth_openfile(const char *file, struct passwd *pw, int strict_modes, |
569 | int log_missing, char *file_type) | 500 | int log_missing, char *file_type) |
@@ -596,7 +527,7 @@ auth_openfile(const char *file, struct passwd *pw, int strict_modes, | |||
596 | return NULL; | 527 | return NULL; |
597 | } | 528 | } |
598 | if (strict_modes && | 529 | if (strict_modes && |
599 | secure_filename(f, file, pw, line, sizeof(line)) != 0) { | 530 | safe_path_fd(fileno(f), file, pw, line, sizeof(line)) != 0) { |
600 | fclose(f); | 531 | fclose(f); |
601 | logit("Authentication refused: %s", line); | 532 | logit("Authentication refused: %s", line); |
602 | auth_debug_add("Ignored %s: %s", file_type, line); | 533 | auth_debug_add("Ignored %s: %s", file_type, line); |
@@ -635,6 +566,8 @@ getpwnamallow(const char *user) | |||
635 | 566 | ||
636 | ci->user = user; | 567 | ci->user = user; |
637 | parse_server_match_config(&options, ci); | 568 | parse_server_match_config(&options, ci); |
569 | log_change_level(options.log_level); | ||
570 | process_permitopen(ssh, &options); | ||
638 | 571 | ||
639 | #if defined(_AIX) && defined(HAVE_SETAUTHDB) | 572 | #if defined(_AIX) && defined(HAVE_SETAUTHDB) |
640 | aix_setauthdb(user); | 573 | aix_setauthdb(user); |
@@ -694,7 +627,7 @@ getpwnamallow(const char *user) | |||
694 | 627 | ||
695 | /* Returns 1 if key is revoked by revoked_keys_file, 0 otherwise */ | 628 | /* Returns 1 if key is revoked by revoked_keys_file, 0 otherwise */ |
696 | int | 629 | int |
697 | auth_key_is_revoked(Key *key) | 630 | auth_key_is_revoked(struct sshkey *key) |
698 | { | 631 | { |
699 | char *fp = NULL; | 632 | char *fp = NULL; |
700 | int r; | 633 | int r; |