1*79eb0734Srin /* $NetBSD: auth.c,v 1.37 2024/10/09 01:49:20 rin Exp $ */ 29469f4f1Schristos /* $OpenBSD: auth.c,v 1.162 2024/09/15 01:18:26 djm Exp $ */ 31c7715ddSchristos 4ca32bd8dSchristos /* 5ca32bd8dSchristos * Copyright (c) 2000 Markus Friedl. All rights reserved. 6ca32bd8dSchristos * 7ca32bd8dSchristos * Redistribution and use in source and binary forms, with or without 8ca32bd8dSchristos * modification, are permitted provided that the following conditions 9ca32bd8dSchristos * are met: 10ca32bd8dSchristos * 1. Redistributions of source code must retain the above copyright 11ca32bd8dSchristos * notice, this list of conditions and the following disclaimer. 12ca32bd8dSchristos * 2. Redistributions in binary form must reproduce the above copyright 13ca32bd8dSchristos * notice, this list of conditions and the following disclaimer in the 14ca32bd8dSchristos * documentation and/or other materials provided with the distribution. 15ca32bd8dSchristos * 16ca32bd8dSchristos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17ca32bd8dSchristos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18ca32bd8dSchristos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19ca32bd8dSchristos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20ca32bd8dSchristos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21ca32bd8dSchristos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22ca32bd8dSchristos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23ca32bd8dSchristos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24ca32bd8dSchristos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25ca32bd8dSchristos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26ca32bd8dSchristos */ 27ca32bd8dSchristos 28313c6c94Schristos #include "includes.h" 29*79eb0734Srin __RCSID("$NetBSD: auth.c,v 1.37 2024/10/09 01:49:20 rin Exp $"); 30ca32bd8dSchristos #include <sys/types.h> 31ca32bd8dSchristos #include <sys/stat.h> 325101d403Schristos #include <sys/socket.h> 33ffae97bbSchristos #include <sys/wait.h> 34ca32bd8dSchristos 35cd4ada6aSchristos #include <stdlib.h> 36ca32bd8dSchristos #include <errno.h> 37ca32bd8dSchristos #include <fcntl.h> 38ca32bd8dSchristos #include <login_cap.h> 39ca32bd8dSchristos #include <paths.h> 40ca32bd8dSchristos #include <pwd.h> 41ca32bd8dSchristos #include <stdarg.h> 42ca32bd8dSchristos #include <stdio.h> 43ca32bd8dSchristos #include <string.h> 44ca32bd8dSchristos #include <unistd.h> 45e4d43b82Schristos #include <limits.h> 465101d403Schristos #include <netdb.h> 47aa36fcacSchristos #include <time.h> 48ca32bd8dSchristos 49ca32bd8dSchristos #include "xmalloc.h" 50ca32bd8dSchristos #include "match.h" 51ca32bd8dSchristos #include "groupaccess.h" 52ca32bd8dSchristos #include "log.h" 5355a4608bSchristos #include "sshbuf.h" 548a4530f9Schristos #include "misc.h" 55ca32bd8dSchristos #include "servconf.h" 5655a4608bSchristos #include "sshkey.h" 57ca32bd8dSchristos #include "hostfile.h" 58ca32bd8dSchristos #include "auth.h" 59ca32bd8dSchristos #include "auth-options.h" 60ca32bd8dSchristos #include "canohost.h" 61ca32bd8dSchristos #include "uidswap.h" 62ca32bd8dSchristos #include "packet.h" 63ca32bd8dSchristos #ifdef GSSAPI 64ca32bd8dSchristos #include "ssh-gss.h" 65ca32bd8dSchristos #endif 6634b27b53Sadam #include "authfile.h" 67ca32bd8dSchristos #include "monitor_wrap.h" 68e4d43b82Schristos #include "ssherr.h" 69ffae97bbSchristos #include "channels.h" 70068e5a51Schristos #include "pfilter.h" 71ca32bd8dSchristos 72313c6c94Schristos #ifdef HAVE_LOGIN_CAP 73313c6c94Schristos #include <login_cap.h> 74313c6c94Schristos #endif 75313c6c94Schristos 76ca32bd8dSchristos /* import */ 77ca32bd8dSchristos extern ServerOptions options; 78ed75d7a8Schristos extern struct include_list includes; 79ffae97bbSchristos extern struct sshauthopt *auth_opts; 80ca32bd8dSchristos 81ca32bd8dSchristos /* Debugging messages */ 8255a4608bSchristos static struct sshbuf *auth_debug; 83ca32bd8dSchristos 845101d403Schristos #ifndef HOST_ONLY 85ca32bd8dSchristos /* 86ca32bd8dSchristos * Check if the user is allowed to log in via ssh. If user is listed 87ca32bd8dSchristos * in DenyUsers or one of user's groups is listed in DenyGroups, false 88ca32bd8dSchristos * will be returned. If AllowUsers isn't empty and user isn't listed 89ca32bd8dSchristos * there, or if AllowGroups isn't empty and one of user's groups isn't 90ca32bd8dSchristos * listed there, false will be returned. 91ca32bd8dSchristos * If the user's shell is not executable, false will be returned. 92ca32bd8dSchristos * Otherwise true is returned. 93ca32bd8dSchristos */ 94ca32bd8dSchristos int 95aa36fcacSchristos allowed_user(struct ssh *ssh, struct passwd * pw) 96ca32bd8dSchristos { 97313c6c94Schristos #ifdef HAVE_LOGIN_CAP 98313c6c94Schristos extern login_cap_t *lc; 99313c6c94Schristos int match_name, match_ip; 100313c6c94Schristos char *cap_hlist, *hp; 101313c6c94Schristos #endif 102ca32bd8dSchristos struct stat st; 103ca32bd8dSchristos const char *hostname = NULL, *ipaddr = NULL; 104ee85abc4Schristos int r; 105ca32bd8dSchristos u_int i; 106ca32bd8dSchristos 107ca32bd8dSchristos /* Shouldn't be called if pw is NULL, but better safe than sorry... */ 108ca32bd8dSchristos if (!pw || !pw->pw_name) 109ca32bd8dSchristos return 0; 110ca32bd8dSchristos 111313c6c94Schristos #ifdef HAVE_LOGIN_CAP 1125101d403Schristos hostname = auth_get_canonical_hostname(ssh, options.use_dns); 1135101d403Schristos ipaddr = ssh_remote_ipaddr(ssh); 114313c6c94Schristos 115313c6c94Schristos lc = login_getclass(pw->pw_class); 116313c6c94Schristos 117313c6c94Schristos /* 118313c6c94Schristos * Check the deny list. 119313c6c94Schristos */ 120313c6c94Schristos cap_hlist = login_getcapstr(lc, "host.deny", NULL, NULL); 121313c6c94Schristos if (cap_hlist != NULL) { 122313c6c94Schristos hp = strtok(cap_hlist, ","); 123313c6c94Schristos while (hp != NULL) { 1244054ffb0Schristos match_name = match_hostname(hostname, hp); 1254054ffb0Schristos match_ip = match_hostname(ipaddr, hp); 126313c6c94Schristos /* 127313c6c94Schristos * Only a positive match here causes a "deny". 128313c6c94Schristos */ 129313c6c94Schristos if (match_name > 0 || match_ip > 0) { 130313c6c94Schristos free(cap_hlist); 131313c6c94Schristos login_close(lc); 132313c6c94Schristos return 0; 133313c6c94Schristos } 134313c6c94Schristos hp = strtok(NULL, ","); 135313c6c94Schristos } 136313c6c94Schristos free(cap_hlist); 137313c6c94Schristos } 138313c6c94Schristos 139313c6c94Schristos /* 140313c6c94Schristos * Check the allow list. If the allow list exists, and the 141313c6c94Schristos * remote host is not in it, the user is implicitly denied. 142313c6c94Schristos */ 143313c6c94Schristos cap_hlist = login_getcapstr(lc, "host.allow", NULL, NULL); 144313c6c94Schristos if (cap_hlist != NULL) { 145313c6c94Schristos hp = strtok(cap_hlist, ","); 146313c6c94Schristos if (hp == NULL) { 147313c6c94Schristos /* Just in case there's an empty string... */ 148313c6c94Schristos free(cap_hlist); 149313c6c94Schristos login_close(lc); 150313c6c94Schristos return 0; 151313c6c94Schristos } 152313c6c94Schristos while (hp != NULL) { 1534054ffb0Schristos match_name = match_hostname(hostname, hp); 1544054ffb0Schristos match_ip = match_hostname(ipaddr, hp); 155313c6c94Schristos /* 156313c6c94Schristos * Negative match causes an immediate "deny". 157313c6c94Schristos * Positive match causes us to break out 158313c6c94Schristos * of the loop (allowing a fallthrough). 159313c6c94Schristos */ 160313c6c94Schristos if (match_name < 0 || match_ip < 0) { 161313c6c94Schristos free(cap_hlist); 162313c6c94Schristos login_close(lc); 163313c6c94Schristos return 0; 164313c6c94Schristos } 165313c6c94Schristos if (match_name > 0 || match_ip > 0) 166313c6c94Schristos break; 167313c6c94Schristos hp = strtok(NULL, ","); 168313c6c94Schristos } 169313c6c94Schristos free(cap_hlist); 170313c6c94Schristos if (hp == NULL) { 171313c6c94Schristos login_close(lc); 172313c6c94Schristos return 0; 173313c6c94Schristos } 174313c6c94Schristos } 175313c6c94Schristos 176313c6c94Schristos login_close(lc); 177313c6c94Schristos #endif 178313c6c94Schristos 179313c6c94Schristos #ifdef USE_PAM 180313c6c94Schristos if (!options.use_pam) { 181313c6c94Schristos #endif 182313c6c94Schristos /* 183313c6c94Schristos * password/account expiration. 184313c6c94Schristos */ 185313c6c94Schristos if (pw->pw_change || pw->pw_expire) { 186313c6c94Schristos struct timeval tv; 187313c6c94Schristos 188313c6c94Schristos (void)gettimeofday(&tv, (struct timezone *)NULL); 189313c6c94Schristos if (pw->pw_expire) { 190313c6c94Schristos if (tv.tv_sec >= pw->pw_expire) { 191313c6c94Schristos logit("User %.100s not allowed because account has expired", 192313c6c94Schristos pw->pw_name); 193313c6c94Schristos return 0; /* expired */ 194313c6c94Schristos } 195313c6c94Schristos } 196313c6c94Schristos #ifdef _PASSWORD_CHGNOW 197313c6c94Schristos if (pw->pw_change == _PASSWORD_CHGNOW) { 198313c6c94Schristos logit("User %.100s not allowed because password needs to be changed", 199313c6c94Schristos pw->pw_name); 200313c6c94Schristos 201313c6c94Schristos return 0; /* can't force password change (yet) */ 202313c6c94Schristos } 203313c6c94Schristos #endif 204313c6c94Schristos if (pw->pw_change) { 205313c6c94Schristos if (tv.tv_sec >= pw->pw_change) { 206313c6c94Schristos logit("User %.100s not allowed because password has expired", 207313c6c94Schristos pw->pw_name); 208313c6c94Schristos return 0; /* expired */ 209313c6c94Schristos } 210313c6c94Schristos } 211313c6c94Schristos } 212313c6c94Schristos #ifdef USE_PAM 213313c6c94Schristos } 214313c6c94Schristos #endif 215313c6c94Schristos 216ca32bd8dSchristos /* 21734b27b53Sadam * Deny if shell does not exist or is not executable unless we 21834b27b53Sadam * are chrooting. 219ca32bd8dSchristos */ 220313c6c94Schristos /* 221313c6c94Schristos * XXX Should check to see if it is executable by the 222313c6c94Schristos * XXX requesting user. --thorpej 223313c6c94Schristos */ 22434b27b53Sadam if (options.chroot_directory == NULL || 22534b27b53Sadam strcasecmp(options.chroot_directory, "none") == 0) { 22634b27b53Sadam char *shell = xstrdup((pw->pw_shell[0] == '\0') ? 22734b27b53Sadam _PATH_BSHELL : pw->pw_shell); /* empty = /bin/sh */ 22834b27b53Sadam 229cd4ada6aSchristos if (stat(shell, &st) == -1) { 23034b27b53Sadam logit("User %.100s not allowed because shell %.100s " 23134b27b53Sadam "does not exist", pw->pw_name, shell); 23200a838c4Schristos free(shell); 233ca32bd8dSchristos return 0; 234ca32bd8dSchristos } 235ca32bd8dSchristos if (S_ISREG(st.st_mode) == 0 || 236ca32bd8dSchristos (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) { 23734b27b53Sadam logit("User %.100s not allowed because shell %.100s " 23834b27b53Sadam "is not executable", pw->pw_name, shell); 23900a838c4Schristos free(shell); 240ca32bd8dSchristos return 0; 241ca32bd8dSchristos } 24200a838c4Schristos free(shell); 24334b27b53Sadam } 244313c6c94Schristos /* 245313c6c94Schristos * XXX Consider nuking {Allow,Deny}{Users,Groups}. We have the 246313c6c94Schristos * XXX login_cap(3) mechanism which covers all other types of 247313c6c94Schristos * XXX logins, too. 248313c6c94Schristos */ 249ca32bd8dSchristos 250ca32bd8dSchristos if (options.num_deny_users > 0 || options.num_allow_users > 0 || 251ca32bd8dSchristos options.num_deny_groups > 0 || options.num_allow_groups > 0) { 2525101d403Schristos hostname = auth_get_canonical_hostname(ssh, options.use_dns); 2535101d403Schristos ipaddr = ssh_remote_ipaddr(ssh); 254ca32bd8dSchristos } 255ca32bd8dSchristos 256ca32bd8dSchristos /* Return false if user is listed in DenyUsers */ 257ca32bd8dSchristos if (options.num_deny_users > 0) { 258ee85abc4Schristos for (i = 0; i < options.num_deny_users; i++) { 259ee85abc4Schristos r = match_user(pw->pw_name, hostname, ipaddr, 260ee85abc4Schristos options.deny_users[i]); 261ee85abc4Schristos if (r < 0) { 262ee85abc4Schristos fatal("Invalid DenyUsers pattern \"%.100s\"", 263ee85abc4Schristos options.deny_users[i]); 264ee85abc4Schristos } else if (r != 0) { 265ca32bd8dSchristos logit("User %.100s from %.100s not allowed " 266ca32bd8dSchristos "because listed in DenyUsers", 267ca32bd8dSchristos pw->pw_name, hostname); 268ca32bd8dSchristos return 0; 269ca32bd8dSchristos } 270ca32bd8dSchristos } 271ee85abc4Schristos } 272ca32bd8dSchristos /* Return false if AllowUsers isn't empty and user isn't listed there */ 273ca32bd8dSchristos if (options.num_allow_users > 0) { 274ee85abc4Schristos for (i = 0; i < options.num_allow_users; i++) { 275ee85abc4Schristos r = match_user(pw->pw_name, hostname, ipaddr, 276ee85abc4Schristos options.allow_users[i]); 277ee85abc4Schristos if (r < 0) { 278ee85abc4Schristos fatal("Invalid AllowUsers pattern \"%.100s\"", 279ee85abc4Schristos options.allow_users[i]); 280ee85abc4Schristos } else if (r == 1) 281ca32bd8dSchristos break; 282ee85abc4Schristos } 283ca32bd8dSchristos /* i < options.num_allow_users iff we break for loop */ 284ca32bd8dSchristos if (i >= options.num_allow_users) { 285ca32bd8dSchristos logit("User %.100s from %.100s not allowed because " 286ca32bd8dSchristos "not listed in AllowUsers", pw->pw_name, hostname); 287ca32bd8dSchristos return 0; 288ca32bd8dSchristos } 289ca32bd8dSchristos } 290ca32bd8dSchristos if (options.num_deny_groups > 0 || options.num_allow_groups > 0) { 291ca32bd8dSchristos /* Get the user's group access list (primary and supplementary) */ 292ca32bd8dSchristos if (ga_init(pw->pw_name, pw->pw_gid) == 0) { 293ca32bd8dSchristos logit("User %.100s from %.100s not allowed because " 294ca32bd8dSchristos "not in any group", pw->pw_name, hostname); 295ca32bd8dSchristos return 0; 296ca32bd8dSchristos } 297ca32bd8dSchristos 298ca32bd8dSchristos /* Return false if one of user's groups is listed in DenyGroups */ 299ca32bd8dSchristos if (options.num_deny_groups > 0) 300ca32bd8dSchristos if (ga_match(options.deny_groups, 301ca32bd8dSchristos options.num_deny_groups)) { 302ca32bd8dSchristos ga_free(); 303ca32bd8dSchristos logit("User %.100s from %.100s not allowed " 304ca32bd8dSchristos "because a group is listed in DenyGroups", 305ca32bd8dSchristos pw->pw_name, hostname); 306ca32bd8dSchristos return 0; 307ca32bd8dSchristos } 308ca32bd8dSchristos /* 309ca32bd8dSchristos * Return false if AllowGroups isn't empty and one of user's groups 310ca32bd8dSchristos * isn't listed there 311ca32bd8dSchristos */ 312ca32bd8dSchristos if (options.num_allow_groups > 0) 313ca32bd8dSchristos if (!ga_match(options.allow_groups, 314ca32bd8dSchristos options.num_allow_groups)) { 315ca32bd8dSchristos ga_free(); 316ca32bd8dSchristos logit("User %.100s from %.100s not allowed " 317ca32bd8dSchristos "because none of user's groups are listed " 318ca32bd8dSchristos "in AllowGroups", pw->pw_name, hostname); 319ca32bd8dSchristos return 0; 320ca32bd8dSchristos } 321ca32bd8dSchristos ga_free(); 322ca32bd8dSchristos } 323ca32bd8dSchristos /* We found no reason not to let this user try to log on... */ 324ca32bd8dSchristos return 1; 325ca32bd8dSchristos } 326ca32bd8dSchristos 3277a183406Schristos /* 3287a183406Schristos * Formats any key left in authctxt->auth_method_key for inclusion in 3297a183406Schristos * auth_log()'s message. Also includes authxtct->auth_method_info if present. 3307a183406Schristos */ 3317a183406Schristos static char * 3327a183406Schristos format_method_key(Authctxt *authctxt) 33300a838c4Schristos { 3347a183406Schristos const struct sshkey *key = authctxt->auth_method_key; 3357a183406Schristos const char *methinfo = authctxt->auth_method_info; 336aa36fcacSchristos char *fp, *cafp, *ret = NULL; 33700a838c4Schristos 3387a183406Schristos if (key == NULL) 3397a183406Schristos return NULL; 34000a838c4Schristos 34155a4608bSchristos if (sshkey_is_cert(key)) { 342aa36fcacSchristos fp = sshkey_fingerprint(key, 3437a183406Schristos options.fingerprint_hash, SSH_FP_DEFAULT); 344aa36fcacSchristos cafp = sshkey_fingerprint(key->cert->signature_key, 345aa36fcacSchristos options.fingerprint_hash, SSH_FP_DEFAULT); 346aa36fcacSchristos xasprintf(&ret, "%s %s ID %s (serial %llu) CA %s %s%s%s", 347aa36fcacSchristos sshkey_type(key), fp == NULL ? "(null)" : fp, 348aa36fcacSchristos key->cert->key_id, 3497a183406Schristos (unsigned long long)key->cert->serial, 3507a183406Schristos sshkey_type(key->cert->signature_key), 351aa36fcacSchristos cafp == NULL ? "(null)" : cafp, 3527a183406Schristos methinfo == NULL ? "" : ", ", 3537a183406Schristos methinfo == NULL ? "" : methinfo); 3547a183406Schristos free(fp); 355aa36fcacSchristos free(cafp); 3567a183406Schristos } else { 3577a183406Schristos fp = sshkey_fingerprint(key, options.fingerprint_hash, 3587a183406Schristos SSH_FP_DEFAULT); 3597a183406Schristos xasprintf(&ret, "%s %s%s%s", sshkey_type(key), 3607a183406Schristos fp == NULL ? "(null)" : fp, 3617a183406Schristos methinfo == NULL ? "" : ", ", 3627a183406Schristos methinfo == NULL ? "" : methinfo); 3637a183406Schristos free(fp); 3647a183406Schristos } 3657a183406Schristos return ret; 36600a838c4Schristos } 36700a838c4Schristos 36800a838c4Schristos void 369aa36fcacSchristos auth_log(struct ssh *ssh, int authenticated, int partial, 37000a838c4Schristos const char *method, const char *submethod) 371ca32bd8dSchristos { 372aa36fcacSchristos Authctxt *authctxt = (Authctxt *)ssh->authctxt; 373aa36fcacSchristos int level = SYSLOG_LEVEL_VERBOSE; 374185c8f97Schristos const char *authmsg; 3757a183406Schristos char *extra = NULL; 376ca32bd8dSchristos 3771c7715ddSchristos if (!mm_is_monitor() && !authctxt->postponed) 378ca32bd8dSchristos return; 379ca32bd8dSchristos 380ca32bd8dSchristos /* Raise logging level */ 381ca32bd8dSchristos if (authenticated == 1 || 382ca32bd8dSchristos !authctxt->valid || 383ca32bd8dSchristos authctxt->failures >= options.max_authtries / 2 || 384ca32bd8dSchristos strcmp(method, "password") == 0) 385aa36fcacSchristos level = SYSLOG_LEVEL_INFO; 386ca32bd8dSchristos 387ca32bd8dSchristos if (authctxt->postponed) 388ca32bd8dSchristos authmsg = "Postponed"; 389ce11a51fSchristos else if (partial) 390ce11a51fSchristos authmsg = "Partial"; 391ca32bd8dSchristos else 392ca32bd8dSchristos authmsg = authenticated ? "Accepted" : "Failed"; 393ca32bd8dSchristos 3947a183406Schristos if ((extra = format_method_key(authctxt)) == NULL) { 3957a183406Schristos if (authctxt->auth_method_info != NULL) 3967a183406Schristos extra = xstrdup(authctxt->auth_method_info); 3977a183406Schristos } 3987a183406Schristos 399aa36fcacSchristos do_log2(level, "%s %s%s%s for %s%.100s from %.200s port %d ssh2%s%s", 400ca32bd8dSchristos authmsg, 401ca32bd8dSchristos method, 402ce11a51fSchristos submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod, 403ca32bd8dSchristos authctxt->valid ? "" : "invalid user ", 404ca32bd8dSchristos authctxt->user, 4055101d403Schristos ssh_remote_ipaddr(ssh), 4065101d403Schristos ssh_remote_port(ssh), 4077a183406Schristos extra != NULL ? ": " : "", 4087a183406Schristos extra != NULL ? extra : ""); 4097a183406Schristos 4107a183406Schristos free(extra); 411ca32bd8dSchristos } 412ca32bd8dSchristos 4138a4530f9Schristos void 414aa36fcacSchristos auth_maxtries_exceeded(struct ssh *ssh) 4158a4530f9Schristos { 416aa36fcacSchristos Authctxt *authctxt = (Authctxt *)ssh->authctxt; 4175101d403Schristos 418*79eb0734Srin pfilter_notify(1); 419e4d43b82Schristos error("maximum authentication attempts exceeded for " 420ee85abc4Schristos "%s%.100s from %.200s port %d ssh2", 4218a4530f9Schristos authctxt->valid ? "" : "invalid user ", 4228a4530f9Schristos authctxt->user, 4235101d403Schristos ssh_remote_ipaddr(ssh), 424ee85abc4Schristos ssh_remote_port(ssh)); 425aa36fcacSchristos ssh_packet_disconnect(ssh, "Too many authentication failures"); 4268a4530f9Schristos /* NOTREACHED */ 4278a4530f9Schristos } 4288a4530f9Schristos 429ca32bd8dSchristos /* 430ca32bd8dSchristos * Check whether root logins are disallowed. 431ca32bd8dSchristos */ 432ca32bd8dSchristos int 433ffae97bbSchristos auth_root_allowed(struct ssh *ssh, const char *method) 434ca32bd8dSchristos { 435ca32bd8dSchristos switch (options.permit_root_login) { 436ca32bd8dSchristos case PERMIT_YES: 437ca32bd8dSchristos return 1; 438ca32bd8dSchristos case PERMIT_NO_PASSWD: 4398395c133Schristos if (strcmp(method, "publickey") == 0 || 4408395c133Schristos strcmp(method, "hostbased") == 0 || 441b1c8f1c6Schristos strcmp(method, "gssapi-with-mic") == 0) 442ca32bd8dSchristos return 1; 443ca32bd8dSchristos break; 444ca32bd8dSchristos case PERMIT_FORCED_ONLY: 445ffae97bbSchristos if (auth_opts->force_command != NULL) { 446ca32bd8dSchristos logit("Root login accepted for forced command."); 447ca32bd8dSchristos return 1; 448ca32bd8dSchristos } 449ca32bd8dSchristos break; 450ca32bd8dSchristos } 4515101d403Schristos logit("ROOT LOGIN REFUSED FROM %.200s port %d", 4525101d403Schristos ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); 453ca32bd8dSchristos return 0; 454ca32bd8dSchristos } 455ca32bd8dSchristos 456ca32bd8dSchristos 457ca32bd8dSchristos /* 458ca32bd8dSchristos * Given a template and a passwd structure, build a filename 459ca32bd8dSchristos * by substituting % tokenised options. Currently, %% becomes '%', 460ca32bd8dSchristos * %h becomes the home directory and %u the username. 461ca32bd8dSchristos * 462ca32bd8dSchristos * This returns a buffer allocated by xmalloc. 463ca32bd8dSchristos */ 4646f47b660Schristos char * 465ca32bd8dSchristos expand_authorized_keys(const char *filename, struct passwd *pw) 466ca32bd8dSchristos { 46755a4608bSchristos char *file, uidstr[32], ret[PATH_MAX]; 468ca32bd8dSchristos int i; 469ca32bd8dSchristos 47055a4608bSchristos snprintf(uidstr, sizeof(uidstr), "%llu", 47155a4608bSchristos (unsigned long long)pw->pw_uid); 472ca32bd8dSchristos file = percent_expand(filename, "h", pw->pw_dir, 47355a4608bSchristos "u", pw->pw_name, "U", uidstr, (char *)NULL); 474ca32bd8dSchristos 475ca32bd8dSchristos /* 476ca32bd8dSchristos * Ensure that filename starts anchored. If not, be backward 477ca32bd8dSchristos * compatible and prepend the '%h/' 478ca32bd8dSchristos */ 479aa36fcacSchristos if (path_absolute(file)) 480ca32bd8dSchristos return (file); 481ca32bd8dSchristos 482ca32bd8dSchristos i = snprintf(ret, sizeof(ret), "%s/%s", pw->pw_dir, file); 483ca32bd8dSchristos if (i < 0 || (size_t)i >= sizeof(ret)) 484ca32bd8dSchristos fatal("expand_authorized_keys: path too long"); 48500a838c4Schristos free(file); 486ca32bd8dSchristos return (xstrdup(ret)); 487ca32bd8dSchristos } 488ca32bd8dSchristos 489ca32bd8dSchristos char * 49034b27b53Sadam authorized_principals_file(struct passwd *pw) 49134b27b53Sadam { 4924054ffb0Schristos if (options.authorized_principals_file == NULL) 49334b27b53Sadam return NULL; 49434b27b53Sadam return expand_authorized_keys(options.authorized_principals_file, pw); 49534b27b53Sadam } 49634b27b53Sadam 497ca32bd8dSchristos /* return ok if key exists in sysfile or userfile */ 498ca32bd8dSchristos HostStatus 4997a183406Schristos check_key_in_hostfiles(struct passwd *pw, struct sshkey *key, const char *host, 500ca32bd8dSchristos const char *sysfile, const char *userfile) 501ca32bd8dSchristos { 502ca32bd8dSchristos char *user_hostfile; 503ca32bd8dSchristos struct stat st; 504ca32bd8dSchristos HostStatus host_status; 505185c8f97Schristos struct hostkeys *hostkeys; 506185c8f97Schristos const struct hostkey_entry *found; 507ca32bd8dSchristos 508185c8f97Schristos hostkeys = init_hostkeys(); 50917418e98Schristos load_hostkeys(hostkeys, host, sysfile, 0); 510185c8f97Schristos if (userfile != NULL) { 511ca32bd8dSchristos user_hostfile = tilde_expand_filename(userfile, pw->pw_uid); 512ca32bd8dSchristos if (options.strict_modes && 513ca32bd8dSchristos (stat(user_hostfile, &st) == 0) && 514ca32bd8dSchristos ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || 515ca32bd8dSchristos (st.st_mode & 022) != 0)) { 516ca32bd8dSchristos logit("Authentication refused for %.100s: " 517ca32bd8dSchristos "bad owner or modes for %.200s", 518ca32bd8dSchristos pw->pw_name, user_hostfile); 51934b27b53Sadam auth_debug_add("Ignored %.200s: bad ownership or modes", 52034b27b53Sadam user_hostfile); 521ca32bd8dSchristos } else { 522ca32bd8dSchristos temporarily_use_uid(pw); 52317418e98Schristos load_hostkeys(hostkeys, host, user_hostfile, 0); 524ca32bd8dSchristos restore_uid(); 525ca32bd8dSchristos } 52600a838c4Schristos free(user_hostfile); 527ca32bd8dSchristos } 528185c8f97Schristos host_status = check_key_in_hostkeys(hostkeys, key, &found); 529185c8f97Schristos if (host_status == HOST_REVOKED) 530185c8f97Schristos error("WARNING: revoked key for %s attempted authentication", 531ed75d7a8Schristos host); 532185c8f97Schristos else if (host_status == HOST_OK) 53317418e98Schristos debug_f("key for %s found at %s:%ld", 534185c8f97Schristos found->host, found->file, found->line); 535185c8f97Schristos else 53617418e98Schristos debug_f("key for host %s not found", host); 537ca32bd8dSchristos 538185c8f97Schristos free_hostkeys(hostkeys); 539185c8f97Schristos 540ca32bd8dSchristos return host_status; 541ca32bd8dSchristos } 542ca32bd8dSchristos 543ca32bd8dSchristos struct passwd * 544aa36fcacSchristos getpwnamallow(struct ssh *ssh, const char *user) 545ca32bd8dSchristos { 546313c6c94Schristos #ifdef HAVE_LOGIN_CAP 547ca32bd8dSchristos extern login_cap_t *lc; 548313c6c94Schristos #ifdef BSD_AUTH 549ca32bd8dSchristos auth_session_t *as; 550313c6c94Schristos #endif 551313c6c94Schristos #endif 552ca32bd8dSchristos struct passwd *pw; 553aa36fcacSchristos struct connection_info *ci; 55417418e98Schristos u_int i; 555ca32bd8dSchristos 5561c7715ddSchristos ci = server_get_connection_info(ssh, 1, options.use_dns); 5572649c700Schristos ci->user = user; 5589469f4f1Schristos ci->user_invalid = getpwnam(user) == NULL; 559ed75d7a8Schristos parse_server_match_config(&options, &includes, ci); 5607a183406Schristos log_change_level(options.log_level); 56117418e98Schristos log_verbose_reset(); 56217418e98Schristos for (i = 0; i < options.num_log_verbose; i++) 56317418e98Schristos log_verbose_add(options.log_verbose[i]); 5641c7715ddSchristos server_process_permitopen(ssh); 565ca32bd8dSchristos 566ca32bd8dSchristos pw = getpwnam(user); 567ca32bd8dSchristos if (pw == NULL) { 5681d2e8f99Schristos pfilter_notify(1); 5695101d403Schristos logit("Invalid user %.100s from %.100s port %d", 5705101d403Schristos user, ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); 571ca32bd8dSchristos return (NULL); 572ca32bd8dSchristos } 573aa36fcacSchristos if (!allowed_user(ssh, pw)) 574ca32bd8dSchristos return (NULL); 575313c6c94Schristos #ifdef HAVE_LOGIN_CAP 576ca32bd8dSchristos if ((lc = login_getclass(pw->pw_class)) == NULL) { 577ca32bd8dSchristos debug("unable to get login class: %s", user); 578ca32bd8dSchristos return (NULL); 579ca32bd8dSchristos } 580313c6c94Schristos #ifdef BSD_AUTH 581ca32bd8dSchristos if ((as = auth_open()) == NULL || auth_setpwd(as, pw) != 0 || 582ca32bd8dSchristos auth_approval(as, lc, pw->pw_name, "ssh") <= 0) { 583ca32bd8dSchristos debug("Approval failure for %s", user); 584ca32bd8dSchristos pw = NULL; 585ca32bd8dSchristos } 586ca32bd8dSchristos if (as != NULL) 587ca32bd8dSchristos auth_close(as); 588313c6c94Schristos #endif 589313c6c94Schristos #endif 590ca32bd8dSchristos if (pw != NULL) 591ca32bd8dSchristos return (pwcopy(pw)); 592ca32bd8dSchristos return (NULL); 593ca32bd8dSchristos } 594ca32bd8dSchristos 59534b27b53Sadam /* Returns 1 if key is revoked by revoked_keys_file, 0 otherwise */ 59634b27b53Sadam int 5977a183406Schristos auth_key_is_revoked(struct sshkey *key) 59834b27b53Sadam { 599e4d43b82Schristos char *fp = NULL; 600e4d43b82Schristos int r; 60134b27b53Sadam 60234b27b53Sadam if (options.revoked_keys_file == NULL) 60334b27b53Sadam return 0; 604e4d43b82Schristos if ((fp = sshkey_fingerprint(key, options.fingerprint_hash, 605e4d43b82Schristos SSH_FP_DEFAULT)) == NULL) { 606e4d43b82Schristos r = SSH_ERR_ALLOC_FAIL; 60717418e98Schristos error_fr(r, "fingerprint key"); 608e4d43b82Schristos goto out; 609e4d43b82Schristos } 610e4d43b82Schristos 611e4d43b82Schristos r = sshkey_check_revoked(key, options.revoked_keys_file); 612e4d43b82Schristos switch (r) { 613ce11a51fSchristos case 0: 614e4d43b82Schristos break; /* not revoked */ 615e4d43b82Schristos case SSH_ERR_KEY_REVOKED: 616e4d43b82Schristos error("Authentication key %s %s revoked by file %s", 617e4d43b82Schristos sshkey_type(key), fp, options.revoked_keys_file); 618e4d43b82Schristos goto out; 619ce11a51fSchristos default: 62017418e98Schristos error_r(r, "Error checking authentication key %s %s in " 62117418e98Schristos "revoked keys file %s", sshkey_type(key), fp, 62217418e98Schristos options.revoked_keys_file); 623e4d43b82Schristos goto out; 624ce11a51fSchristos } 625e4d43b82Schristos 626e4d43b82Schristos /* Success */ 627e4d43b82Schristos r = 0; 628e4d43b82Schristos 629e4d43b82Schristos out: 630e4d43b82Schristos free(fp); 631e4d43b82Schristos return r == 0 ? 0 : 1; 63234b27b53Sadam } 633ffae97bbSchristos #endif 63434b27b53Sadam 635ca32bd8dSchristos void 636ca32bd8dSchristos auth_debug_add(const char *fmt,...) 637ca32bd8dSchristos { 638ca32bd8dSchristos char buf[1024]; 639ca32bd8dSchristos va_list args; 64055a4608bSchristos int r; 641ca32bd8dSchristos 642ca32bd8dSchristos va_start(args, fmt); 643ca32bd8dSchristos vsnprintf(buf, sizeof(buf), fmt, args); 644ca32bd8dSchristos va_end(args); 645b1066cf3Schristos debug3("%s", buf); 646b1066cf3Schristos if (auth_debug != NULL) 64755a4608bSchristos if ((r = sshbuf_put_cstring(auth_debug, buf)) != 0) 64817418e98Schristos fatal_fr(r, "sshbuf_put_cstring"); 649ca32bd8dSchristos } 650ca32bd8dSchristos 651ca32bd8dSchristos void 652aa36fcacSchristos auth_debug_send(struct ssh *ssh) 653ca32bd8dSchristos { 654ca32bd8dSchristos char *msg; 65555a4608bSchristos int r; 656ca32bd8dSchristos 65755a4608bSchristos if (auth_debug == NULL) 658ca32bd8dSchristos return; 65955a4608bSchristos while (sshbuf_len(auth_debug) != 0) { 66055a4608bSchristos if ((r = sshbuf_get_cstring(auth_debug, &msg, NULL)) != 0) 66117418e98Schristos fatal_fr(r, "sshbuf_get_cstring"); 66255a4608bSchristos ssh_packet_send_debug(ssh, "%s", msg); 66300a838c4Schristos free(msg); 664ca32bd8dSchristos } 665ca32bd8dSchristos } 666ca32bd8dSchristos 667ca32bd8dSchristos void 668ca32bd8dSchristos auth_debug_reset(void) 669ca32bd8dSchristos { 67055a4608bSchristos if (auth_debug != NULL) 67155a4608bSchristos sshbuf_reset(auth_debug); 67255a4608bSchristos else if ((auth_debug = sshbuf_new()) == NULL) 67317418e98Schristos fatal_f("sshbuf_new failed"); 674ca32bd8dSchristos } 675ca32bd8dSchristos 676ca32bd8dSchristos struct passwd * 677ca32bd8dSchristos fakepw(void) 678ca32bd8dSchristos { 679a03ec00cSchristos static int done = 0; 680ca32bd8dSchristos static struct passwd fake; 681a03ec00cSchristos const char hashchars[] = "./ABCDEFGHIJKLMNOPQRSTUVWXYZ" 682a03ec00cSchristos "abcdefghijklmnopqrstuvwxyz0123456789"; /* from bcrypt.c */ 683a03ec00cSchristos char *cp; 684a03ec00cSchristos 685a03ec00cSchristos if (done) 686a03ec00cSchristos return (&fake); 687ca32bd8dSchristos 688ca32bd8dSchristos memset(&fake, 0, sizeof(fake)); 689a03ec00cSchristos fake.pw_name = __UNCONST("NOUSER"); 690a03ec00cSchristos fake.pw_passwd = xstrdup("$2a$10$" 691a03ec00cSchristos "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); 692a03ec00cSchristos for (cp = fake.pw_passwd + 7; *cp != '\0'; cp++) 693a03ec00cSchristos *cp = hashchars[arc4random_uniform(sizeof(hashchars) - 1)]; 694a03ec00cSchristos fake.pw_gecos = __UNCONST("NOUSER"); 695ca32bd8dSchristos fake.pw_uid = (uid_t)-1; 696ca32bd8dSchristos fake.pw_gid = (gid_t)-1; 697185c8f97Schristos fake.pw_class = __UNCONST(""); 698a03ec00cSchristos fake.pw_dir = __UNCONST("/nonexist"); 699a03ec00cSchristos fake.pw_shell = __UNCONST("/nonexist"); 700a03ec00cSchristos done = 1; 701ca32bd8dSchristos 702ca32bd8dSchristos return (&fake); 703ca32bd8dSchristos } 7045101d403Schristos 7055101d403Schristos /* 7065101d403Schristos * Return the canonical name of the host in the other side of the current 7075101d403Schristos * connection. The host name is cached, so it is efficient to call this 7085101d403Schristos * several times. 7095101d403Schristos */ 7105101d403Schristos 7115101d403Schristos const char * 7125101d403Schristos auth_get_canonical_hostname(struct ssh *ssh, int use_dns) 7135101d403Schristos { 7145101d403Schristos static char *dnsname; 7155101d403Schristos 7165101d403Schristos if (!use_dns) 7175101d403Schristos return ssh_remote_ipaddr(ssh); 7181c7715ddSchristos if (dnsname != NULL) 7195101d403Schristos return dnsname; 7201c7715ddSchristos dnsname = ssh_remote_hostname(ssh); 7215101d403Schristos return dnsname; 7225101d403Schristos } 723ffae97bbSchristos 724ffae97bbSchristos /* These functions link key/cert options to the auth framework */ 725ffae97bbSchristos 726ffae97bbSchristos /* Log sshauthopt options locally and (optionally) for remote transmission */ 727ffae97bbSchristos void 728ffae97bbSchristos auth_log_authopts(const char *loc, const struct sshauthopt *opts, int do_remote) 729ffae97bbSchristos { 730ffae97bbSchristos int do_env = options.permit_user_env && opts->nenv > 0; 731ffae97bbSchristos int do_permitopen = opts->npermitopen > 0 && 732ffae97bbSchristos (options.allow_tcp_forwarding & FORWARD_LOCAL) != 0; 73355a4608bSchristos int do_permitlisten = opts->npermitlisten > 0 && 73455a4608bSchristos (options.allow_tcp_forwarding & FORWARD_REMOTE) != 0; 735ffae97bbSchristos size_t i; 736ffae97bbSchristos char msg[1024], buf[64]; 737ffae97bbSchristos 738ffae97bbSchristos snprintf(buf, sizeof(buf), "%d", opts->force_tun_device); 739ffae97bbSchristos /* Try to keep this alphabetically sorted */ 7402d3b0f52Schristos snprintf(msg, sizeof(msg), "key options:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", 741ffae97bbSchristos opts->permit_agent_forwarding_flag ? " agent-forwarding" : "", 742ffae97bbSchristos opts->force_command == NULL ? "" : " command", 743ffae97bbSchristos do_env ? " environment" : "", 744ffae97bbSchristos opts->valid_before == 0 ? "" : "expires", 7452d3b0f52Schristos opts->no_require_user_presence ? " no-touch-required" : "", 746ffae97bbSchristos do_permitopen ? " permitopen" : "", 74755a4608bSchristos do_permitlisten ? " permitlisten" : "", 748ffae97bbSchristos opts->permit_port_forwarding_flag ? " port-forwarding" : "", 749ffae97bbSchristos opts->cert_principals == NULL ? "" : " principals", 750ffae97bbSchristos opts->permit_pty_flag ? " pty" : "", 7512d3b0f52Schristos opts->require_verify ? " uv" : "", 752ffae97bbSchristos opts->force_tun_device == -1 ? "" : " tun=", 753ffae97bbSchristos opts->force_tun_device == -1 ? "" : buf, 754ffae97bbSchristos opts->permit_user_rc ? " user-rc" : "", 7552d3b0f52Schristos opts->permit_x11_forwarding_flag ? " x11-forwarding" : ""); 756ffae97bbSchristos 757ffae97bbSchristos debug("%s: %s", loc, msg); 758ffae97bbSchristos if (do_remote) 759ffae97bbSchristos auth_debug_add("%s: %s", loc, msg); 760ffae97bbSchristos 761ffae97bbSchristos if (options.permit_user_env) { 762ffae97bbSchristos for (i = 0; i < opts->nenv; i++) { 763ffae97bbSchristos debug("%s: environment: %s", loc, opts->env[i]); 764ffae97bbSchristos if (do_remote) { 765ffae97bbSchristos auth_debug_add("%s: environment: %s", 766ffae97bbSchristos loc, opts->env[i]); 767ffae97bbSchristos } 768ffae97bbSchristos } 769ffae97bbSchristos } 770ffae97bbSchristos 771ffae97bbSchristos /* Go into a little more details for the local logs. */ 772ffae97bbSchristos if (opts->valid_before != 0) { 773ffae97bbSchristos format_absolute_time(opts->valid_before, buf, sizeof(buf)); 774ffae97bbSchristos debug("%s: expires at %s", loc, buf); 775ffae97bbSchristos } 776ffae97bbSchristos if (opts->cert_principals != NULL) { 777ffae97bbSchristos debug("%s: authorized principals: \"%s\"", 778ffae97bbSchristos loc, opts->cert_principals); 779ffae97bbSchristos } 780ffae97bbSchristos if (opts->force_command != NULL) 781ffae97bbSchristos debug("%s: forced command: \"%s\"", loc, opts->force_command); 78255a4608bSchristos if (do_permitopen) { 783ffae97bbSchristos for (i = 0; i < opts->npermitopen; i++) { 784ffae97bbSchristos debug("%s: permitted open: %s", 785ffae97bbSchristos loc, opts->permitopen[i]); 786ffae97bbSchristos } 787ffae97bbSchristos } 78855a4608bSchristos if (do_permitlisten) { 78955a4608bSchristos for (i = 0; i < opts->npermitlisten; i++) { 79055a4608bSchristos debug("%s: permitted listen: %s", 79155a4608bSchristos loc, opts->permitlisten[i]); 79255a4608bSchristos } 79355a4608bSchristos } 794ffae97bbSchristos } 795ffae97bbSchristos 796ffae97bbSchristos /* Activate a new set of key/cert options; merging with what is there. */ 797ffae97bbSchristos int 798ffae97bbSchristos auth_activate_options(struct ssh *ssh, struct sshauthopt *opts) 799ffae97bbSchristos { 800ffae97bbSchristos struct sshauthopt *old = auth_opts; 801ffae97bbSchristos const char *emsg = NULL; 802ffae97bbSchristos 80317418e98Schristos debug_f("setting new authentication options"); 804ffae97bbSchristos if ((auth_opts = sshauthopt_merge(old, opts, &emsg)) == NULL) { 805ffae97bbSchristos error("Inconsistent authentication options: %s", emsg); 806ffae97bbSchristos return -1; 807ffae97bbSchristos } 808ffae97bbSchristos return 0; 809ffae97bbSchristos } 810ffae97bbSchristos 811ffae97bbSchristos /* Disable forwarding, etc for the session */ 812ffae97bbSchristos void 813ffae97bbSchristos auth_restrict_session(struct ssh *ssh) 814ffae97bbSchristos { 815ffae97bbSchristos struct sshauthopt *restricted; 816ffae97bbSchristos 81717418e98Schristos debug_f("restricting session"); 818ffae97bbSchristos 819ffae97bbSchristos /* A blank sshauthopt defaults to permitting nothing */ 820e160b4e8Schristos if ((restricted = sshauthopt_new()) == NULL) 821e160b4e8Schristos fatal_f("sshauthopt_new failed"); 82255a4608bSchristos restricted->permit_pty_flag = 1; 823ffae97bbSchristos restricted->restricted = 1; 824ffae97bbSchristos 825ffae97bbSchristos if (auth_activate_options(ssh, restricted) != 0) 82617418e98Schristos fatal_f("failed to restrict session"); 827ffae97bbSchristos sshauthopt_free(restricted); 828ffae97bbSchristos } 829