1 /* 2 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 */ 24 25 #include "includes.h" 26 RCSID("$OpenBSD: auth.c,v 1.60 2005/06/17 02:44:32 djm Exp $"); 27 RCSID("$FreeBSD$"); 28 29 #ifdef HAVE_LOGIN_H 30 #include <login.h> 31 #endif 32 #ifdef USE_SHADOW 33 #include <shadow.h> 34 #endif 35 36 #ifdef HAVE_LIBGEN_H 37 #include <libgen.h> 38 #endif 39 40 #include "xmalloc.h" 41 #include "match.h" 42 #include "groupaccess.h" 43 #include "log.h" 44 #include "servconf.h" 45 #include "auth.h" 46 #include "auth-options.h" 47 #include "canohost.h" 48 #include "buffer.h" 49 #include "bufaux.h" 50 #include "uidswap.h" 51 #include "misc.h" 52 #include "bufaux.h" 53 #include "packet.h" 54 #include "loginrec.h" 55 #include "monitor_wrap.h" 56 57 /* import */ 58 extern ServerOptions options; 59 extern Buffer loginmsg; 60 61 /* Debugging messages */ 62 Buffer auth_debug; 63 int auth_debug_init; 64 65 /* 66 * Check if the user is allowed to log in via ssh. If user is listed 67 * in DenyUsers or one of user's groups is listed in DenyGroups, false 68 * will be returned. If AllowUsers isn't empty and user isn't listed 69 * there, or if AllowGroups isn't empty and one of user's groups isn't 70 * listed there, false will be returned. 71 * If the user's shell is not executable, false will be returned. 72 * Otherwise true is returned. 73 */ 74 int 75 allowed_user(struct passwd * pw) 76 { 77 struct stat st; 78 const char *hostname = NULL, *ipaddr = NULL, *passwd = NULL; 79 char *shell; 80 u_int i; 81 #ifdef USE_SHADOW 82 struct spwd *spw = NULL; 83 #endif 84 85 /* Shouldn't be called if pw is NULL, but better safe than sorry... */ 86 if (!pw || !pw->pw_name) 87 return 0; 88 89 #ifdef USE_SHADOW 90 if (!options.use_pam) 91 spw = getspnam(pw->pw_name); 92 #ifdef HAS_SHADOW_EXPIRE 93 if (!options.use_pam && spw != NULL && auth_shadow_acctexpired(spw)) 94 return 0; 95 #endif /* HAS_SHADOW_EXPIRE */ 96 #endif /* USE_SHADOW */ 97 98 /* grab passwd field for locked account check */ 99 #ifdef USE_SHADOW 100 if (spw != NULL) 101 #if defined(HAVE_LIBIAF) && !defined(BROKEN_LIBIAF) 102 passwd = get_iaf_password(pw); 103 #else 104 passwd = spw->sp_pwdp; 105 #endif /* HAVE_LIBIAF && !BROKEN_LIBIAF */ 106 #else 107 passwd = pw->pw_passwd; 108 #endif 109 110 /* check for locked account */ 111 if (!options.use_pam && passwd && *passwd) { 112 int locked = 0; 113 114 #ifdef LOCKED_PASSWD_STRING 115 if (strcmp(passwd, LOCKED_PASSWD_STRING) == 0) 116 locked = 1; 117 #endif 118 #ifdef LOCKED_PASSWD_PREFIX 119 if (strncmp(passwd, LOCKED_PASSWD_PREFIX, 120 strlen(LOCKED_PASSWD_PREFIX)) == 0) 121 locked = 1; 122 #endif 123 #ifdef LOCKED_PASSWD_SUBSTR 124 if (strstr(passwd, LOCKED_PASSWD_SUBSTR)) 125 locked = 1; 126 #endif 127 #if defined(HAVE_LIBIAF) && !defined(BROKEN_LIBIAF) 128 free(passwd); 129 #endif /* HAVE_LIBIAF && !BROKEN_LIBIAF */ 130 if (locked) { 131 logit("User %.100s not allowed because account is locked", 132 pw->pw_name); 133 return 0; 134 } 135 } 136 137 /* 138 * Get the shell from the password data. An empty shell field is 139 * legal, and means /bin/sh. 140 */ 141 shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell; 142 143 /* deny if shell does not exists or is not executable */ 144 if (stat(shell, &st) != 0) { 145 logit("User %.100s not allowed because shell %.100s does not exist", 146 pw->pw_name, shell); 147 return 0; 148 } 149 if (S_ISREG(st.st_mode) == 0 || 150 (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) { 151 logit("User %.100s not allowed because shell %.100s is not executable", 152 pw->pw_name, shell); 153 return 0; 154 } 155 156 if (options.num_deny_users > 0 || options.num_allow_users > 0 || 157 options.num_deny_groups > 0 || options.num_allow_groups > 0) { 158 hostname = get_canonical_hostname(options.use_dns); 159 ipaddr = get_remote_ipaddr(); 160 } 161 162 /* Return false if user is listed in DenyUsers */ 163 if (options.num_deny_users > 0) { 164 for (i = 0; i < options.num_deny_users; i++) 165 if (match_user(pw->pw_name, hostname, ipaddr, 166 options.deny_users[i])) { 167 logit("User %.100s from %.100s not allowed " 168 "because listed in DenyUsers", 169 pw->pw_name, hostname); 170 return 0; 171 } 172 } 173 /* Return false if AllowUsers isn't empty and user isn't listed there */ 174 if (options.num_allow_users > 0) { 175 for (i = 0; i < options.num_allow_users; i++) 176 if (match_user(pw->pw_name, hostname, ipaddr, 177 options.allow_users[i])) 178 break; 179 /* i < options.num_allow_users iff we break for loop */ 180 if (i >= options.num_allow_users) { 181 logit("User %.100s from %.100s not allowed because " 182 "not listed in AllowUsers", pw->pw_name, hostname); 183 return 0; 184 } 185 } 186 if (options.num_deny_groups > 0 || options.num_allow_groups > 0) { 187 /* Get the user's group access list (primary and supplementary) */ 188 if (ga_init(pw->pw_name, pw->pw_gid) == 0) { 189 logit("User %.100s from %.100s not allowed because " 190 "not in any group", pw->pw_name, hostname); 191 return 0; 192 } 193 194 /* Return false if one of user's groups is listed in DenyGroups */ 195 if (options.num_deny_groups > 0) 196 if (ga_match(options.deny_groups, 197 options.num_deny_groups)) { 198 ga_free(); 199 logit("User %.100s from %.100s not allowed " 200 "because a group is listed in DenyGroups", 201 pw->pw_name, hostname); 202 return 0; 203 } 204 /* 205 * Return false if AllowGroups isn't empty and one of user's groups 206 * isn't listed there 207 */ 208 if (options.num_allow_groups > 0) 209 if (!ga_match(options.allow_groups, 210 options.num_allow_groups)) { 211 ga_free(); 212 logit("User %.100s from %.100s not allowed " 213 "because none of user's groups are listed " 214 "in AllowGroups", pw->pw_name, hostname); 215 return 0; 216 } 217 ga_free(); 218 } 219 220 #ifdef CUSTOM_SYS_AUTH_ALLOWED_USER 221 if (!sys_auth_allowed_user(pw, &loginmsg)) 222 return 0; 223 #endif 224 225 /* We found no reason not to let this user try to log on... */ 226 return 1; 227 } 228 229 void 230 auth_log(Authctxt *authctxt, int authenticated, char *method, char *info) 231 { 232 void (*authlog) (const char *fmt,...) = verbose; 233 char *authmsg; 234 235 /* Raise logging level */ 236 if (authenticated == 1 || 237 !authctxt->valid || 238 authctxt->failures >= options.max_authtries / 2 || 239 strcmp(method, "password") == 0) 240 authlog = logit; 241 242 if (authctxt->postponed) 243 authmsg = "Postponed"; 244 else 245 authmsg = authenticated ? "Accepted" : "Failed"; 246 247 authlog("%s %s for %s%.100s from %.200s port %d%s", 248 authmsg, 249 method, 250 authctxt->valid ? "" : "invalid user ", 251 authctxt->user, 252 get_remote_ipaddr(), 253 get_remote_port(), 254 info); 255 256 #ifdef CUSTOM_FAILED_LOGIN 257 if (authenticated == 0 && !authctxt->postponed && 258 (strcmp(method, "password") == 0 || 259 strncmp(method, "keyboard-interactive", 20) == 0 || 260 strcmp(method, "challenge-response") == 0)) 261 record_failed_login(authctxt->user, 262 get_canonical_hostname(options.use_dns), "ssh"); 263 #endif 264 #ifdef SSH_AUDIT_EVENTS 265 if (authenticated == 0 && !authctxt->postponed) { 266 ssh_audit_event_t event; 267 268 debug3("audit failed auth attempt, method %s euid %d", 269 method, (int)geteuid()); 270 /* 271 * Because the auth loop is used in both monitor and slave, 272 * we must be careful to send each event only once and with 273 * enough privs to write the event. 274 */ 275 event = audit_classify_auth(method); 276 switch(event) { 277 case SSH_AUTH_FAIL_NONE: 278 case SSH_AUTH_FAIL_PASSWD: 279 case SSH_AUTH_FAIL_KBDINT: 280 if (geteuid() == 0) 281 audit_event(event); 282 break; 283 case SSH_AUTH_FAIL_PUBKEY: 284 case SSH_AUTH_FAIL_HOSTBASED: 285 case SSH_AUTH_FAIL_GSSAPI: 286 /* 287 * This is required to handle the case where privsep 288 * is enabled but it's root logging in, since 289 * use_privsep won't be cleared until after a 290 * successful login. 291 */ 292 if (geteuid() == 0) 293 audit_event(event); 294 else 295 PRIVSEP(audit_event(event)); 296 break; 297 default: 298 error("unknown authentication audit event %d", event); 299 } 300 } 301 #endif 302 } 303 304 /* 305 * Check whether root logins are disallowed. 306 */ 307 int 308 auth_root_allowed(char *method) 309 { 310 switch (options.permit_root_login) { 311 case PERMIT_YES: 312 return 1; 313 break; 314 case PERMIT_NO_PASSWD: 315 if (strcmp(method, "password") != 0) 316 return 1; 317 break; 318 case PERMIT_FORCED_ONLY: 319 if (forced_command) { 320 logit("Root login accepted for forced command."); 321 return 1; 322 } 323 break; 324 } 325 logit("ROOT LOGIN REFUSED FROM %.200s", get_remote_ipaddr()); 326 return 0; 327 } 328 329 330 /* 331 * Given a template and a passwd structure, build a filename 332 * by substituting % tokenised options. Currently, %% becomes '%', 333 * %h becomes the home directory and %u the username. 334 * 335 * This returns a buffer allocated by xmalloc. 336 */ 337 static char * 338 expand_authorized_keys(const char *filename, struct passwd *pw) 339 { 340 char *file, *ret; 341 342 file = percent_expand(filename, "h", pw->pw_dir, 343 "u", pw->pw_name, (char *)NULL); 344 345 /* 346 * Ensure that filename starts anchored. If not, be backward 347 * compatible and prepend the '%h/' 348 */ 349 if (*file == '/') 350 return (file); 351 352 ret = xmalloc(MAXPATHLEN); 353 if (strlcpy(ret, pw->pw_dir, MAXPATHLEN) >= MAXPATHLEN || 354 strlcat(ret, "/", MAXPATHLEN) >= MAXPATHLEN || 355 strlcat(ret, file, MAXPATHLEN) >= MAXPATHLEN) 356 fatal("expand_authorized_keys: path too long"); 357 358 xfree(file); 359 return (ret); 360 } 361 362 char * 363 authorized_keys_file(struct passwd *pw) 364 { 365 return expand_authorized_keys(options.authorized_keys_file, pw); 366 } 367 368 char * 369 authorized_keys_file2(struct passwd *pw) 370 { 371 return expand_authorized_keys(options.authorized_keys_file2, pw); 372 } 373 374 /* return ok if key exists in sysfile or userfile */ 375 HostStatus 376 check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host, 377 const char *sysfile, const char *userfile) 378 { 379 Key *found; 380 char *user_hostfile; 381 struct stat st; 382 HostStatus host_status; 383 384 /* Check if we know the host and its host key. */ 385 found = key_new(key->type); 386 host_status = check_host_in_hostfile(sysfile, host, key, found, NULL); 387 388 if (host_status != HOST_OK && userfile != NULL) { 389 user_hostfile = tilde_expand_filename(userfile, pw->pw_uid); 390 if (options.strict_modes && 391 (stat(user_hostfile, &st) == 0) && 392 ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || 393 (st.st_mode & 022) != 0)) { 394 logit("Authentication refused for %.100s: " 395 "bad owner or modes for %.200s", 396 pw->pw_name, user_hostfile); 397 } else { 398 temporarily_use_uid(pw); 399 host_status = check_host_in_hostfile(user_hostfile, 400 host, key, found, NULL); 401 restore_uid(); 402 } 403 xfree(user_hostfile); 404 } 405 key_free(found); 406 407 debug2("check_key_in_hostfiles: key %s for %s", host_status == HOST_OK ? 408 "ok" : "not found", host); 409 return host_status; 410 } 411 412 413 /* 414 * Check a given file for security. This is defined as all components 415 * of the path to the file must be owned by either the owner of 416 * of the file or root and no directories must be group or world writable. 417 * 418 * XXX Should any specific check be done for sym links ? 419 * 420 * Takes an open file descriptor, the file name, a uid and and 421 * error buffer plus max size as arguments. 422 * 423 * Returns 0 on success and -1 on failure 424 */ 425 int 426 secure_filename(FILE *f, const char *file, struct passwd *pw, 427 char *err, size_t errlen) 428 { 429 uid_t uid = pw->pw_uid; 430 char buf[MAXPATHLEN], homedir[MAXPATHLEN]; 431 char *cp; 432 int comparehome = 0; 433 struct stat st; 434 435 if (realpath(file, buf) == NULL) { 436 snprintf(err, errlen, "realpath %s failed: %s", file, 437 strerror(errno)); 438 return -1; 439 } 440 if (realpath(pw->pw_dir, homedir) != NULL) 441 comparehome = 1; 442 443 /* check the open file to avoid races */ 444 if (fstat(fileno(f), &st) < 0 || 445 (st.st_uid != 0 && st.st_uid != uid) || 446 (st.st_mode & 022) != 0) { 447 snprintf(err, errlen, "bad ownership or modes for file %s", 448 buf); 449 return -1; 450 } 451 452 /* for each component of the canonical path, walking upwards */ 453 for (;;) { 454 if ((cp = dirname(buf)) == NULL) { 455 snprintf(err, errlen, "dirname() failed"); 456 return -1; 457 } 458 strlcpy(buf, cp, sizeof(buf)); 459 460 debug3("secure_filename: checking '%s'", buf); 461 if (stat(buf, &st) < 0 || 462 (st.st_uid != 0 && 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 passed the homedir then we can stop */ 470 if (comparehome && strcmp(homedir, buf) == 0) { 471 debug3("secure_filename: terminating check at '%s'", 472 buf); 473 break; 474 } 475 /* 476 * dirname should always complete with a "/" path, 477 * but we can be paranoid and check for "." too 478 */ 479 if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0)) 480 break; 481 } 482 return 0; 483 } 484 485 struct passwd * 486 getpwnamallow(const char *user) 487 { 488 #ifdef HAVE_LOGIN_CAP 489 extern login_cap_t *lc; 490 #ifdef BSD_AUTH 491 auth_session_t *as; 492 #endif 493 #endif 494 struct passwd *pw; 495 496 pw = getpwnam(user); 497 if (pw == NULL) { 498 logit("Invalid user %.100s from %.100s", 499 user, get_remote_ipaddr()); 500 #ifdef CUSTOM_FAILED_LOGIN 501 record_failed_login(user, 502 get_canonical_hostname(options.use_dns), "ssh"); 503 #endif 504 #ifdef SSH_AUDIT_EVENTS 505 audit_event(SSH_INVALID_USER); 506 #endif /* SSH_AUDIT_EVENTS */ 507 return (NULL); 508 } 509 if (!allowed_user(pw)) 510 return (NULL); 511 #ifdef HAVE_LOGIN_CAP 512 if ((lc = login_getpwclass(pw)) == NULL) { 513 debug("unable to get login class: %s", user); 514 return (NULL); 515 } 516 #ifdef BSD_AUTH 517 if ((as = auth_open()) == NULL || auth_setpwd(as, pw) != 0 || 518 auth_approval(as, lc, pw->pw_name, "ssh") <= 0) { 519 debug("Approval failure for %s", user); 520 pw = NULL; 521 } 522 if (as != NULL) 523 auth_close(as); 524 #endif 525 #endif 526 if (pw != NULL) 527 return (pwcopy(pw)); 528 return (NULL); 529 } 530 531 void 532 auth_debug_add(const char *fmt,...) 533 { 534 char buf[1024]; 535 va_list args; 536 537 if (!auth_debug_init) 538 return; 539 540 va_start(args, fmt); 541 vsnprintf(buf, sizeof(buf), fmt, args); 542 va_end(args); 543 buffer_put_cstring(&auth_debug, buf); 544 } 545 546 void 547 auth_debug_send(void) 548 { 549 char *msg; 550 551 if (!auth_debug_init) 552 return; 553 while (buffer_len(&auth_debug)) { 554 msg = buffer_get_string(&auth_debug, NULL); 555 packet_send_debug("%s", msg); 556 xfree(msg); 557 } 558 } 559 560 void 561 auth_debug_reset(void) 562 { 563 if (auth_debug_init) 564 buffer_clear(&auth_debug); 565 else { 566 buffer_init(&auth_debug); 567 auth_debug_init = 1; 568 } 569 } 570 571 struct passwd * 572 fakepw(void) 573 { 574 static struct passwd fake; 575 576 memset(&fake, 0, sizeof(fake)); 577 fake.pw_name = "NOUSER"; 578 fake.pw_passwd = 579 "$2a$06$r3.juUaHZDlIbQaO2dS9FuYxL1W9M81R1Tc92PoSNmzvpEqLkLGrK"; 580 fake.pw_gecos = "NOUSER"; 581 fake.pw_uid = (uid_t)-1; 582 fake.pw_gid = (gid_t)-1; 583 #ifdef HAVE_PW_CLASS_IN_PASSWD 584 fake.pw_class = ""; 585 #endif 586 fake.pw_dir = "/nonexist"; 587 fake.pw_shell = "/nonexist"; 588 589 return (&fake); 590 } 591