auth.c (240075) | auth.c (248619) |
---|---|
1/* $OpenBSD: auth.c,v 1.96 2012/05/13 01:42:32 dtucker Exp $ */ | 1/* $OpenBSD: auth.c,v 1.101 2013/02/06 00:22:21 dtucker Exp $ */ |
2/* 3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. --- 9 unchanged lines hidden (view full) --- 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "includes.h" | 2/* 3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. --- 9 unchanged lines hidden (view full) --- 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "includes.h" |
27__RCSID("$FreeBSD: head/crypto/openssh/auth.c 240075 2012-09-03 16:51:41Z des $"); | 27__RCSID("$FreeBSD: head/crypto/openssh/auth.c 248619 2013-03-22 17:55:38Z des $"); |
28 29#include <sys/types.h> 30#include <sys/stat.h> 31#include <sys/param.h> 32 33#include <netinet/in.h> 34 35#include <errno.h> --- 31 unchanged lines hidden (view full) --- 67#include "misc.h" 68#include "packet.h" 69#include "loginrec.h" 70#ifdef GSSAPI 71#include "ssh-gss.h" 72#endif 73#include "authfile.h" 74#include "monitor_wrap.h" | 28 29#include <sys/types.h> 30#include <sys/stat.h> 31#include <sys/param.h> 32 33#include <netinet/in.h> 34 35#include <errno.h> --- 31 unchanged lines hidden (view full) --- 67#include "misc.h" 68#include "packet.h" 69#include "loginrec.h" 70#ifdef GSSAPI 71#include "ssh-gss.h" 72#endif 73#include "authfile.h" 74#include "monitor_wrap.h" |
75#include "krl.h" |
|
75 76/* import */ 77extern ServerOptions options; 78extern int use_privsep; 79extern Buffer loginmsg; 80extern struct passwd *privsep_pw; 81 82/* Debugging messages */ --- 164 unchanged lines hidden (view full) --- 247 return 0; 248#endif 249 250 /* We found no reason not to let this user try to log on... */ 251 return 1; 252} 253 254void | 76 77/* import */ 78extern ServerOptions options; 79extern int use_privsep; 80extern Buffer loginmsg; 81extern struct passwd *privsep_pw; 82 83/* Debugging messages */ --- 164 unchanged lines hidden (view full) --- 248 return 0; 249#endif 250 251 /* We found no reason not to let this user try to log on... */ 252 return 1; 253} 254 255void |
255auth_log(Authctxt *authctxt, int authenticated, char *method, char *info) | 256auth_log(Authctxt *authctxt, int authenticated, int partial, 257 const char *method, const char *submethod, const char *info) |
256{ 257 void (*authlog) (const char *fmt,...) = verbose; 258 char *authmsg; 259 260 if (use_privsep && !mm_is_monitor() && !authctxt->postponed) 261 return; 262 263 /* Raise logging level */ 264 if (authenticated == 1 || 265 !authctxt->valid || 266 authctxt->failures >= options.max_authtries / 2 || 267 strcmp(method, "password") == 0) 268 authlog = logit; 269 270 if (authctxt->postponed) 271 authmsg = "Postponed"; | 258{ 259 void (*authlog) (const char *fmt,...) = verbose; 260 char *authmsg; 261 262 if (use_privsep && !mm_is_monitor() && !authctxt->postponed) 263 return; 264 265 /* Raise logging level */ 266 if (authenticated == 1 || 267 !authctxt->valid || 268 authctxt->failures >= options.max_authtries / 2 || 269 strcmp(method, "password") == 0) 270 authlog = logit; 271 272 if (authctxt->postponed) 273 authmsg = "Postponed"; |
274 else if (partial) 275 authmsg = "Partial"; |
|
272 else 273 authmsg = authenticated ? "Accepted" : "Failed"; 274 | 276 else 277 authmsg = authenticated ? "Accepted" : "Failed"; 278 |
275 authlog("%s %s for %s%.100s from %.200s port %d%s", | 279 authlog("%s %s%s%s for %s%.100s from %.200s port %d%s", |
276 authmsg, 277 method, | 280 authmsg, 281 method, |
282 submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod, |
|
278 authctxt->valid ? "" : "invalid user ", 279 authctxt->user, 280 get_remote_ipaddr(), 281 get_remote_port(), 282 info); 283 284#ifdef CUSTOM_FAILED_LOGIN 285 if (authenticated == 0 && !authctxt->postponed && --- 13 unchanged lines hidden (view full) --- 299 audit_event(audit_classify_auth(method)); 300#endif 301} 302 303/* 304 * Check whether root logins are disallowed. 305 */ 306int | 283 authctxt->valid ? "" : "invalid user ", 284 authctxt->user, 285 get_remote_ipaddr(), 286 get_remote_port(), 287 info); 288 289#ifdef CUSTOM_FAILED_LOGIN 290 if (authenticated == 0 && !authctxt->postponed && --- 13 unchanged lines hidden (view full) --- 304 audit_event(audit_classify_auth(method)); 305#endif 306} 307 308/* 309 * Check whether root logins are disallowed. 310 */ 311int |
307auth_root_allowed(char *method) | 312auth_root_allowed(const char *method) |
308{ 309 switch (options.permit_root_login) { 310 case PERMIT_YES: 311 return 1; 312 case PERMIT_NO_PASSWD: 313 if (strcmp(method, "password") != 0) 314 return 1; 315 break; --- 89 unchanged lines hidden (view full) --- 405 else 406 debug("%s: key for host %s not found", __func__, host); 407 408 free_hostkeys(hostkeys); 409 410 return host_status; 411} 412 | 313{ 314 switch (options.permit_root_login) { 315 case PERMIT_YES: 316 return 1; 317 case PERMIT_NO_PASSWD: 318 if (strcmp(method, "password") != 0) 319 return 1; 320 break; --- 89 unchanged lines hidden (view full) --- 410 else 411 debug("%s: key for host %s not found", __func__, host); 412 413 free_hostkeys(hostkeys); 414 415 return host_status; 416} 417 |
413 | |
414/* | 418/* |
415 * Check a given file for security. This is defined as all components | 419 * Check a given path for security. This is defined as all components |
416 * of the path to the file must be owned by either the owner of 417 * of the file or root and no directories must be group or world writable. 418 * 419 * XXX Should any specific check be done for sym links ? 420 * | 420 * of the path to the file must be owned by either the owner of 421 * of the file or root and no directories must be group or world writable. 422 * 423 * XXX Should any specific check be done for sym links ? 424 * |
421 * Takes an open file descriptor, the file name, a uid and and | 425 * Takes a file name, its stat information (preferably from fstat() to 426 * avoid races), the uid of the expected owner, their home directory and an |
422 * error buffer plus max size as arguments. 423 * 424 * Returns 0 on success and -1 on failure 425 */ | 427 * error buffer plus max size as arguments. 428 * 429 * Returns 0 on success and -1 on failure 430 */ |
426static int 427secure_filename(FILE *f, const char *file, struct passwd *pw, 428 char *err, size_t errlen) | 431int 432auth_secure_path(const char *name, struct stat *stp, const char *pw_dir, 433 uid_t uid, char *err, size_t errlen) |
429{ | 434{ |
430 uid_t uid = pw->pw_uid; | |
431 char buf[MAXPATHLEN], homedir[MAXPATHLEN]; 432 char *cp; 433 int comparehome = 0; 434 struct stat st; 435 | 435 char buf[MAXPATHLEN], homedir[MAXPATHLEN]; 436 char *cp; 437 int comparehome = 0; 438 struct stat st; 439 |
436 if (realpath(file, buf) == NULL) { 437 snprintf(err, errlen, "realpath %s failed: %s", file, | 440 if (realpath(name, buf) == NULL) { 441 snprintf(err, errlen, "realpath %s failed: %s", name, |
438 strerror(errno)); 439 return -1; 440 } | 442 strerror(errno)); 443 return -1; 444 } |
441 if (realpath(pw->pw_dir, homedir) != NULL) | 445 if (pw_dir != NULL && realpath(pw_dir, homedir) != NULL) |
442 comparehome = 1; 443 | 446 comparehome = 1; 447 |
444 /* check the open file to avoid races */ 445 if (fstat(fileno(f), &st) < 0 || 446 (st.st_uid != 0 && st.st_uid != uid) || 447 (st.st_mode & 022) != 0) { | 448 if (!S_ISREG(stp->st_mode)) { 449 snprintf(err, errlen, "%s is not a regular file", buf); 450 return -1; 451 } 452 if ((!platform_sys_dir_uid(stp->st_uid) && stp->st_uid != uid) || 453 (stp->st_mode & 022) != 0) { |
448 snprintf(err, errlen, "bad ownership or modes for file %s", 449 buf); 450 return -1; 451 } 452 453 /* for each component of the canonical path, walking upwards */ 454 for (;;) { 455 if ((cp = dirname(buf)) == NULL) { 456 snprintf(err, errlen, "dirname() failed"); 457 return -1; 458 } 459 strlcpy(buf, cp, sizeof(buf)); 460 461 if (stat(buf, &st) < 0 || | 454 snprintf(err, errlen, "bad ownership or modes for file %s", 455 buf); 456 return -1; 457 } 458 459 /* for each component of the canonical path, walking upwards */ 460 for (;;) { 461 if ((cp = dirname(buf)) == NULL) { 462 snprintf(err, errlen, "dirname() failed"); 463 return -1; 464 } 465 strlcpy(buf, cp, sizeof(buf)); 466 467 if (stat(buf, &st) < 0 || |
462 (st.st_uid != 0 && st.st_uid != uid) || | 468 (!platform_sys_dir_uid(st.st_uid) && st.st_uid != uid) || |
463 (st.st_mode & 022) != 0) { 464 snprintf(err, errlen, 465 "bad ownership or modes for directory %s", buf); 466 return -1; 467 } 468 469 /* If are past the homedir then we can stop */ 470 if (comparehome && strcmp(homedir, buf) == 0) --- 4 unchanged lines hidden (view full) --- 475 * but we can be paranoid and check for "." too 476 */ 477 if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0)) 478 break; 479 } 480 return 0; 481} 482 | 469 (st.st_mode & 022) != 0) { 470 snprintf(err, errlen, 471 "bad ownership or modes for directory %s", buf); 472 return -1; 473 } 474 475 /* If are past the homedir then we can stop */ 476 if (comparehome && strcmp(homedir, buf) == 0) --- 4 unchanged lines hidden (view full) --- 481 * but we can be paranoid and check for "." too 482 */ 483 if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0)) 484 break; 485 } 486 return 0; 487} 488 |
489/* 490 * Version of secure_path() that accepts an open file descriptor to 491 * avoid races. 492 * 493 * Returns 0 on success and -1 on failure 494 */ 495static int 496secure_filename(FILE *f, const char *file, struct passwd *pw, 497 char *err, size_t errlen) 498{ 499 struct stat st; 500 501 /* check the open file to avoid races */ 502 if (fstat(fileno(f), &st) < 0) { 503 snprintf(err, errlen, "cannot stat file %s: %s", 504 file, strerror(errno)); 505 return -1; 506 } 507 return auth_secure_path(file, &st, pw->pw_dir, pw->pw_uid, err, errlen); 508} 509 |
|
483static FILE * 484auth_openfile(const char *file, struct passwd *pw, int strict_modes, 485 int log_missing, char *file_type) 486{ 487 char line[1024]; 488 struct stat st; 489 int fd; 490 FILE *f; --- 119 unchanged lines hidden (view full) --- 610/* Returns 1 if key is revoked by revoked_keys_file, 0 otherwise */ 611int 612auth_key_is_revoked(Key *key) 613{ 614 char *key_fp; 615 616 if (options.revoked_keys_file == NULL) 617 return 0; | 510static FILE * 511auth_openfile(const char *file, struct passwd *pw, int strict_modes, 512 int log_missing, char *file_type) 513{ 514 char line[1024]; 515 struct stat st; 516 int fd; 517 FILE *f; --- 119 unchanged lines hidden (view full) --- 637/* Returns 1 if key is revoked by revoked_keys_file, 0 otherwise */ 638int 639auth_key_is_revoked(Key *key) 640{ 641 char *key_fp; 642 643 if (options.revoked_keys_file == NULL) 644 return 0; |
618 | 645 switch (ssh_krl_file_contains_key(options.revoked_keys_file, key)) { 646 case 0: 647 return 0; /* Not revoked */ 648 case -2: 649 break; /* Not a KRL */ 650 default: 651 goto revoked; 652 } 653 debug3("%s: treating %s as a key list", __func__, 654 options.revoked_keys_file); |
619 switch (key_in_file(key, options.revoked_keys_file, 0)) { 620 case 0: 621 /* key not revoked */ 622 return 0; 623 case -1: 624 /* Error opening revoked_keys_file: refuse all keys */ 625 error("Revoked keys file is unreadable: refusing public key " 626 "authentication"); 627 return 1; 628 case 1: | 655 switch (key_in_file(key, options.revoked_keys_file, 0)) { 656 case 0: 657 /* key not revoked */ 658 return 0; 659 case -1: 660 /* Error opening revoked_keys_file: refuse all keys */ 661 error("Revoked keys file is unreadable: refusing public key " 662 "authentication"); 663 return 1; 664 case 1: |
665 revoked: |
|
629 /* Key revoked */ 630 key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); 631 error("WARNING: authentication attempt with a revoked " 632 "%s key %s ", key_type(key), key_fp); 633 xfree(key_fp); 634 return 1; 635 } 636 fatal("key_in_file returned junk"); --- 62 unchanged lines hidden --- | 666 /* Key revoked */ 667 key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); 668 error("WARNING: authentication attempt with a revoked " 669 "%s key %s ", key_type(key), key_fp); 670 xfree(key_fp); 671 return 1; 672 } 673 fatal("key_in_file returned junk"); --- 62 unchanged lines hidden --- |