auth.c revision 248619
1184610Salfred/* $OpenBSD: auth.c,v 1.101 2013/02/06 00:22:21 dtucker Exp $ */ 2184610Salfred/* 3184610Salfred * Copyright (c) 2000 Markus Friedl. All rights reserved. 4184610Salfred * 5184610Salfred * Redistribution and use in source and binary forms, with or without 6184610Salfred * modification, are permitted provided that the following conditions 7184610Salfred * are met: 8184610Salfred * 1. Redistributions of source code must retain the above copyright 9184610Salfred * notice, this list of conditions and the following disclaimer. 10184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 11184610Salfred * notice, this list of conditions and the following disclaimer in the 12184610Salfred * documentation and/or other materials provided with the distribution. 13184610Salfred * 14184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15184610Salfred * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16184610Salfred * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17184610Salfred * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18184610Salfred * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19184610Salfred * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20184610Salfred * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21184610Salfred * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22184610Salfred * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23184610Salfred * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24184610Salfred */ 25184610Salfred 26184610Salfred#include "includes.h" 27184610Salfred__RCSID("$FreeBSD: head/crypto/openssh/auth.c 248619 2013-03-22 17:55:38Z des $"); 28184610Salfred 29184610Salfred#include <sys/types.h> 30184610Salfred#include <sys/stat.h> 31184610Salfred#include <sys/param.h> 32184610Salfred 33184610Salfred#include <netinet/in.h> 34184610Salfred 35184610Salfred#include <errno.h> 36184610Salfred#include <fcntl.h> 37184610Salfred#ifdef HAVE_PATHS_H 38194677Sthompsa# include <paths.h> 39194677Sthompsa#endif 40194677Sthompsa#include <pwd.h> 41194677Sthompsa#ifdef HAVE_LOGIN_H 42194677Sthompsa#include <login.h> 43194677Sthompsa#endif 44194677Sthompsa#ifdef USE_SHADOW 45194677Sthompsa#include <shadow.h> 46194677Sthompsa#endif 47194677Sthompsa#ifdef HAVE_LIBGEN_H 48194677Sthompsa#include <libgen.h> 49194677Sthompsa#endif 50194677Sthompsa#include <stdarg.h> 51194677Sthompsa#include <stdio.h> 52194677Sthompsa#include <string.h> 53194677Sthompsa#include <unistd.h> 54194677Sthompsa 55194677Sthompsa#include "xmalloc.h" 56194677Sthompsa#include "match.h" 57194677Sthompsa#include "groupaccess.h" 58198373Sthompsa#include "log.h" 59194677Sthompsa#include "buffer.h" 60188942Sthompsa#include "servconf.h" 61194677Sthompsa#include "key.h" 62194677Sthompsa#include "hostfile.h" 63188942Sthompsa#include "auth.h" 64194677Sthompsa#include "auth-options.h" 65184610Salfred#include "canohost.h" 66184610Salfred#include "uidswap.h" 67188942Sthompsa#include "misc.h" 68184610Salfred#include "packet.h" 69188942Sthompsa#include "loginrec.h" 70184610Salfred#ifdef GSSAPI 71184610Salfred#include "ssh-gss.h" 72184610Salfred#endif 73184610Salfred#include "authfile.h" 74184610Salfred#include "monitor_wrap.h" 75184610Salfred#include "krl.h" 76207077Sthompsa 77184610Salfred/* import */ 78184610Salfredextern ServerOptions options; 79227309Sedextern int use_privsep; 80192502Sthompsaextern Buffer loginmsg; 81184610Salfredextern struct passwd *privsep_pw; 82184610Salfred 83184610Salfred/* Debugging messages */ 84184610SalfredBuffer auth_debug; 85184610Salfredint auth_debug_init; 86184610Salfred 87184610Salfred/* 88184610Salfred * Check if the user is allowed to log in via ssh. If user is listed 89184610Salfred * in DenyUsers or one of user's groups is listed in DenyGroups, false 90184610Salfred * will be returned. If AllowUsers isn't empty and user isn't listed 91190741Sthompsa * there, or if AllowGroups isn't empty and one of user's groups isn't 92184610Salfred * listed there, false will be returned. 93187259Sthompsa * If the user's shell is not executable, false will be returned. 94187259Sthompsa * Otherwise true is returned. 95188981Sthompsa */ 96187259Sthompsaint 97187259Sthompsaallowed_user(struct passwd * pw) 98190741Sthompsa{ 99184610Salfred struct stat st; 100184610Salfred const char *hostname = NULL, *ipaddr = NULL, *passwd = NULL; 101184610Salfred u_int i; 102184610Salfred#ifdef USE_SHADOW 103184610Salfred struct spwd *spw = NULL; 104184610Salfred#endif 105184610Salfred 106184610Salfred /* Shouldn't be called if pw is NULL, but better safe than sorry... */ 107184610Salfred if (!pw || !pw->pw_name) 108184610Salfred return 0; 109184610Salfred 110184610Salfred#ifdef USE_SHADOW 111184610Salfred if (!options.use_pam) 112188981Sthompsa spw = getspnam(pw->pw_name); 113188981Sthompsa#ifdef HAS_SHADOW_EXPIRE 114184610Salfred if (!options.use_pam && spw != NULL && auth_shadow_acctexpired(spw)) 115189583Sthompsa return 0; 116189583Sthompsa#endif /* HAS_SHADOW_EXPIRE */ 117189583Sthompsa#endif /* USE_SHADOW */ 118189583Sthompsa 119189583Sthompsa /* grab passwd field for locked account check */ 120189583Sthompsa passwd = pw->pw_passwd; 121190741Sthompsa#ifdef USE_SHADOW 122190741Sthompsa if (spw != NULL) 123190741Sthompsa#ifdef USE_LIBIAF 124190741Sthompsa passwd = get_iaf_password(pw); 125192984Sthompsa#else 126190741Sthompsa passwd = spw->sp_pwdp; 127192984Sthompsa#endif /* USE_LIBIAF */ 128190741Sthompsa#endif 129190741Sthompsa 130190741Sthompsa /* check for locked account */ 131190741Sthompsa if (!options.use_pam && passwd && *passwd) { 132190741Sthompsa int locked = 0; 133190741Sthompsa 134192984Sthompsa#ifdef LOCKED_PASSWD_STRING 135190741Sthompsa if (strcmp(passwd, LOCKED_PASSWD_STRING) == 0) 136195959Salfred locked = 1; 137235451Shselasky#endif 138195959Salfred#ifdef LOCKED_PASSWD_PREFIX 139190741Sthompsa if (strncmp(passwd, LOCKED_PASSWD_PREFIX, 140190741Sthompsa strlen(LOCKED_PASSWD_PREFIX)) == 0) 141184610Salfred locked = 1; 142184610Salfred#endif 143184610Salfred#ifdef LOCKED_PASSWD_SUBSTR 144184610Salfred if (strstr(passwd, LOCKED_PASSWD_SUBSTR)) 145184610Salfred locked = 1; 146193045Sthompsa#endif 147184610Salfred#ifdef USE_LIBIAF 148184610Salfred free((void *) passwd); 149184610Salfred#endif /* USE_LIBIAF */ 150184610Salfred if (locked) { 151184610Salfred logit("User %.100s not allowed because account is locked", 152193045Sthompsa pw->pw_name); 153193045Sthompsa return 0; 154193045Sthompsa } 155193045Sthompsa } 156193045Sthompsa 157184610Salfred /* 158198373Sthompsa * Deny if shell does not exist or is not executable unless we 159198373Sthompsa * are chrooting. 160198373Sthompsa */ 161184610Salfred if (options.chroot_directory == NULL || 162192984Sthompsa strcasecmp(options.chroot_directory, "none") == 0) { 163184610Salfred char *shell = xstrdup((pw->pw_shell[0] == '\0') ? 164184610Salfred _PATH_BSHELL : pw->pw_shell); /* empty = /bin/sh */ 165184610Salfred 166184610Salfred if (stat(shell, &st) != 0) { 167184610Salfred logit("User %.100s not allowed because shell %.100s " 168184610Salfred "does not exist", pw->pw_name, shell); 169184610Salfred xfree(shell); 170184610Salfred return 0; 171184610Salfred } 172184610Salfred if (S_ISREG(st.st_mode) == 0 || 173184610Salfred (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) { 174184610Salfred logit("User %.100s not allowed because shell %.100s " 175184610Salfred "is not executable", pw->pw_name, shell); 176184610Salfred xfree(shell); 177184610Salfred return 0; 178184610Salfred } 179184610Salfred xfree(shell); 180184610Salfred } 181184610Salfred 182194677Sthompsa if (options.num_deny_users > 0 || options.num_allow_users > 0 || 183184610Salfred options.num_deny_groups > 0 || options.num_allow_groups > 0) { 184194677Sthompsa hostname = get_canonical_hostname(options.use_dns); 185190741Sthompsa ipaddr = get_remote_ipaddr(); 186194677Sthompsa } 187184610Salfred 188184610Salfred /* Return false if user is listed in DenyUsers */ 189195959Salfred if (options.num_deny_users > 0) { 190190741Sthompsa for (i = 0; i < options.num_deny_users; i++) 191190741Sthompsa if (match_user(pw->pw_name, hostname, ipaddr, 192190741Sthompsa options.deny_users[i])) { 193190741Sthompsa logit("User %.100s from %.100s not allowed " 194190741Sthompsa "because listed in DenyUsers", 195184610Salfred pw->pw_name, hostname); 196189583Sthompsa return 0; 197194677Sthompsa } 198184610Salfred } 199194677Sthompsa /* Return false if AllowUsers isn't empty and user isn't listed there */ 200194677Sthompsa if (options.num_allow_users > 0) { 201184610Salfred for (i = 0; i < options.num_allow_users; i++) 202184610Salfred if (match_user(pw->pw_name, hostname, ipaddr, 203184610Salfred options.allow_users[i])) 204184610Salfred break; 205233774Shselasky /* i < options.num_allow_users iff we break for loop */ 206184610Salfred if (i >= options.num_allow_users) { 207184610Salfred logit("User %.100s from %.100s not allowed because " 208184610Salfred "not listed in AllowUsers", pw->pw_name, hostname); 209184610Salfred return 0; 210188981Sthompsa } 211184610Salfred } 212188981Sthompsa if (options.num_deny_groups > 0 || options.num_allow_groups > 0) { 213194677Sthompsa /* Get the user's group access list (primary and supplementary) */ 214194677Sthompsa if (ga_init(pw->pw_name, pw->pw_gid) == 0) { 215184610Salfred logit("User %.100s from %.100s not allowed because " 216184610Salfred "not in any group", pw->pw_name, hostname); 217184610Salfred return 0; 218184610Salfred } 219184610Salfred 220184610Salfred /* Return false if one of user's groups is listed in DenyGroups */ 221184610Salfred if (options.num_deny_groups > 0) 222184610Salfred if (ga_match(options.deny_groups, 223184610Salfred options.num_deny_groups)) { 224189583Sthompsa ga_free(); 225184610Salfred logit("User %.100s from %.100s not allowed " 226184610Salfred "because a group is listed in DenyGroups", 227184610Salfred pw->pw_name, hostname); 228184610Salfred return 0; 229184610Salfred } 230189583Sthompsa /* 231190741Sthompsa * Return false if AllowGroups isn't empty and one of user's groups 232184610Salfred * isn't listed there 233184610Salfred */ 234184610Salfred if (options.num_allow_groups > 0) 235184610Salfred if (!ga_match(options.allow_groups, 236184610Salfred options.num_allow_groups)) { 237184610Salfred ga_free(); 238190741Sthompsa logit("User %.100s from %.100s not allowed " 239190741Sthompsa "because none of user's groups are listed " 240190741Sthompsa "in AllowGroups", pw->pw_name, hostname); 241190741Sthompsa return 0; 242184610Salfred } 243190741Sthompsa ga_free(); 244190741Sthompsa } 245190741Sthompsa 246184610Salfred#ifdef CUSTOM_SYS_AUTH_ALLOWED_USER 247190741Sthompsa if (!sys_auth_allowed_user(pw, &loginmsg)) 248190741Sthompsa return 0; 249190741Sthompsa#endif 250184610Salfred 251190741Sthompsa /* We found no reason not to let this user try to log on... */ 252190741Sthompsa return 1; 253190741Sthompsa} 254190741Sthompsa 255190741Sthompsavoid 256190741Sthompsaauth_log(Authctxt *authctxt, int authenticated, int partial, 257190741Sthompsa const char *method, const char *submethod, const char *info) 258190741Sthompsa{ 259184610Salfred void (*authlog) (const char *fmt,...) = verbose; 260190741Sthompsa char *authmsg; 261190741Sthompsa 262190741Sthompsa if (use_privsep && !mm_is_monitor() && !authctxt->postponed) 263184610Salfred return; 264190741Sthompsa 265195959Salfred /* Raise logging level */ 266195959Salfred if (authenticated == 1 || 267195959Salfred !authctxt->valid || 268190741Sthompsa authctxt->failures >= options.max_authtries / 2 || 269189583Sthompsa strcmp(method, "password") == 0) 270195959Salfred authlog = logit; 271195959Salfred 272195959Salfred if (authctxt->postponed) 273195959Salfred authmsg = "Postponed"; 274195959Salfred else if (partial) 275184610Salfred authmsg = "Partial"; 276184610Salfred else 277190741Sthompsa authmsg = authenticated ? "Accepted" : "Failed"; 278190741Sthompsa 279190741Sthompsa authlog("%s %s%s%s for %s%.100s from %.200s port %d%s", 280195959Salfred authmsg, 281195959Salfred method, 282195959Salfred submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod, 283184610Salfred authctxt->valid ? "" : "invalid user ", 284184610Salfred authctxt->user, 285184610Salfred get_remote_ipaddr(), 286184610Salfred get_remote_port(), 287184610Salfred info); 288184610Salfred 289208009Sthompsa#ifdef CUSTOM_FAILED_LOGIN 290208009Sthompsa if (authenticated == 0 && !authctxt->postponed && 291208009Sthompsa (strcmp(method, "password") == 0 || 292208009Sthompsa strncmp(method, "keyboard-interactive", 20) == 0 || 293208009Sthompsa strcmp(method, "challenge-response") == 0)) 294208009Sthompsa record_failed_login(authctxt->user, 295184610Salfred get_canonical_hostname(options.use_dns), "ssh"); 296184610Salfred# ifdef WITH_AIXAUTHENTICATE 297184610Salfred if (authenticated) 298184610Salfred sys_auth_record_login(authctxt->user, 299184610Salfred get_canonical_hostname(options.use_dns), "ssh", &loginmsg); 300184610Salfred# endif 301184610Salfred#endif 302184610Salfred#ifdef SSH_AUDIT_EVENTS 303184610Salfred if (authenticated == 0 && !authctxt->postponed) 304184610Salfred audit_event(audit_classify_auth(method)); 305188981Sthompsa#endif 306188981Sthompsa} 307188981Sthompsa 308188981Sthompsa/* 309188981Sthompsa * Check whether root logins are disallowed. 310188981Sthompsa */ 311188981Sthompsaint 312188981Sthompsaauth_root_allowed(const char *method) 313184610Salfred{ 314190741Sthompsa switch (options.permit_root_login) { 315184610Salfred case PERMIT_YES: 316184610Salfred return 1; 317184610Salfred case PERMIT_NO_PASSWD: 318194228Sthompsa if (strcmp(method, "password") != 0) 319184610Salfred return 1; 320184610Salfred break; 321184610Salfred case PERMIT_FORCED_ONLY: 322194228Sthompsa if (forced_command) { 323184610Salfred logit("Root login accepted for forced command."); 324184610Salfred return 1; 325184610Salfred } 326184610Salfred break; 327184610Salfred } 328184610Salfred logit("ROOT LOGIN REFUSED FROM %.200s", get_remote_ipaddr()); 329188981Sthompsa return 0; 330194228Sthompsa} 331188981Sthompsa 332194677Sthompsa 333194228Sthompsa/* 334184610Salfred * Given a template and a passwd structure, build a filename 335188981Sthompsa * by substituting % tokenised options. Currently, %% becomes '%', 336184610Salfred * %h becomes the home directory and %u the username. 337184610Salfred * 338194677Sthompsa * This returns a buffer allocated by xmalloc. 339188981Sthompsa */ 340194677Sthompsachar * 341188981Sthompsaexpand_authorized_keys(const char *filename, struct passwd *pw) 342184610Salfred{ 343188981Sthompsa char *file, ret[MAXPATHLEN]; 344184610Salfred int i; 345184610Salfred 346184610Salfred file = percent_expand(filename, "h", pw->pw_dir, 347192984Sthompsa "u", pw->pw_name, (char *)NULL); 348184610Salfred 349187259Sthompsa /* 350184610Salfred * Ensure that filename starts anchored. If not, be backward 351184610Salfred * compatible and prepend the '%h/' 352184610Salfred */ 353190734Sthompsa if (*file == '/') 354190734Sthompsa return (file); 355190734Sthompsa 356184610Salfred i = snprintf(ret, sizeof(ret), "%s/%s", pw->pw_dir, file); 357184610Salfred if (i < 0 || (size_t)i >= sizeof(ret)) 358184610Salfred fatal("expand_authorized_keys: path too long"); 359223521Shselasky xfree(file); 360223521Shselasky return (xstrdup(ret)); 361223521Shselasky} 362223521Shselasky 363223521Shselaskychar * 364223521Shselaskyauthorized_principals_file(struct passwd *pw) 365223521Shselasky{ 366184610Salfred if (options.authorized_principals_file == NULL || 367184610Salfred strcasecmp(options.authorized_principals_file, "none") == 0) 368184610Salfred return NULL; 369192984Sthompsa return expand_authorized_keys(options.authorized_principals_file, pw); 370184610Salfred} 371245248Shselasky 372184610Salfred/* return ok if key exists in sysfile or userfile */ 373184610SalfredHostStatus 374184610Salfredcheck_key_in_hostfiles(struct passwd *pw, Key *key, const char *host, 375184610Salfred const char *sysfile, const char *userfile) 376192499Sthompsa{ 377184610Salfred char *user_hostfile; 378188981Sthompsa struct stat st; 379194068Sthompsa HostStatus host_status; 380184610Salfred struct hostkeys *hostkeys; 381188981Sthompsa const struct hostkey_entry *found; 382240615Shselasky 383240615Shselasky hostkeys = init_hostkeys(); 384240615Shselasky load_hostkeys(hostkeys, host, sysfile); 385194068Sthompsa if (userfile != NULL) { 386194068Sthompsa user_hostfile = tilde_expand_filename(userfile, pw->pw_uid); 387222051Savg if (options.strict_modes && 388194068Sthompsa (stat(user_hostfile, &st) == 0) && 389194228Sthompsa ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || 390184610Salfred (st.st_mode & 022) != 0)) { 391184610Salfred logit("Authentication refused for %.100s: " 392188981Sthompsa "bad owner or modes for %.200s", 393184610Salfred pw->pw_name, user_hostfile); 394188981Sthompsa auth_debug_add("Ignored %.200s: bad ownership or modes", 395245248Shselasky user_hostfile); 396245248Shselasky } else { 397245248Shselasky temporarily_use_uid(pw); 398245248Shselasky load_hostkeys(hostkeys, host, user_hostfile); 399245248Shselasky restore_uid(); 400184610Salfred } 401245248Shselasky xfree(user_hostfile); 402184610Salfred } 403184610Salfred host_status = check_key_in_hostkeys(hostkeys, key, &found); 404190741Sthompsa if (host_status == HOST_REVOKED) 405190741Sthompsa error("WARNING: revoked key for %s attempted authentication", 406190741Sthompsa found->host); 407184610Salfred else if (host_status == HOST_OK) 408190741Sthompsa debug("%s: key for %s found at %s:%ld", __func__, 409184610Salfred found->host, found->file, found->line); 410184610Salfred else 411212129Sthompsa debug("%s: key for host %s not found", __func__, host); 412184610Salfred 413190741Sthompsa free_hostkeys(hostkeys); 414190741Sthompsa 415184610Salfred return host_status; 416184610Salfred} 417190741Sthompsa 418184610Salfred/* 419184610Salfred * Check a given path for security. This is defined as all components 420190741Sthompsa * of the path to the file must be owned by either the owner of 421190741Sthompsa * of the file or root and no directories must be group or world writable. 422184610Salfred * 423184610Salfred * XXX Should any specific check be done for sym links ? 424190741Sthompsa * 425184610Salfred * Takes a file name, its stat information (preferably from fstat() to 426184610Salfred * avoid races), the uid of the expected owner, their home directory and an 427184610Salfred * error buffer plus max size as arguments. 428190741Sthompsa * 429190741Sthompsa * Returns 0 on success and -1 on failure 430190741Sthompsa */ 431190741Sthompsaint 432190741Sthompsaauth_secure_path(const char *name, struct stat *stp, const char *pw_dir, 433190741Sthompsa uid_t uid, char *err, size_t errlen) 434184610Salfred{ 435190741Sthompsa char buf[MAXPATHLEN], homedir[MAXPATHLEN]; 436184610Salfred char *cp; 437184610Salfred int comparehome = 0; 438184610Salfred struct stat st; 439184610Salfred 440184610Salfred if (realpath(name, buf) == NULL) { 441190741Sthompsa snprintf(err, errlen, "realpath %s failed: %s", name, 442190741Sthompsa strerror(errno)); 443190741Sthompsa return -1; 444184610Salfred } 445184610Salfred if (pw_dir != NULL && realpath(pw_dir, homedir) != NULL) 446190741Sthompsa comparehome = 1; 447184610Salfred 448184610Salfred if (!S_ISREG(stp->st_mode)) { 449190741Sthompsa snprintf(err, errlen, "%s is not a regular file", buf); 450190741Sthompsa return -1; 451190741Sthompsa } 452184610Salfred if ((!platform_sys_dir_uid(stp->st_uid) && stp->st_uid != uid) || 453184610Salfred (stp->st_mode & 022) != 0) { 454190741Sthompsa snprintf(err, errlen, "bad ownership or modes for file %s", 455184610Salfred buf); 456184610Salfred return -1; 457184610Salfred } 458184610Salfred 459184610Salfred /* for each component of the canonical path, walking upwards */ 460184610Salfred for (;;) { 461184610Salfred if ((cp = dirname(buf)) == NULL) { 462184610Salfred snprintf(err, errlen, "dirname() failed"); 463184610Salfred return -1; 464190741Sthompsa } 465190741Sthompsa strlcpy(buf, cp, sizeof(buf)); 466190741Sthompsa 467184610Salfred if (stat(buf, &st) < 0 || 468190741Sthompsa (!platform_sys_dir_uid(st.st_uid) && st.st_uid != uid) || 469184610Salfred (st.st_mode & 022) != 0) { 470184610Salfred snprintf(err, errlen, 471190741Sthompsa "bad ownership or modes for directory %s", buf); 472184610Salfred return -1; 473208009Sthompsa } 474208009Sthompsa 475208009Sthompsa /* If are past the homedir then we can stop */ 476208009Sthompsa if (comparehome && strcmp(homedir, buf) == 0) 477208009Sthompsa break; 478208009Sthompsa 479184610Salfred /* 480184610Salfred * dirname should always complete with a "/" path, 481184610Salfred * but we can be paranoid and check for "." too 482184610Salfred */ 483190741Sthompsa if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0)) 484190741Sthompsa break; 485190741Sthompsa } 486184610Salfred return 0; 487184610Salfred} 488184610Salfred 489212129Sthompsa/* 490212129Sthompsa * Version of secure_path() that accepts an open file descriptor to 491212129Sthompsa * avoid races. 492212132Sthompsa * 493212129Sthompsa * Returns 0 on success and -1 on failure 494212129Sthompsa */ 495212129Sthompsastatic int 496212129Sthompsasecure_filename(FILE *f, const char *file, struct passwd *pw, 497212129Sthompsa char *err, size_t errlen) 498212129Sthompsa{ 499212129Sthompsa struct stat st; 500190741Sthompsa 501184610Salfred /* check the open file to avoid races */ 502190741Sthompsa if (fstat(fileno(f), &st) < 0) { 503190741Sthompsa snprintf(err, errlen, "cannot stat file %s: %s", 504184610Salfred file, strerror(errno)); 505190741Sthompsa return -1; 506190741Sthompsa } 507190741Sthompsa return auth_secure_path(file, &st, pw->pw_dir, pw->pw_uid, err, errlen); 508190741Sthompsa} 509190741Sthompsa 510190741Sthompsastatic FILE * 511190741Sthompsaauth_openfile(const char *file, struct passwd *pw, int strict_modes, 512190741Sthompsa int log_missing, char *file_type) 513190741Sthompsa{ 514190741Sthompsa char line[1024]; 515190741Sthompsa struct stat st; 516190741Sthompsa int fd; 517190741Sthompsa FILE *f; 518190741Sthompsa 519190741Sthompsa if ((fd = open(file, O_RDONLY|O_NONBLOCK)) == -1) { 520190741Sthompsa if (log_missing || errno != ENOENT) 521190741Sthompsa debug("Could not open %s '%s': %s", file_type, file, 522192984Sthompsa strerror(errno)); 523190741Sthompsa return NULL; 524190741Sthompsa } 525190741Sthompsa 526190741Sthompsa if (fstat(fd, &st) < 0) { 527190741Sthompsa close(fd); 528190741Sthompsa return NULL; 529190741Sthompsa } 530207077Sthompsa if (!S_ISREG(st.st_mode)) { 531190741Sthompsa logit("User %s %s %s is not a regular file", 532207077Sthompsa pw->pw_name, file_type, file); 533190741Sthompsa close(fd); 534190741Sthompsa return NULL; 535190741Sthompsa } 536194228Sthompsa unset_nonblock(fd); 537190741Sthompsa if ((f = fdopen(fd, "r")) == NULL) { 538190741Sthompsa close(fd); 539190741Sthompsa return NULL; 540194228Sthompsa } 541190741Sthompsa if (strict_modes && 542190741Sthompsa secure_filename(f, file, pw, line, sizeof(line)) != 0) { 543190741Sthompsa fclose(f); 544190741Sthompsa logit("Authentication refused: %s", line); 545190741Sthompsa auth_debug_add("Ignored %s: %s", file_type, line); 546190741Sthompsa return NULL; 547190741Sthompsa } 548194228Sthompsa 549190741Sthompsa return f; 550190741Sthompsa} 551194228Sthompsa 552190741Sthompsa 553190741SthompsaFILE * 554190741Sthompsaauth_openkeyfile(const char *file, struct passwd *pw, int strict_modes) 555190741Sthompsa{ 556194228Sthompsa return auth_openfile(file, pw, strict_modes, 1, "authorized keys"); 557190741Sthompsa} 558190741Sthompsa 559195959SalfredFILE * 560195959Salfredauth_openprincipals(const char *file, struct passwd *pw, int strict_modes) 561194228Sthompsa{ 562190741Sthompsa return auth_openfile(file, pw, strict_modes, 0, 563190741Sthompsa "authorized principals"); 564190741Sthompsa} 565190741Sthompsa 566190741Sthompsastruct passwd * 567190741Sthompsagetpwnamallow(const char *user) 568190741Sthompsa{ 569189583Sthompsa#ifdef HAVE_LOGIN_CAP 570184610Salfred extern login_cap_t *lc; 571184610Salfred#ifdef BSD_AUTH 572184610Salfred auth_session_t *as; 573184610Salfred#endif 574184610Salfred#endif 575184610Salfred struct passwd *pw; 576184610Salfred struct connection_info *ci = get_connection_info(1, options.use_dns); 577194228Sthompsa 578195959Salfred ci->user = user; 579195959Salfred parse_server_match_config(&options, ci); 580195959Salfred 581190741Sthompsa#if defined(_AIX) && defined(HAVE_SETAUTHDB) 582190741Sthompsa aix_setauthdb(user); 583184610Salfred#endif 584184610Salfred 585184610Salfred pw = getpwnam(user); 586190741Sthompsa 587184610Salfred#if defined(_AIX) && defined(HAVE_SETAUTHDB) 588184610Salfred aix_restoreauthdb(); 589190741Sthompsa#endif 590195959Salfred#ifdef HAVE_CYGWIN 591190741Sthompsa /* 592195959Salfred * Windows usernames are case-insensitive. To avoid later problems 593190741Sthompsa * when trying to match the username, the user is only allowed to 594195959Salfred * login if the username is given in the same case as stored in the 595190741Sthompsa * user database. 596195959Salfred */ 597190741Sthompsa if (pw != NULL && strcmp(user, pw->pw_name) != 0) { 598195959Salfred logit("Login name %.100s does not match stored username %.100s", 599190741Sthompsa user, pw->pw_name); 600195959Salfred pw = NULL; 601188981Sthompsa } 602190741Sthompsa#endif 603190741Sthompsa if (pw == NULL) { 604190741Sthompsa logit("Invalid user %.100s from %.100s", 605190741Sthompsa user, get_remote_ipaddr()); 606190741Sthompsa#ifdef CUSTOM_FAILED_LOGIN 607190741Sthompsa record_failed_login(user, 608190741Sthompsa get_canonical_hostname(options.use_dns), "ssh"); 609190741Sthompsa#endif 610190741Sthompsa#ifdef SSH_AUDIT_EVENTS 611184610Salfred audit_event(SSH_INVALID_USER); 612188981Sthompsa#endif /* SSH_AUDIT_EVENTS */ 613194228Sthompsa return (NULL); 614190741Sthompsa } 615184610Salfred if (!allowed_user(pw)) 616190741Sthompsa return (NULL); 617184610Salfred#ifdef HAVE_LOGIN_CAP 618233774Shselasky if ((lc = login_getpwclass(pw)) == NULL) { 619184610Salfred debug("unable to get login class: %s", user); 620194677Sthompsa return (NULL); 621194677Sthompsa } 622184610Salfred#ifdef BSD_AUTH 623184610Salfred if ((as = auth_open()) == NULL || auth_setpwd(as, pw) != 0 || 624184610Salfred auth_approval(as, lc, pw->pw_name, "ssh") <= 0) { 625184610Salfred debug("Approval failure for %s", user); 626207077Sthompsa pw = NULL; 627190741Sthompsa } 628190741Sthompsa if (as != NULL) 629184610Salfred auth_close(as); 630190741Sthompsa#endif 631190741Sthompsa#endif 632190741Sthompsa if (pw != NULL) 633190741Sthompsa return (pwcopy(pw)); 634190741Sthompsa return (NULL); 635190741Sthompsa} 636190741Sthompsa 637190741Sthompsa/* Returns 1 if key is revoked by revoked_keys_file, 0 otherwise */ 638190741Sthompsaint 639190741Sthompsaauth_key_is_revoked(Key *key) 640190741Sthompsa{ 641190741Sthompsa char *key_fp; 642190741Sthompsa 643190741Sthompsa if (options.revoked_keys_file == NULL) 644190741Sthompsa return 0; 645190741Sthompsa switch (ssh_krl_file_contains_key(options.revoked_keys_file, key)) { 646190741Sthompsa case 0: 647184610Salfred return 0; /* Not revoked */ 648184610Salfred case -2: 649184610Salfred break; /* Not a KRL */ 650184610Salfred default: 651194228Sthompsa goto revoked; 652184610Salfred } 653233774Shselasky debug3("%s: treating %s as a key list", __func__, 654189110Sthompsa options.revoked_keys_file); 655235451Shselasky switch (key_in_file(key, options.revoked_keys_file, 0)) { 656184610Salfred case 0: 657235451Shselasky /* key not revoked */ 658198373Sthompsa return 0; 659198373Sthompsa case -1: 660198373Sthompsa /* Error opening revoked_keys_file: refuse all keys */ 661198373Sthompsa error("Revoked keys file is unreadable: refusing public key " 662219848Shselasky "authentication"); 663198373Sthompsa return 1; 664184610Salfred case 1: 665184610Salfred revoked: 666184610Salfred /* Key revoked */ 667184610Salfred key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); 668184610Salfred error("WARNING: authentication attempt with a revoked " 669184610Salfred "%s key %s ", key_type(key), key_fp); 670184610Salfred xfree(key_fp); 671184610Salfred return 1; 672184610Salfred } 673184610Salfred fatal("key_in_file returned junk"); 674184610Salfred} 675184610Salfred 676184610Salfredvoid 677184610Salfredauth_debug_add(const char *fmt,...) 678184610Salfred{ 679184610Salfred char buf[1024]; 680184610Salfred va_list args; 681194228Sthompsa 682184610Salfred if (!auth_debug_init) 683194228Sthompsa return; 684184610Salfred 685194228Sthompsa va_start(args, fmt); 686184610Salfred vsnprintf(buf, sizeof(buf), fmt, args); 687184610Salfred va_end(args); 688184610Salfred buffer_put_cstring(&auth_debug, buf); 689184610Salfred} 690184610Salfred 691184610Salfredvoid 692184610Salfredauth_debug_send(void) 693192984Sthompsa{ 694184610Salfred char *msg; 695194677Sthompsa 696195959Salfred if (!auth_debug_init) 697184610Salfred return; 698195959Salfred while (buffer_len(&auth_debug)) { 699195959Salfred msg = buffer_get_string(&auth_debug, NULL); 700195959Salfred packet_send_debug("%s", msg); 701195959Salfred xfree(msg); 702195959Salfred } 703195959Salfred} 704195959Salfred 705195959Salfredvoid 706195959Salfredauth_debug_reset(void) 707195959Salfred{ 708195959Salfred if (auth_debug_init) 709195959Salfred buffer_clear(&auth_debug); 710195959Salfred else { 711195959Salfred buffer_init(&auth_debug); 712195959Salfred auth_debug_init = 1; 713195959Salfred } 714194228Sthompsa} 715184610Salfred 716184610Salfredstruct passwd * 717184610Salfredfakepw(void) 718192984Sthompsa{ 719184610Salfred static struct passwd fake; 720194677Sthompsa 721184610Salfred memset(&fake, 0, sizeof(fake)); 722194228Sthompsa fake.pw_name = "NOUSER"; 723194228Sthompsa fake.pw_passwd = 724184610Salfred "$2a$06$r3.juUaHZDlIbQaO2dS9FuYxL1W9M81R1Tc92PoSNmzvpEqLkLGrK"; 725184610Salfred fake.pw_gecos = "NOUSER"; 726184610Salfred fake.pw_uid = privsep_pw == NULL ? (uid_t)-1 : privsep_pw->pw_uid; 727184610Salfred fake.pw_gid = privsep_pw == NULL ? (gid_t)-1 : privsep_pw->pw_gid; 728184610Salfred#ifdef HAVE_PW_CLASS_IN_PASSWD 729184610Salfred fake.pw_class = ""; 730184610Salfred#endif 731184610Salfred fake.pw_dir = "/nonexist"; 732184610Salfred fake.pw_shell = "/nonexist"; 733184610Salfred 734184610Salfred return (&fake); 735184610Salfred} 736184610Salfred