1*664f4763Szrj /* $OpenBSD: auth.c,v 1.138 2019/01/19 21:41:18 djm Exp $ */ 218de8d7fSPeter Avalos /* 318de8d7fSPeter Avalos * Copyright (c) 2000 Markus Friedl. All rights reserved. 418de8d7fSPeter Avalos * 518de8d7fSPeter Avalos * Redistribution and use in source and binary forms, with or without 618de8d7fSPeter Avalos * modification, are permitted provided that the following conditions 718de8d7fSPeter Avalos * are met: 818de8d7fSPeter Avalos * 1. Redistributions of source code must retain the above copyright 918de8d7fSPeter Avalos * notice, this list of conditions and the following disclaimer. 1018de8d7fSPeter Avalos * 2. Redistributions in binary form must reproduce the above copyright 1118de8d7fSPeter Avalos * notice, this list of conditions and the following disclaimer in the 1218de8d7fSPeter Avalos * documentation and/or other materials provided with the distribution. 1318de8d7fSPeter Avalos * 1418de8d7fSPeter Avalos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1518de8d7fSPeter Avalos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1618de8d7fSPeter Avalos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1718de8d7fSPeter Avalos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1818de8d7fSPeter Avalos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1918de8d7fSPeter Avalos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2018de8d7fSPeter Avalos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2118de8d7fSPeter Avalos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2218de8d7fSPeter Avalos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2318de8d7fSPeter Avalos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2418de8d7fSPeter Avalos */ 2518de8d7fSPeter Avalos 2618de8d7fSPeter Avalos #include "includes.h" 2718de8d7fSPeter Avalos 2818de8d7fSPeter Avalos #include <sys/types.h> 2918de8d7fSPeter Avalos #include <sys/stat.h> 30e9778795SPeter Avalos #include <sys/socket.h> 31*664f4763Szrj #include <sys/wait.h> 3218de8d7fSPeter Avalos 3318de8d7fSPeter Avalos #include <netinet/in.h> 3418de8d7fSPeter Avalos 3518de8d7fSPeter Avalos #include <errno.h> 3618de8d7fSPeter Avalos #include <fcntl.h> 3718de8d7fSPeter Avalos #ifdef HAVE_PATHS_H 3818de8d7fSPeter Avalos # include <paths.h> 3918de8d7fSPeter Avalos #endif 4018de8d7fSPeter Avalos #include <pwd.h> 4118de8d7fSPeter Avalos #ifdef HAVE_LOGIN_H 4218de8d7fSPeter Avalos #include <login.h> 4318de8d7fSPeter Avalos #endif 4418de8d7fSPeter Avalos #ifdef USE_SHADOW 4518de8d7fSPeter Avalos #include <shadow.h> 4618de8d7fSPeter Avalos #endif 4718de8d7fSPeter Avalos #include <stdarg.h> 4818de8d7fSPeter Avalos #include <stdio.h> 4918de8d7fSPeter Avalos #include <string.h> 5018de8d7fSPeter Avalos #include <unistd.h> 51e9778795SPeter Avalos #include <limits.h> 52e9778795SPeter Avalos #include <netdb.h> 53*664f4763Szrj #include <time.h> 5418de8d7fSPeter Avalos 5518de8d7fSPeter Avalos #include "xmalloc.h" 5618de8d7fSPeter Avalos #include "match.h" 5718de8d7fSPeter Avalos #include "groupaccess.h" 5818de8d7fSPeter Avalos #include "log.h" 59*664f4763Szrj #include "sshbuf.h" 6036e94dc5SPeter Avalos #include "misc.h" 6118de8d7fSPeter Avalos #include "servconf.h" 62*664f4763Szrj #include "sshkey.h" 6318de8d7fSPeter Avalos #include "hostfile.h" 6418de8d7fSPeter Avalos #include "auth.h" 6518de8d7fSPeter Avalos #include "auth-options.h" 6618de8d7fSPeter Avalos #include "canohost.h" 6718de8d7fSPeter Avalos #include "uidswap.h" 6818de8d7fSPeter Avalos #include "packet.h" 6918de8d7fSPeter Avalos #include "loginrec.h" 7018de8d7fSPeter Avalos #ifdef GSSAPI 7118de8d7fSPeter Avalos #include "ssh-gss.h" 7218de8d7fSPeter Avalos #endif 73856ea928SPeter Avalos #include "authfile.h" 7418de8d7fSPeter Avalos #include "monitor_wrap.h" 75e9778795SPeter Avalos #include "authfile.h" 76e9778795SPeter Avalos #include "ssherr.h" 7736e94dc5SPeter Avalos #include "compat.h" 78*664f4763Szrj #include "channels.h" 7918de8d7fSPeter Avalos 8018de8d7fSPeter Avalos /* import */ 8118de8d7fSPeter Avalos extern ServerOptions options; 8218de8d7fSPeter Avalos extern int use_privsep; 83*664f4763Szrj extern struct sshbuf *loginmsg; 8418de8d7fSPeter Avalos extern struct passwd *privsep_pw; 85*664f4763Szrj extern struct sshauthopt *auth_opts; 8618de8d7fSPeter Avalos 8718de8d7fSPeter Avalos /* Debugging messages */ 88*664f4763Szrj static struct sshbuf *auth_debug; 8918de8d7fSPeter Avalos 9018de8d7fSPeter Avalos /* 9118de8d7fSPeter Avalos * Check if the user is allowed to log in via ssh. If user is listed 9218de8d7fSPeter Avalos * in DenyUsers or one of user's groups is listed in DenyGroups, false 9318de8d7fSPeter Avalos * will be returned. If AllowUsers isn't empty and user isn't listed 9418de8d7fSPeter Avalos * there, or if AllowGroups isn't empty and one of user's groups isn't 9518de8d7fSPeter Avalos * listed there, false will be returned. 9618de8d7fSPeter Avalos * If the user's shell is not executable, false will be returned. 9718de8d7fSPeter Avalos * Otherwise true is returned. 9818de8d7fSPeter Avalos */ 9918de8d7fSPeter Avalos int 100*664f4763Szrj allowed_user(struct ssh *ssh, struct passwd * pw) 10118de8d7fSPeter Avalos { 10218de8d7fSPeter Avalos struct stat st; 10318de8d7fSPeter Avalos const char *hostname = NULL, *ipaddr = NULL, *passwd = NULL; 10418de8d7fSPeter Avalos u_int i; 105ce74bacaSMatthew Dillon int r; 10618de8d7fSPeter Avalos #ifdef USE_SHADOW 10718de8d7fSPeter Avalos struct spwd *spw = NULL; 10818de8d7fSPeter Avalos #endif 10918de8d7fSPeter Avalos 11018de8d7fSPeter Avalos /* Shouldn't be called if pw is NULL, but better safe than sorry... */ 11118de8d7fSPeter Avalos if (!pw || !pw->pw_name) 11218de8d7fSPeter Avalos return 0; 11318de8d7fSPeter Avalos 11418de8d7fSPeter Avalos #ifdef USE_SHADOW 11518de8d7fSPeter Avalos if (!options.use_pam) 11618de8d7fSPeter Avalos spw = getspnam(pw->pw_name); 11718de8d7fSPeter Avalos #ifdef HAS_SHADOW_EXPIRE 11818de8d7fSPeter Avalos if (!options.use_pam && spw != NULL && auth_shadow_acctexpired(spw)) 11918de8d7fSPeter Avalos return 0; 12018de8d7fSPeter Avalos #endif /* HAS_SHADOW_EXPIRE */ 12118de8d7fSPeter Avalos #endif /* USE_SHADOW */ 12218de8d7fSPeter Avalos 12318de8d7fSPeter Avalos /* grab passwd field for locked account check */ 12418de8d7fSPeter Avalos passwd = pw->pw_passwd; 12518de8d7fSPeter Avalos #ifdef USE_SHADOW 12618de8d7fSPeter Avalos if (spw != NULL) 12718de8d7fSPeter Avalos #ifdef USE_LIBIAF 12818de8d7fSPeter Avalos passwd = get_iaf_password(pw); 12918de8d7fSPeter Avalos #else 13018de8d7fSPeter Avalos passwd = spw->sp_pwdp; 13118de8d7fSPeter Avalos #endif /* USE_LIBIAF */ 13218de8d7fSPeter Avalos #endif 13318de8d7fSPeter Avalos 13418de8d7fSPeter Avalos /* check for locked account */ 13518de8d7fSPeter Avalos if (!options.use_pam && passwd && *passwd) { 13618de8d7fSPeter Avalos int locked = 0; 13718de8d7fSPeter Avalos 13818de8d7fSPeter Avalos #ifdef LOCKED_PASSWD_STRING 13918de8d7fSPeter Avalos if (strcmp(passwd, LOCKED_PASSWD_STRING) == 0) 14018de8d7fSPeter Avalos locked = 1; 14118de8d7fSPeter Avalos #endif 14218de8d7fSPeter Avalos #ifdef LOCKED_PASSWD_PREFIX 14318de8d7fSPeter Avalos if (strncmp(passwd, LOCKED_PASSWD_PREFIX, 14418de8d7fSPeter Avalos strlen(LOCKED_PASSWD_PREFIX)) == 0) 14518de8d7fSPeter Avalos locked = 1; 14618de8d7fSPeter Avalos #endif 14718de8d7fSPeter Avalos #ifdef LOCKED_PASSWD_SUBSTR 14818de8d7fSPeter Avalos if (strstr(passwd, LOCKED_PASSWD_SUBSTR)) 14918de8d7fSPeter Avalos locked = 1; 15018de8d7fSPeter Avalos #endif 15118de8d7fSPeter Avalos #ifdef USE_LIBIAF 152856ea928SPeter Avalos free((void *) passwd); 15318de8d7fSPeter Avalos #endif /* USE_LIBIAF */ 15418de8d7fSPeter Avalos if (locked) { 15518de8d7fSPeter Avalos logit("User %.100s not allowed because account is locked", 15618de8d7fSPeter Avalos pw->pw_name); 15718de8d7fSPeter Avalos return 0; 15818de8d7fSPeter Avalos } 15918de8d7fSPeter Avalos } 16018de8d7fSPeter Avalos 16118de8d7fSPeter Avalos /* 162856ea928SPeter Avalos * Deny if shell does not exist or is not executable unless we 163856ea928SPeter Avalos * are chrooting. 16418de8d7fSPeter Avalos */ 165856ea928SPeter Avalos if (options.chroot_directory == NULL || 166856ea928SPeter Avalos strcasecmp(options.chroot_directory, "none") == 0) { 167856ea928SPeter Avalos char *shell = xstrdup((pw->pw_shell[0] == '\0') ? 168856ea928SPeter Avalos _PATH_BSHELL : pw->pw_shell); /* empty = /bin/sh */ 16918de8d7fSPeter Avalos 17018de8d7fSPeter Avalos if (stat(shell, &st) != 0) { 171856ea928SPeter Avalos logit("User %.100s not allowed because shell %.100s " 172856ea928SPeter Avalos "does not exist", pw->pw_name, shell); 17336e94dc5SPeter Avalos free(shell); 17418de8d7fSPeter Avalos return 0; 17518de8d7fSPeter Avalos } 17618de8d7fSPeter Avalos if (S_ISREG(st.st_mode) == 0 || 17718de8d7fSPeter Avalos (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) { 178856ea928SPeter Avalos logit("User %.100s not allowed because shell %.100s " 179856ea928SPeter Avalos "is not executable", pw->pw_name, shell); 18036e94dc5SPeter Avalos free(shell); 18118de8d7fSPeter Avalos return 0; 18218de8d7fSPeter Avalos } 18336e94dc5SPeter Avalos free(shell); 184856ea928SPeter Avalos } 18518de8d7fSPeter Avalos 18618de8d7fSPeter Avalos if (options.num_deny_users > 0 || options.num_allow_users > 0 || 18718de8d7fSPeter Avalos options.num_deny_groups > 0 || options.num_allow_groups > 0) { 188e9778795SPeter Avalos hostname = auth_get_canonical_hostname(ssh, options.use_dns); 189e9778795SPeter Avalos ipaddr = ssh_remote_ipaddr(ssh); 19018de8d7fSPeter Avalos } 19118de8d7fSPeter Avalos 19218de8d7fSPeter Avalos /* Return false if user is listed in DenyUsers */ 19318de8d7fSPeter Avalos if (options.num_deny_users > 0) { 194ce74bacaSMatthew Dillon for (i = 0; i < options.num_deny_users; i++) { 195ce74bacaSMatthew Dillon r = match_user(pw->pw_name, hostname, ipaddr, 196ce74bacaSMatthew Dillon options.deny_users[i]); 197ce74bacaSMatthew Dillon if (r < 0) { 198ce74bacaSMatthew Dillon fatal("Invalid DenyUsers pattern \"%.100s\"", 199ce74bacaSMatthew Dillon options.deny_users[i]); 200ce74bacaSMatthew Dillon } else if (r != 0) { 20118de8d7fSPeter Avalos logit("User %.100s from %.100s not allowed " 20218de8d7fSPeter Avalos "because listed in DenyUsers", 20318de8d7fSPeter Avalos pw->pw_name, hostname); 20418de8d7fSPeter Avalos return 0; 20518de8d7fSPeter Avalos } 20618de8d7fSPeter Avalos } 207ce74bacaSMatthew Dillon } 20818de8d7fSPeter Avalos /* Return false if AllowUsers isn't empty and user isn't listed there */ 20918de8d7fSPeter Avalos if (options.num_allow_users > 0) { 210ce74bacaSMatthew Dillon for (i = 0; i < options.num_allow_users; i++) { 211ce74bacaSMatthew Dillon r = match_user(pw->pw_name, hostname, ipaddr, 212ce74bacaSMatthew Dillon options.allow_users[i]); 213ce74bacaSMatthew Dillon if (r < 0) { 214ce74bacaSMatthew Dillon fatal("Invalid AllowUsers pattern \"%.100s\"", 215ce74bacaSMatthew Dillon options.allow_users[i]); 216ce74bacaSMatthew Dillon } else if (r == 1) 21718de8d7fSPeter Avalos break; 218ce74bacaSMatthew Dillon } 21918de8d7fSPeter Avalos /* i < options.num_allow_users iff we break for loop */ 22018de8d7fSPeter Avalos if (i >= options.num_allow_users) { 22118de8d7fSPeter Avalos logit("User %.100s from %.100s not allowed because " 22218de8d7fSPeter Avalos "not listed in AllowUsers", pw->pw_name, hostname); 22318de8d7fSPeter Avalos return 0; 22418de8d7fSPeter Avalos } 22518de8d7fSPeter Avalos } 22618de8d7fSPeter Avalos if (options.num_deny_groups > 0 || options.num_allow_groups > 0) { 22718de8d7fSPeter Avalos /* Get the user's group access list (primary and supplementary) */ 22818de8d7fSPeter Avalos if (ga_init(pw->pw_name, pw->pw_gid) == 0) { 22918de8d7fSPeter Avalos logit("User %.100s from %.100s not allowed because " 23018de8d7fSPeter Avalos "not in any group", pw->pw_name, hostname); 23118de8d7fSPeter Avalos return 0; 23218de8d7fSPeter Avalos } 23318de8d7fSPeter Avalos 23418de8d7fSPeter Avalos /* Return false if one of user's groups is listed in DenyGroups */ 23518de8d7fSPeter Avalos if (options.num_deny_groups > 0) 23618de8d7fSPeter Avalos if (ga_match(options.deny_groups, 23718de8d7fSPeter Avalos options.num_deny_groups)) { 23818de8d7fSPeter Avalos ga_free(); 23918de8d7fSPeter Avalos logit("User %.100s from %.100s not allowed " 24018de8d7fSPeter Avalos "because a group is listed in DenyGroups", 24118de8d7fSPeter Avalos pw->pw_name, hostname); 24218de8d7fSPeter Avalos return 0; 24318de8d7fSPeter Avalos } 24418de8d7fSPeter Avalos /* 24518de8d7fSPeter Avalos * Return false if AllowGroups isn't empty and one of user's groups 24618de8d7fSPeter Avalos * isn't listed there 24718de8d7fSPeter Avalos */ 24818de8d7fSPeter Avalos if (options.num_allow_groups > 0) 24918de8d7fSPeter Avalos if (!ga_match(options.allow_groups, 25018de8d7fSPeter Avalos options.num_allow_groups)) { 25118de8d7fSPeter Avalos ga_free(); 25218de8d7fSPeter Avalos logit("User %.100s from %.100s not allowed " 25318de8d7fSPeter Avalos "because none of user's groups are listed " 25418de8d7fSPeter Avalos "in AllowGroups", pw->pw_name, hostname); 25518de8d7fSPeter Avalos return 0; 25618de8d7fSPeter Avalos } 25718de8d7fSPeter Avalos ga_free(); 25818de8d7fSPeter Avalos } 25918de8d7fSPeter Avalos 26018de8d7fSPeter Avalos #ifdef CUSTOM_SYS_AUTH_ALLOWED_USER 261*664f4763Szrj if (!sys_auth_allowed_user(pw, loginmsg)) 26218de8d7fSPeter Avalos return 0; 26318de8d7fSPeter Avalos #endif 26418de8d7fSPeter Avalos 26518de8d7fSPeter Avalos /* We found no reason not to let this user try to log on... */ 26618de8d7fSPeter Avalos return 1; 26718de8d7fSPeter Avalos } 26818de8d7fSPeter Avalos 269ce74bacaSMatthew Dillon /* 270ce74bacaSMatthew Dillon * Formats any key left in authctxt->auth_method_key for inclusion in 271ce74bacaSMatthew Dillon * auth_log()'s message. Also includes authxtct->auth_method_info if present. 272ce74bacaSMatthew Dillon */ 273ce74bacaSMatthew Dillon static char * 274ce74bacaSMatthew Dillon format_method_key(Authctxt *authctxt) 27536e94dc5SPeter Avalos { 276ce74bacaSMatthew Dillon const struct sshkey *key = authctxt->auth_method_key; 277ce74bacaSMatthew Dillon const char *methinfo = authctxt->auth_method_info; 278*664f4763Szrj char *fp, *cafp, *ret = NULL; 27936e94dc5SPeter Avalos 280ce74bacaSMatthew Dillon if (key == NULL) 281ce74bacaSMatthew Dillon return NULL; 28236e94dc5SPeter Avalos 283*664f4763Szrj if (sshkey_is_cert(key)) { 284*664f4763Szrj fp = sshkey_fingerprint(key, 285ce74bacaSMatthew Dillon options.fingerprint_hash, SSH_FP_DEFAULT); 286*664f4763Szrj cafp = sshkey_fingerprint(key->cert->signature_key, 287*664f4763Szrj options.fingerprint_hash, SSH_FP_DEFAULT); 288*664f4763Szrj xasprintf(&ret, "%s %s ID %s (serial %llu) CA %s %s%s%s", 289*664f4763Szrj sshkey_type(key), fp == NULL ? "(null)" : fp, 290*664f4763Szrj key->cert->key_id, 291ce74bacaSMatthew Dillon (unsigned long long)key->cert->serial, 292ce74bacaSMatthew Dillon sshkey_type(key->cert->signature_key), 293*664f4763Szrj cafp == NULL ? "(null)" : cafp, 294ce74bacaSMatthew Dillon methinfo == NULL ? "" : ", ", 295ce74bacaSMatthew Dillon methinfo == NULL ? "" : methinfo); 296ce74bacaSMatthew Dillon free(fp); 297*664f4763Szrj free(cafp); 298ce74bacaSMatthew Dillon } else { 299ce74bacaSMatthew Dillon fp = sshkey_fingerprint(key, options.fingerprint_hash, 300ce74bacaSMatthew Dillon SSH_FP_DEFAULT); 301ce74bacaSMatthew Dillon xasprintf(&ret, "%s %s%s%s", sshkey_type(key), 302ce74bacaSMatthew Dillon fp == NULL ? "(null)" : fp, 303ce74bacaSMatthew Dillon methinfo == NULL ? "" : ", ", 304ce74bacaSMatthew Dillon methinfo == NULL ? "" : methinfo); 305ce74bacaSMatthew Dillon free(fp); 306ce74bacaSMatthew Dillon } 307ce74bacaSMatthew Dillon return ret; 30836e94dc5SPeter Avalos } 30936e94dc5SPeter Avalos 31036e94dc5SPeter Avalos void 311*664f4763Szrj auth_log(struct ssh *ssh, int authenticated, int partial, 31236e94dc5SPeter Avalos const char *method, const char *submethod) 31318de8d7fSPeter Avalos { 314*664f4763Szrj Authctxt *authctxt = (Authctxt *)ssh->authctxt; 315*664f4763Szrj int level = SYSLOG_LEVEL_VERBOSE; 316ce74bacaSMatthew Dillon const char *authmsg; 317ce74bacaSMatthew Dillon char *extra = NULL; 31818de8d7fSPeter Avalos 31918de8d7fSPeter Avalos if (use_privsep && !mm_is_monitor() && !authctxt->postponed) 32018de8d7fSPeter Avalos return; 32118de8d7fSPeter Avalos 32218de8d7fSPeter Avalos /* Raise logging level */ 32318de8d7fSPeter Avalos if (authenticated == 1 || 32418de8d7fSPeter Avalos !authctxt->valid || 32518de8d7fSPeter Avalos authctxt->failures >= options.max_authtries / 2 || 32618de8d7fSPeter Avalos strcmp(method, "password") == 0) 327*664f4763Szrj level = SYSLOG_LEVEL_INFO; 32818de8d7fSPeter Avalos 32918de8d7fSPeter Avalos if (authctxt->postponed) 33018de8d7fSPeter Avalos authmsg = "Postponed"; 33136e94dc5SPeter Avalos else if (partial) 33236e94dc5SPeter Avalos authmsg = "Partial"; 33318de8d7fSPeter Avalos else 33418de8d7fSPeter Avalos authmsg = authenticated ? "Accepted" : "Failed"; 33518de8d7fSPeter Avalos 336ce74bacaSMatthew Dillon if ((extra = format_method_key(authctxt)) == NULL) { 337ce74bacaSMatthew Dillon if (authctxt->auth_method_info != NULL) 338ce74bacaSMatthew Dillon extra = xstrdup(authctxt->auth_method_info); 339ce74bacaSMatthew Dillon } 340ce74bacaSMatthew Dillon 341*664f4763Szrj do_log2(level, "%s %s%s%s for %s%.100s from %.200s port %d ssh2%s%s", 34218de8d7fSPeter Avalos authmsg, 34318de8d7fSPeter Avalos method, 34436e94dc5SPeter Avalos submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod, 34518de8d7fSPeter Avalos authctxt->valid ? "" : "invalid user ", 34618de8d7fSPeter Avalos authctxt->user, 347e9778795SPeter Avalos ssh_remote_ipaddr(ssh), 348e9778795SPeter Avalos ssh_remote_port(ssh), 349ce74bacaSMatthew Dillon extra != NULL ? ": " : "", 350ce74bacaSMatthew Dillon extra != NULL ? extra : ""); 351ce74bacaSMatthew Dillon 352ce74bacaSMatthew Dillon free(extra); 35318de8d7fSPeter Avalos 35418de8d7fSPeter Avalos #ifdef CUSTOM_FAILED_LOGIN 35518de8d7fSPeter Avalos if (authenticated == 0 && !authctxt->postponed && 35618de8d7fSPeter Avalos (strcmp(method, "password") == 0 || 35718de8d7fSPeter Avalos strncmp(method, "keyboard-interactive", 20) == 0 || 35818de8d7fSPeter Avalos strcmp(method, "challenge-response") == 0)) 359*664f4763Szrj record_failed_login(ssh, authctxt->user, 360e9778795SPeter Avalos auth_get_canonical_hostname(ssh, options.use_dns), "ssh"); 36118de8d7fSPeter Avalos # ifdef WITH_AIXAUTHENTICATE 36218de8d7fSPeter Avalos if (authenticated) 36318de8d7fSPeter Avalos sys_auth_record_login(authctxt->user, 364e9778795SPeter Avalos auth_get_canonical_hostname(ssh, options.use_dns), "ssh", 365*664f4763Szrj loginmsg); 36618de8d7fSPeter Avalos # endif 36718de8d7fSPeter Avalos #endif 36818de8d7fSPeter Avalos #ifdef SSH_AUDIT_EVENTS 36918de8d7fSPeter Avalos if (authenticated == 0 && !authctxt->postponed) 370*664f4763Szrj audit_event(ssh, audit_classify_auth(method)); 37118de8d7fSPeter Avalos #endif 37218de8d7fSPeter Avalos } 37318de8d7fSPeter Avalos 37436e94dc5SPeter Avalos 37536e94dc5SPeter Avalos void 376*664f4763Szrj auth_maxtries_exceeded(struct ssh *ssh) 37736e94dc5SPeter Avalos { 378*664f4763Szrj Authctxt *authctxt = (Authctxt *)ssh->authctxt; 379e9778795SPeter Avalos 380e9778795SPeter Avalos error("maximum authentication attempts exceeded for " 381ce74bacaSMatthew Dillon "%s%.100s from %.200s port %d ssh2", 38236e94dc5SPeter Avalos authctxt->valid ? "" : "invalid user ", 38336e94dc5SPeter Avalos authctxt->user, 384e9778795SPeter Avalos ssh_remote_ipaddr(ssh), 385ce74bacaSMatthew Dillon ssh_remote_port(ssh)); 386*664f4763Szrj ssh_packet_disconnect(ssh, "Too many authentication failures"); 38736e94dc5SPeter Avalos /* NOTREACHED */ 38836e94dc5SPeter Avalos } 38936e94dc5SPeter Avalos 39018de8d7fSPeter Avalos /* 39118de8d7fSPeter Avalos * Check whether root logins are disallowed. 39218de8d7fSPeter Avalos */ 39318de8d7fSPeter Avalos int 394*664f4763Szrj auth_root_allowed(struct ssh *ssh, const char *method) 39518de8d7fSPeter Avalos { 39618de8d7fSPeter Avalos switch (options.permit_root_login) { 39718de8d7fSPeter Avalos case PERMIT_YES: 39818de8d7fSPeter Avalos return 1; 39918de8d7fSPeter Avalos case PERMIT_NO_PASSWD: 400e9778795SPeter Avalos if (strcmp(method, "publickey") == 0 || 401e9778795SPeter Avalos strcmp(method, "hostbased") == 0 || 402e9778795SPeter Avalos strcmp(method, "gssapi-with-mic") == 0) 40318de8d7fSPeter Avalos return 1; 40418de8d7fSPeter Avalos break; 40518de8d7fSPeter Avalos case PERMIT_FORCED_ONLY: 406*664f4763Szrj if (auth_opts->force_command != NULL) { 40718de8d7fSPeter Avalos logit("Root login accepted for forced command."); 40818de8d7fSPeter Avalos return 1; 40918de8d7fSPeter Avalos } 41018de8d7fSPeter Avalos break; 41118de8d7fSPeter Avalos } 412e9778795SPeter Avalos logit("ROOT LOGIN REFUSED FROM %.200s port %d", 413e9778795SPeter Avalos ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); 41418de8d7fSPeter Avalos return 0; 41518de8d7fSPeter Avalos } 41618de8d7fSPeter Avalos 41718de8d7fSPeter Avalos 41818de8d7fSPeter Avalos /* 41918de8d7fSPeter Avalos * Given a template and a passwd structure, build a filename 42018de8d7fSPeter Avalos * by substituting % tokenised options. Currently, %% becomes '%', 42118de8d7fSPeter Avalos * %h becomes the home directory and %u the username. 42218de8d7fSPeter Avalos * 42318de8d7fSPeter Avalos * This returns a buffer allocated by xmalloc. 42418de8d7fSPeter Avalos */ 4251c188a7fSPeter Avalos char * 42618de8d7fSPeter Avalos expand_authorized_keys(const char *filename, struct passwd *pw) 42718de8d7fSPeter Avalos { 428*664f4763Szrj char *file, uidstr[32], ret[PATH_MAX]; 42918de8d7fSPeter Avalos int i; 43018de8d7fSPeter Avalos 431*664f4763Szrj snprintf(uidstr, sizeof(uidstr), "%llu", 432*664f4763Szrj (unsigned long long)pw->pw_uid); 43318de8d7fSPeter Avalos file = percent_expand(filename, "h", pw->pw_dir, 434*664f4763Szrj "u", pw->pw_name, "U", uidstr, (char *)NULL); 43518de8d7fSPeter Avalos 43618de8d7fSPeter Avalos /* 43718de8d7fSPeter Avalos * Ensure that filename starts anchored. If not, be backward 43818de8d7fSPeter Avalos * compatible and prepend the '%h/' 43918de8d7fSPeter Avalos */ 440*664f4763Szrj if (path_absolute(file)) 44118de8d7fSPeter Avalos return (file); 44218de8d7fSPeter Avalos 44318de8d7fSPeter Avalos i = snprintf(ret, sizeof(ret), "%s/%s", pw->pw_dir, file); 44418de8d7fSPeter Avalos if (i < 0 || (size_t)i >= sizeof(ret)) 44518de8d7fSPeter Avalos fatal("expand_authorized_keys: path too long"); 44636e94dc5SPeter Avalos free(file); 44718de8d7fSPeter Avalos return (xstrdup(ret)); 44818de8d7fSPeter Avalos } 44918de8d7fSPeter Avalos 45018de8d7fSPeter Avalos char * 451856ea928SPeter Avalos authorized_principals_file(struct passwd *pw) 452856ea928SPeter Avalos { 453e9778795SPeter Avalos if (options.authorized_principals_file == NULL) 454856ea928SPeter Avalos return NULL; 455856ea928SPeter Avalos return expand_authorized_keys(options.authorized_principals_file, pw); 456856ea928SPeter Avalos } 457856ea928SPeter Avalos 45818de8d7fSPeter Avalos /* return ok if key exists in sysfile or userfile */ 45918de8d7fSPeter Avalos HostStatus 460ce74bacaSMatthew Dillon check_key_in_hostfiles(struct passwd *pw, struct sshkey *key, const char *host, 46118de8d7fSPeter Avalos const char *sysfile, const char *userfile) 46218de8d7fSPeter Avalos { 46318de8d7fSPeter Avalos char *user_hostfile; 46418de8d7fSPeter Avalos struct stat st; 46518de8d7fSPeter Avalos HostStatus host_status; 4669f304aafSPeter Avalos struct hostkeys *hostkeys; 4679f304aafSPeter Avalos const struct hostkey_entry *found; 46818de8d7fSPeter Avalos 4699f304aafSPeter Avalos hostkeys = init_hostkeys(); 4709f304aafSPeter Avalos load_hostkeys(hostkeys, host, sysfile); 4719f304aafSPeter Avalos if (userfile != NULL) { 47218de8d7fSPeter Avalos user_hostfile = tilde_expand_filename(userfile, pw->pw_uid); 47318de8d7fSPeter Avalos if (options.strict_modes && 47418de8d7fSPeter Avalos (stat(user_hostfile, &st) == 0) && 47518de8d7fSPeter Avalos ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || 47618de8d7fSPeter Avalos (st.st_mode & 022) != 0)) { 47718de8d7fSPeter Avalos logit("Authentication refused for %.100s: " 47818de8d7fSPeter Avalos "bad owner or modes for %.200s", 47918de8d7fSPeter Avalos pw->pw_name, user_hostfile); 480856ea928SPeter Avalos auth_debug_add("Ignored %.200s: bad ownership or modes", 481856ea928SPeter Avalos user_hostfile); 48218de8d7fSPeter Avalos } else { 48318de8d7fSPeter Avalos temporarily_use_uid(pw); 4849f304aafSPeter Avalos load_hostkeys(hostkeys, host, user_hostfile); 48518de8d7fSPeter Avalos restore_uid(); 48618de8d7fSPeter Avalos } 48736e94dc5SPeter Avalos free(user_hostfile); 48818de8d7fSPeter Avalos } 4899f304aafSPeter Avalos host_status = check_key_in_hostkeys(hostkeys, key, &found); 4909f304aafSPeter Avalos if (host_status == HOST_REVOKED) 4919f304aafSPeter Avalos error("WARNING: revoked key for %s attempted authentication", 4929f304aafSPeter Avalos found->host); 4939f304aafSPeter Avalos else if (host_status == HOST_OK) 4949f304aafSPeter Avalos debug("%s: key for %s found at %s:%ld", __func__, 4959f304aafSPeter Avalos found->host, found->file, found->line); 4969f304aafSPeter Avalos else 4979f304aafSPeter Avalos debug("%s: key for host %s not found", __func__, host); 49818de8d7fSPeter Avalos 4999f304aafSPeter Avalos free_hostkeys(hostkeys); 5009f304aafSPeter Avalos 50118de8d7fSPeter Avalos return host_status; 50218de8d7fSPeter Avalos } 50318de8d7fSPeter Avalos 504856ea928SPeter Avalos static FILE * 505856ea928SPeter Avalos auth_openfile(const char *file, struct passwd *pw, int strict_modes, 506856ea928SPeter Avalos int log_missing, char *file_type) 50718de8d7fSPeter Avalos { 50818de8d7fSPeter Avalos char line[1024]; 50918de8d7fSPeter Avalos struct stat st; 51018de8d7fSPeter Avalos int fd; 51118de8d7fSPeter Avalos FILE *f; 51218de8d7fSPeter Avalos 513856ea928SPeter Avalos if ((fd = open(file, O_RDONLY|O_NONBLOCK)) == -1) { 514856ea928SPeter Avalos if (log_missing || errno != ENOENT) 515856ea928SPeter Avalos debug("Could not open %s '%s': %s", file_type, file, 516856ea928SPeter Avalos strerror(errno)); 51718de8d7fSPeter Avalos return NULL; 518856ea928SPeter Avalos } 51918de8d7fSPeter Avalos 52018de8d7fSPeter Avalos if (fstat(fd, &st) < 0) { 52118de8d7fSPeter Avalos close(fd); 52218de8d7fSPeter Avalos return NULL; 52318de8d7fSPeter Avalos } 52418de8d7fSPeter Avalos if (!S_ISREG(st.st_mode)) { 525856ea928SPeter Avalos logit("User %s %s %s is not a regular file", 526856ea928SPeter Avalos pw->pw_name, file_type, file); 52718de8d7fSPeter Avalos close(fd); 52818de8d7fSPeter Avalos return NULL; 52918de8d7fSPeter Avalos } 53018de8d7fSPeter Avalos unset_nonblock(fd); 53118de8d7fSPeter Avalos if ((f = fdopen(fd, "r")) == NULL) { 53218de8d7fSPeter Avalos close(fd); 53318de8d7fSPeter Avalos return NULL; 53418de8d7fSPeter Avalos } 5359f304aafSPeter Avalos if (strict_modes && 536ce74bacaSMatthew Dillon safe_path_fd(fileno(f), file, pw, line, sizeof(line)) != 0) { 53718de8d7fSPeter Avalos fclose(f); 53818de8d7fSPeter Avalos logit("Authentication refused: %s", line); 539856ea928SPeter Avalos auth_debug_add("Ignored %s: %s", file_type, line); 54018de8d7fSPeter Avalos return NULL; 54118de8d7fSPeter Avalos } 54218de8d7fSPeter Avalos 54318de8d7fSPeter Avalos return f; 54418de8d7fSPeter Avalos } 54518de8d7fSPeter Avalos 546856ea928SPeter Avalos 547856ea928SPeter Avalos FILE * 548856ea928SPeter Avalos auth_openkeyfile(const char *file, struct passwd *pw, int strict_modes) 549856ea928SPeter Avalos { 550856ea928SPeter Avalos return auth_openfile(file, pw, strict_modes, 1, "authorized keys"); 551856ea928SPeter Avalos } 552856ea928SPeter Avalos 553856ea928SPeter Avalos FILE * 554856ea928SPeter Avalos auth_openprincipals(const char *file, struct passwd *pw, int strict_modes) 555856ea928SPeter Avalos { 556856ea928SPeter Avalos return auth_openfile(file, pw, strict_modes, 0, 557856ea928SPeter Avalos "authorized principals"); 558856ea928SPeter Avalos } 559856ea928SPeter Avalos 56018de8d7fSPeter Avalos struct passwd * 561*664f4763Szrj getpwnamallow(struct ssh *ssh, const char *user) 56218de8d7fSPeter Avalos { 56318de8d7fSPeter Avalos #ifdef HAVE_LOGIN_CAP 56418de8d7fSPeter Avalos extern login_cap_t *lc; 56518de8d7fSPeter Avalos #ifdef BSD_AUTH 56618de8d7fSPeter Avalos auth_session_t *as; 56718de8d7fSPeter Avalos #endif 56818de8d7fSPeter Avalos #endif 56918de8d7fSPeter Avalos struct passwd *pw; 570*664f4763Szrj struct connection_info *ci; 57118de8d7fSPeter Avalos 572*664f4763Szrj ci = get_connection_info(ssh, 1, options.use_dns); 57399e85e0dSPeter Avalos ci->user = user; 57499e85e0dSPeter Avalos parse_server_match_config(&options, ci); 575ce74bacaSMatthew Dillon log_change_level(options.log_level); 576ce74bacaSMatthew Dillon process_permitopen(ssh, &options); 57718de8d7fSPeter Avalos 578856ea928SPeter Avalos #if defined(_AIX) && defined(HAVE_SETAUTHDB) 579856ea928SPeter Avalos aix_setauthdb(user); 580856ea928SPeter Avalos #endif 581856ea928SPeter Avalos 58218de8d7fSPeter Avalos pw = getpwnam(user); 583856ea928SPeter Avalos 584856ea928SPeter Avalos #if defined(_AIX) && defined(HAVE_SETAUTHDB) 585856ea928SPeter Avalos aix_restoreauthdb(); 586856ea928SPeter Avalos #endif 58718de8d7fSPeter Avalos if (pw == NULL) { 588e9778795SPeter Avalos logit("Invalid user %.100s from %.100s port %d", 589e9778795SPeter Avalos user, ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); 59018de8d7fSPeter Avalos #ifdef CUSTOM_FAILED_LOGIN 591*664f4763Szrj record_failed_login(ssh, user, 592e9778795SPeter Avalos auth_get_canonical_hostname(ssh, options.use_dns), "ssh"); 59318de8d7fSPeter Avalos #endif 59418de8d7fSPeter Avalos #ifdef SSH_AUDIT_EVENTS 595*664f4763Szrj audit_event(ssh, SSH_INVALID_USER); 59618de8d7fSPeter Avalos #endif /* SSH_AUDIT_EVENTS */ 59718de8d7fSPeter Avalos return (NULL); 59818de8d7fSPeter Avalos } 599*664f4763Szrj if (!allowed_user(ssh, pw)) 60018de8d7fSPeter Avalos return (NULL); 60118de8d7fSPeter Avalos #ifdef HAVE_LOGIN_CAP 60218de8d7fSPeter Avalos if ((lc = login_getclass(pw->pw_class)) == NULL) { 60318de8d7fSPeter Avalos debug("unable to get login class: %s", user); 60418de8d7fSPeter Avalos return (NULL); 60518de8d7fSPeter Avalos } 60618de8d7fSPeter Avalos #ifdef BSD_AUTH 60718de8d7fSPeter Avalos if ((as = auth_open()) == NULL || auth_setpwd(as, pw) != 0 || 60818de8d7fSPeter Avalos auth_approval(as, lc, pw->pw_name, "ssh") <= 0) { 60918de8d7fSPeter Avalos debug("Approval failure for %s", user); 61018de8d7fSPeter Avalos pw = NULL; 61118de8d7fSPeter Avalos } 61218de8d7fSPeter Avalos if (as != NULL) 61318de8d7fSPeter Avalos auth_close(as); 61418de8d7fSPeter Avalos #endif 61518de8d7fSPeter Avalos #endif 61618de8d7fSPeter Avalos if (pw != NULL) 61718de8d7fSPeter Avalos return (pwcopy(pw)); 61818de8d7fSPeter Avalos return (NULL); 61918de8d7fSPeter Avalos } 62018de8d7fSPeter Avalos 621856ea928SPeter Avalos /* Returns 1 if key is revoked by revoked_keys_file, 0 otherwise */ 622856ea928SPeter Avalos int 623ce74bacaSMatthew Dillon auth_key_is_revoked(struct sshkey *key) 624856ea928SPeter Avalos { 625e9778795SPeter Avalos char *fp = NULL; 626e9778795SPeter Avalos int r; 627856ea928SPeter Avalos 628856ea928SPeter Avalos if (options.revoked_keys_file == NULL) 629856ea928SPeter Avalos return 0; 630e9778795SPeter Avalos if ((fp = sshkey_fingerprint(key, options.fingerprint_hash, 631e9778795SPeter Avalos SSH_FP_DEFAULT)) == NULL) { 632e9778795SPeter Avalos r = SSH_ERR_ALLOC_FAIL; 633e9778795SPeter Avalos error("%s: fingerprint key: %s", __func__, ssh_err(r)); 634e9778795SPeter Avalos goto out; 635e9778795SPeter Avalos } 636e9778795SPeter Avalos 637e9778795SPeter Avalos r = sshkey_check_revoked(key, options.revoked_keys_file); 638e9778795SPeter Avalos switch (r) { 63936e94dc5SPeter Avalos case 0: 640e9778795SPeter Avalos break; /* not revoked */ 641e9778795SPeter Avalos case SSH_ERR_KEY_REVOKED: 642e9778795SPeter Avalos error("Authentication key %s %s revoked by file %s", 643e9778795SPeter Avalos sshkey_type(key), fp, options.revoked_keys_file); 644e9778795SPeter Avalos goto out; 64536e94dc5SPeter Avalos default: 646e9778795SPeter Avalos error("Error checking authentication key %s %s in " 647e9778795SPeter Avalos "revoked keys file %s: %s", sshkey_type(key), fp, 648e9778795SPeter Avalos options.revoked_keys_file, ssh_err(r)); 649e9778795SPeter Avalos goto out; 65036e94dc5SPeter Avalos } 651e9778795SPeter Avalos 652e9778795SPeter Avalos /* Success */ 653e9778795SPeter Avalos r = 0; 654e9778795SPeter Avalos 655e9778795SPeter Avalos out: 656e9778795SPeter Avalos free(fp); 657e9778795SPeter Avalos return r == 0 ? 0 : 1; 658856ea928SPeter Avalos } 659856ea928SPeter Avalos 66018de8d7fSPeter Avalos void 66118de8d7fSPeter Avalos auth_debug_add(const char *fmt,...) 66218de8d7fSPeter Avalos { 66318de8d7fSPeter Avalos char buf[1024]; 66418de8d7fSPeter Avalos va_list args; 665*664f4763Szrj int r; 66618de8d7fSPeter Avalos 667*664f4763Szrj if (auth_debug == NULL) 66818de8d7fSPeter Avalos return; 66918de8d7fSPeter Avalos 67018de8d7fSPeter Avalos va_start(args, fmt); 67118de8d7fSPeter Avalos vsnprintf(buf, sizeof(buf), fmt, args); 67218de8d7fSPeter Avalos va_end(args); 673*664f4763Szrj if ((r = sshbuf_put_cstring(auth_debug, buf)) != 0) 674*664f4763Szrj fatal("%s: sshbuf_put_cstring: %s", __func__, ssh_err(r)); 67518de8d7fSPeter Avalos } 67618de8d7fSPeter Avalos 67718de8d7fSPeter Avalos void 678*664f4763Szrj auth_debug_send(struct ssh *ssh) 67918de8d7fSPeter Avalos { 68018de8d7fSPeter Avalos char *msg; 681*664f4763Szrj int r; 68218de8d7fSPeter Avalos 683*664f4763Szrj if (auth_debug == NULL) 68418de8d7fSPeter Avalos return; 685*664f4763Szrj while (sshbuf_len(auth_debug) != 0) { 686*664f4763Szrj if ((r = sshbuf_get_cstring(auth_debug, &msg, NULL)) != 0) 687*664f4763Szrj fatal("%s: sshbuf_get_cstring: %s", 688*664f4763Szrj __func__, ssh_err(r)); 689*664f4763Szrj ssh_packet_send_debug(ssh, "%s", msg); 69036e94dc5SPeter Avalos free(msg); 69118de8d7fSPeter Avalos } 69218de8d7fSPeter Avalos } 69318de8d7fSPeter Avalos 69418de8d7fSPeter Avalos void 69518de8d7fSPeter Avalos auth_debug_reset(void) 69618de8d7fSPeter Avalos { 697*664f4763Szrj if (auth_debug != NULL) 698*664f4763Szrj sshbuf_reset(auth_debug); 699*664f4763Szrj else if ((auth_debug = sshbuf_new()) == NULL) 700*664f4763Szrj fatal("%s: sshbuf_new failed", __func__); 70118de8d7fSPeter Avalos } 70218de8d7fSPeter Avalos 70318de8d7fSPeter Avalos struct passwd * 70418de8d7fSPeter Avalos fakepw(void) 70518de8d7fSPeter Avalos { 70618de8d7fSPeter Avalos static struct passwd fake; 70718de8d7fSPeter Avalos 70818de8d7fSPeter Avalos memset(&fake, 0, sizeof(fake)); 70918de8d7fSPeter Avalos fake.pw_name = "NOUSER"; 71018de8d7fSPeter Avalos fake.pw_passwd = 71118de8d7fSPeter Avalos "$2a$06$r3.juUaHZDlIbQaO2dS9FuYxL1W9M81R1Tc92PoSNmzvpEqLkLGrK"; 71236e94dc5SPeter Avalos #ifdef HAVE_STRUCT_PASSWD_PW_GECOS 71318de8d7fSPeter Avalos fake.pw_gecos = "NOUSER"; 71436e94dc5SPeter Avalos #endif 71518de8d7fSPeter Avalos fake.pw_uid = privsep_pw == NULL ? (uid_t)-1 : privsep_pw->pw_uid; 71618de8d7fSPeter Avalos fake.pw_gid = privsep_pw == NULL ? (gid_t)-1 : privsep_pw->pw_gid; 71736e94dc5SPeter Avalos #ifdef HAVE_STRUCT_PASSWD_PW_CLASS 71818de8d7fSPeter Avalos fake.pw_class = ""; 71918de8d7fSPeter Avalos #endif 72018de8d7fSPeter Avalos fake.pw_dir = "/nonexist"; 72118de8d7fSPeter Avalos fake.pw_shell = "/nonexist"; 72218de8d7fSPeter Avalos 72318de8d7fSPeter Avalos return (&fake); 72418de8d7fSPeter Avalos } 725e9778795SPeter Avalos 726e9778795SPeter Avalos /* 727e9778795SPeter Avalos * Returns the remote DNS hostname as a string. The returned string must not 728e9778795SPeter Avalos * be freed. NB. this will usually trigger a DNS query the first time it is 729e9778795SPeter Avalos * called. 730e9778795SPeter Avalos * This function does additional checks on the hostname to mitigate some 731e9778795SPeter Avalos * attacks on legacy rhosts-style authentication. 732e9778795SPeter Avalos * XXX is RhostsRSAAuthentication vulnerable to these? 733e9778795SPeter Avalos * XXX Can we remove these checks? (or if not, remove RhostsRSAAuthentication?) 734e9778795SPeter Avalos */ 735e9778795SPeter Avalos 736e9778795SPeter Avalos static char * 737e9778795SPeter Avalos remote_hostname(struct ssh *ssh) 738e9778795SPeter Avalos { 739e9778795SPeter Avalos struct sockaddr_storage from; 740e9778795SPeter Avalos socklen_t fromlen; 741e9778795SPeter Avalos struct addrinfo hints, *ai, *aitop; 742e9778795SPeter Avalos char name[NI_MAXHOST], ntop2[NI_MAXHOST]; 743e9778795SPeter Avalos const char *ntop = ssh_remote_ipaddr(ssh); 744e9778795SPeter Avalos 745e9778795SPeter Avalos /* Get IP address of client. */ 746e9778795SPeter Avalos fromlen = sizeof(from); 747e9778795SPeter Avalos memset(&from, 0, sizeof(from)); 748e9778795SPeter Avalos if (getpeername(ssh_packet_get_connection_in(ssh), 749e9778795SPeter Avalos (struct sockaddr *)&from, &fromlen) < 0) { 750e9778795SPeter Avalos debug("getpeername failed: %.100s", strerror(errno)); 751e9778795SPeter Avalos return strdup(ntop); 752e9778795SPeter Avalos } 753e9778795SPeter Avalos 754e9778795SPeter Avalos ipv64_normalise_mapped(&from, &fromlen); 755e9778795SPeter Avalos if (from.ss_family == AF_INET6) 756e9778795SPeter Avalos fromlen = sizeof(struct sockaddr_in6); 757e9778795SPeter Avalos 758e9778795SPeter Avalos debug3("Trying to reverse map address %.100s.", ntop); 759e9778795SPeter Avalos /* Map the IP address to a host name. */ 760e9778795SPeter Avalos if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name), 761e9778795SPeter Avalos NULL, 0, NI_NAMEREQD) != 0) { 762e9778795SPeter Avalos /* Host name not found. Use ip address. */ 763e9778795SPeter Avalos return strdup(ntop); 764e9778795SPeter Avalos } 765e9778795SPeter Avalos 766e9778795SPeter Avalos /* 767e9778795SPeter Avalos * if reverse lookup result looks like a numeric hostname, 768e9778795SPeter Avalos * someone is trying to trick us by PTR record like following: 769e9778795SPeter Avalos * 1.1.1.10.in-addr.arpa. IN PTR 2.3.4.5 770e9778795SPeter Avalos */ 771e9778795SPeter Avalos memset(&hints, 0, sizeof(hints)); 772e9778795SPeter Avalos hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 773e9778795SPeter Avalos hints.ai_flags = AI_NUMERICHOST; 774e9778795SPeter Avalos if (getaddrinfo(name, NULL, &hints, &ai) == 0) { 775e9778795SPeter Avalos logit("Nasty PTR record \"%s\" is set up for %s, ignoring", 776e9778795SPeter Avalos name, ntop); 777e9778795SPeter Avalos freeaddrinfo(ai); 778e9778795SPeter Avalos return strdup(ntop); 779e9778795SPeter Avalos } 780e9778795SPeter Avalos 781e9778795SPeter Avalos /* Names are stored in lowercase. */ 782e9778795SPeter Avalos lowercase(name); 783e9778795SPeter Avalos 784e9778795SPeter Avalos /* 785e9778795SPeter Avalos * Map it back to an IP address and check that the given 786e9778795SPeter Avalos * address actually is an address of this host. This is 787e9778795SPeter Avalos * necessary because anyone with access to a name server can 788e9778795SPeter Avalos * define arbitrary names for an IP address. Mapping from 789e9778795SPeter Avalos * name to IP address can be trusted better (but can still be 790e9778795SPeter Avalos * fooled if the intruder has access to the name server of 791e9778795SPeter Avalos * the domain). 792e9778795SPeter Avalos */ 793e9778795SPeter Avalos memset(&hints, 0, sizeof(hints)); 794e9778795SPeter Avalos hints.ai_family = from.ss_family; 795e9778795SPeter Avalos hints.ai_socktype = SOCK_STREAM; 796e9778795SPeter Avalos if (getaddrinfo(name, NULL, &hints, &aitop) != 0) { 797e9778795SPeter Avalos logit("reverse mapping checking getaddrinfo for %.700s " 798e9778795SPeter Avalos "[%s] failed.", name, ntop); 799e9778795SPeter Avalos return strdup(ntop); 800e9778795SPeter Avalos } 801e9778795SPeter Avalos /* Look for the address from the list of addresses. */ 802e9778795SPeter Avalos for (ai = aitop; ai; ai = ai->ai_next) { 803e9778795SPeter Avalos if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2, 804e9778795SPeter Avalos sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 && 805e9778795SPeter Avalos (strcmp(ntop, ntop2) == 0)) 806e9778795SPeter Avalos break; 807e9778795SPeter Avalos } 808e9778795SPeter Avalos freeaddrinfo(aitop); 809e9778795SPeter Avalos /* If we reached the end of the list, the address was not there. */ 810e9778795SPeter Avalos if (ai == NULL) { 811e9778795SPeter Avalos /* Address not found for the host name. */ 812e9778795SPeter Avalos logit("Address %.100s maps to %.600s, but this does not " 813e9778795SPeter Avalos "map back to the address.", ntop, name); 814e9778795SPeter Avalos return strdup(ntop); 815e9778795SPeter Avalos } 816e9778795SPeter Avalos return strdup(name); 817e9778795SPeter Avalos } 818e9778795SPeter Avalos 819e9778795SPeter Avalos /* 820e9778795SPeter Avalos * Return the canonical name of the host in the other side of the current 821e9778795SPeter Avalos * connection. The host name is cached, so it is efficient to call this 822e9778795SPeter Avalos * several times. 823e9778795SPeter Avalos */ 824e9778795SPeter Avalos 825e9778795SPeter Avalos const char * 826e9778795SPeter Avalos auth_get_canonical_hostname(struct ssh *ssh, int use_dns) 827e9778795SPeter Avalos { 828e9778795SPeter Avalos static char *dnsname; 829e9778795SPeter Avalos 830e9778795SPeter Avalos if (!use_dns) 831e9778795SPeter Avalos return ssh_remote_ipaddr(ssh); 832e9778795SPeter Avalos else if (dnsname != NULL) 833e9778795SPeter Avalos return dnsname; 834e9778795SPeter Avalos else { 835e9778795SPeter Avalos dnsname = remote_hostname(ssh); 836e9778795SPeter Avalos return dnsname; 837e9778795SPeter Avalos } 838e9778795SPeter Avalos } 839*664f4763Szrj 840*664f4763Szrj /* 841*664f4763Szrj * Runs command in a subprocess with a minimal environment. 842*664f4763Szrj * Returns pid on success, 0 on failure. 843*664f4763Szrj * The child stdout and stderr maybe captured, left attached or sent to 844*664f4763Szrj * /dev/null depending on the contents of flags. 845*664f4763Szrj * "tag" is prepended to log messages. 846*664f4763Szrj * NB. "command" is only used for logging; the actual command executed is 847*664f4763Szrj * av[0]. 848*664f4763Szrj */ 849*664f4763Szrj pid_t 850*664f4763Szrj subprocess(const char *tag, struct passwd *pw, const char *command, 851*664f4763Szrj int ac, char **av, FILE **child, u_int flags) 852*664f4763Szrj { 853*664f4763Szrj FILE *f = NULL; 854*664f4763Szrj struct stat st; 855*664f4763Szrj int fd, devnull, p[2], i; 856*664f4763Szrj pid_t pid; 857*664f4763Szrj char *cp, errmsg[512]; 858*664f4763Szrj u_int envsize; 859*664f4763Szrj char **child_env; 860*664f4763Szrj 861*664f4763Szrj if (child != NULL) 862*664f4763Szrj *child = NULL; 863*664f4763Szrj 864*664f4763Szrj debug3("%s: %s command \"%s\" running as %s (flags 0x%x)", __func__, 865*664f4763Szrj tag, command, pw->pw_name, flags); 866*664f4763Szrj 867*664f4763Szrj /* Check consistency */ 868*664f4763Szrj if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0 && 869*664f4763Szrj (flags & SSH_SUBPROCESS_STDOUT_CAPTURE) != 0) { 870*664f4763Szrj error("%s: inconsistent flags", __func__); 871*664f4763Szrj return 0; 872*664f4763Szrj } 873*664f4763Szrj if (((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) == 0) != (child == NULL)) { 874*664f4763Szrj error("%s: inconsistent flags/output", __func__); 875*664f4763Szrj return 0; 876*664f4763Szrj } 877*664f4763Szrj 878*664f4763Szrj /* 879*664f4763Szrj * If executing an explicit binary, then verify the it exists 880*664f4763Szrj * and appears safe-ish to execute 881*664f4763Szrj */ 882*664f4763Szrj if (!path_absolute(av[0])) { 883*664f4763Szrj error("%s path is not absolute", tag); 884*664f4763Szrj return 0; 885*664f4763Szrj } 886*664f4763Szrj temporarily_use_uid(pw); 887*664f4763Szrj if (stat(av[0], &st) < 0) { 888*664f4763Szrj error("Could not stat %s \"%s\": %s", tag, 889*664f4763Szrj av[0], strerror(errno)); 890*664f4763Szrj restore_uid(); 891*664f4763Szrj return 0; 892*664f4763Szrj } 893*664f4763Szrj if (safe_path(av[0], &st, NULL, 0, errmsg, sizeof(errmsg)) != 0) { 894*664f4763Szrj error("Unsafe %s \"%s\": %s", tag, av[0], errmsg); 895*664f4763Szrj restore_uid(); 896*664f4763Szrj return 0; 897*664f4763Szrj } 898*664f4763Szrj /* Prepare to keep the child's stdout if requested */ 899*664f4763Szrj if (pipe(p) != 0) { 900*664f4763Szrj error("%s: pipe: %s", tag, strerror(errno)); 901*664f4763Szrj restore_uid(); 902*664f4763Szrj return 0; 903*664f4763Szrj } 904*664f4763Szrj restore_uid(); 905*664f4763Szrj 906*664f4763Szrj switch ((pid = fork())) { 907*664f4763Szrj case -1: /* error */ 908*664f4763Szrj error("%s: fork: %s", tag, strerror(errno)); 909*664f4763Szrj close(p[0]); 910*664f4763Szrj close(p[1]); 911*664f4763Szrj return 0; 912*664f4763Szrj case 0: /* child */ 913*664f4763Szrj /* Prepare a minimal environment for the child. */ 914*664f4763Szrj envsize = 5; 915*664f4763Szrj child_env = xcalloc(sizeof(*child_env), envsize); 916*664f4763Szrj child_set_env(&child_env, &envsize, "PATH", _PATH_STDPATH); 917*664f4763Szrj child_set_env(&child_env, &envsize, "USER", pw->pw_name); 918*664f4763Szrj child_set_env(&child_env, &envsize, "LOGNAME", pw->pw_name); 919*664f4763Szrj child_set_env(&child_env, &envsize, "HOME", pw->pw_dir); 920*664f4763Szrj if ((cp = getenv("LANG")) != NULL) 921*664f4763Szrj child_set_env(&child_env, &envsize, "LANG", cp); 922*664f4763Szrj 923*664f4763Szrj for (i = 0; i < NSIG; i++) 924*664f4763Szrj signal(i, SIG_DFL); 925*664f4763Szrj 926*664f4763Szrj if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) { 927*664f4763Szrj error("%s: open %s: %s", tag, _PATH_DEVNULL, 928*664f4763Szrj strerror(errno)); 929*664f4763Szrj _exit(1); 930*664f4763Szrj } 931*664f4763Szrj if (dup2(devnull, STDIN_FILENO) == -1) { 932*664f4763Szrj error("%s: dup2: %s", tag, strerror(errno)); 933*664f4763Szrj _exit(1); 934*664f4763Szrj } 935*664f4763Szrj 936*664f4763Szrj /* Set up stdout as requested; leave stderr in place for now. */ 937*664f4763Szrj fd = -1; 938*664f4763Szrj if ((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) != 0) 939*664f4763Szrj fd = p[1]; 940*664f4763Szrj else if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0) 941*664f4763Szrj fd = devnull; 942*664f4763Szrj if (fd != -1 && dup2(fd, STDOUT_FILENO) == -1) { 943*664f4763Szrj error("%s: dup2: %s", tag, strerror(errno)); 944*664f4763Szrj _exit(1); 945*664f4763Szrj } 946*664f4763Szrj closefrom(STDERR_FILENO + 1); 947*664f4763Szrj 948*664f4763Szrj /* Don't use permanently_set_uid() here to avoid fatal() */ 949*664f4763Szrj if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) { 950*664f4763Szrj error("%s: setresgid %u: %s", tag, (u_int)pw->pw_gid, 951*664f4763Szrj strerror(errno)); 952*664f4763Szrj _exit(1); 953*664f4763Szrj } 954*664f4763Szrj if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0) { 955*664f4763Szrj error("%s: setresuid %u: %s", tag, (u_int)pw->pw_uid, 956*664f4763Szrj strerror(errno)); 957*664f4763Szrj _exit(1); 958*664f4763Szrj } 959*664f4763Szrj /* stdin is pointed to /dev/null at this point */ 960*664f4763Szrj if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0 && 961*664f4763Szrj dup2(STDIN_FILENO, STDERR_FILENO) == -1) { 962*664f4763Szrj error("%s: dup2: %s", tag, strerror(errno)); 963*664f4763Szrj _exit(1); 964*664f4763Szrj } 965*664f4763Szrj 966*664f4763Szrj execve(av[0], av, child_env); 967*664f4763Szrj error("%s exec \"%s\": %s", tag, command, strerror(errno)); 968*664f4763Szrj _exit(127); 969*664f4763Szrj default: /* parent */ 970*664f4763Szrj break; 971*664f4763Szrj } 972*664f4763Szrj 973*664f4763Szrj close(p[1]); 974*664f4763Szrj if ((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) == 0) 975*664f4763Szrj close(p[0]); 976*664f4763Szrj else if ((f = fdopen(p[0], "r")) == NULL) { 977*664f4763Szrj error("%s: fdopen: %s", tag, strerror(errno)); 978*664f4763Szrj close(p[0]); 979*664f4763Szrj /* Don't leave zombie child */ 980*664f4763Szrj kill(pid, SIGTERM); 981*664f4763Szrj while (waitpid(pid, NULL, 0) == -1 && errno == EINTR) 982*664f4763Szrj ; 983*664f4763Szrj return 0; 984*664f4763Szrj } 985*664f4763Szrj /* Success */ 986*664f4763Szrj debug3("%s: %s pid %ld", __func__, tag, (long)pid); 987*664f4763Szrj if (child != NULL) 988*664f4763Szrj *child = f; 989*664f4763Szrj return pid; 990*664f4763Szrj } 991*664f4763Szrj 992*664f4763Szrj /* These functions link key/cert options to the auth framework */ 993*664f4763Szrj 994*664f4763Szrj /* Log sshauthopt options locally and (optionally) for remote transmission */ 995*664f4763Szrj void 996*664f4763Szrj auth_log_authopts(const char *loc, const struct sshauthopt *opts, int do_remote) 997*664f4763Szrj { 998*664f4763Szrj int do_env = options.permit_user_env && opts->nenv > 0; 999*664f4763Szrj int do_permitopen = opts->npermitopen > 0 && 1000*664f4763Szrj (options.allow_tcp_forwarding & FORWARD_LOCAL) != 0; 1001*664f4763Szrj int do_permitlisten = opts->npermitlisten > 0 && 1002*664f4763Szrj (options.allow_tcp_forwarding & FORWARD_REMOTE) != 0; 1003*664f4763Szrj size_t i; 1004*664f4763Szrj char msg[1024], buf[64]; 1005*664f4763Szrj 1006*664f4763Szrj snprintf(buf, sizeof(buf), "%d", opts->force_tun_device); 1007*664f4763Szrj /* Try to keep this alphabetically sorted */ 1008*664f4763Szrj snprintf(msg, sizeof(msg), "key options:%s%s%s%s%s%s%s%s%s%s%s%s%s", 1009*664f4763Szrj opts->permit_agent_forwarding_flag ? " agent-forwarding" : "", 1010*664f4763Szrj opts->force_command == NULL ? "" : " command", 1011*664f4763Szrj do_env ? " environment" : "", 1012*664f4763Szrj opts->valid_before == 0 ? "" : "expires", 1013*664f4763Szrj do_permitopen ? " permitopen" : "", 1014*664f4763Szrj do_permitlisten ? " permitlisten" : "", 1015*664f4763Szrj opts->permit_port_forwarding_flag ? " port-forwarding" : "", 1016*664f4763Szrj opts->cert_principals == NULL ? "" : " principals", 1017*664f4763Szrj opts->permit_pty_flag ? " pty" : "", 1018*664f4763Szrj opts->force_tun_device == -1 ? "" : " tun=", 1019*664f4763Szrj opts->force_tun_device == -1 ? "" : buf, 1020*664f4763Szrj opts->permit_user_rc ? " user-rc" : "", 1021*664f4763Szrj opts->permit_x11_forwarding_flag ? " x11-forwarding" : ""); 1022*664f4763Szrj 1023*664f4763Szrj debug("%s: %s", loc, msg); 1024*664f4763Szrj if (do_remote) 1025*664f4763Szrj auth_debug_add("%s: %s", loc, msg); 1026*664f4763Szrj 1027*664f4763Szrj if (options.permit_user_env) { 1028*664f4763Szrj for (i = 0; i < opts->nenv; i++) { 1029*664f4763Szrj debug("%s: environment: %s", loc, opts->env[i]); 1030*664f4763Szrj if (do_remote) { 1031*664f4763Szrj auth_debug_add("%s: environment: %s", 1032*664f4763Szrj loc, opts->env[i]); 1033*664f4763Szrj } 1034*664f4763Szrj } 1035*664f4763Szrj } 1036*664f4763Szrj 1037*664f4763Szrj /* Go into a little more details for the local logs. */ 1038*664f4763Szrj if (opts->valid_before != 0) { 1039*664f4763Szrj format_absolute_time(opts->valid_before, buf, sizeof(buf)); 1040*664f4763Szrj debug("%s: expires at %s", loc, buf); 1041*664f4763Szrj } 1042*664f4763Szrj if (opts->cert_principals != NULL) { 1043*664f4763Szrj debug("%s: authorized principals: \"%s\"", 1044*664f4763Szrj loc, opts->cert_principals); 1045*664f4763Szrj } 1046*664f4763Szrj if (opts->force_command != NULL) 1047*664f4763Szrj debug("%s: forced command: \"%s\"", loc, opts->force_command); 1048*664f4763Szrj if (do_permitopen) { 1049*664f4763Szrj for (i = 0; i < opts->npermitopen; i++) { 1050*664f4763Szrj debug("%s: permitted open: %s", 1051*664f4763Szrj loc, opts->permitopen[i]); 1052*664f4763Szrj } 1053*664f4763Szrj } 1054*664f4763Szrj if (do_permitlisten) { 1055*664f4763Szrj for (i = 0; i < opts->npermitlisten; i++) { 1056*664f4763Szrj debug("%s: permitted listen: %s", 1057*664f4763Szrj loc, opts->permitlisten[i]); 1058*664f4763Szrj } 1059*664f4763Szrj } 1060*664f4763Szrj } 1061*664f4763Szrj 1062*664f4763Szrj /* Activate a new set of key/cert options; merging with what is there. */ 1063*664f4763Szrj int 1064*664f4763Szrj auth_activate_options(struct ssh *ssh, struct sshauthopt *opts) 1065*664f4763Szrj { 1066*664f4763Szrj struct sshauthopt *old = auth_opts; 1067*664f4763Szrj const char *emsg = NULL; 1068*664f4763Szrj 1069*664f4763Szrj debug("%s: setting new authentication options", __func__); 1070*664f4763Szrj if ((auth_opts = sshauthopt_merge(old, opts, &emsg)) == NULL) { 1071*664f4763Szrj error("Inconsistent authentication options: %s", emsg); 1072*664f4763Szrj return -1; 1073*664f4763Szrj } 1074*664f4763Szrj return 0; 1075*664f4763Szrj } 1076*664f4763Szrj 1077*664f4763Szrj /* Disable forwarding, etc for the session */ 1078*664f4763Szrj void 1079*664f4763Szrj auth_restrict_session(struct ssh *ssh) 1080*664f4763Szrj { 1081*664f4763Szrj struct sshauthopt *restricted; 1082*664f4763Szrj 1083*664f4763Szrj debug("%s: restricting session", __func__); 1084*664f4763Szrj 1085*664f4763Szrj /* A blank sshauthopt defaults to permitting nothing */ 1086*664f4763Szrj restricted = sshauthopt_new(); 1087*664f4763Szrj restricted->permit_pty_flag = 1; 1088*664f4763Szrj restricted->restricted = 1; 1089*664f4763Szrj 1090*664f4763Szrj if (auth_activate_options(ssh, restricted) != 0) 1091*664f4763Szrj fatal("%s: failed to restrict session", __func__); 1092*664f4763Szrj sshauthopt_free(restricted); 1093*664f4763Szrj } 1094*664f4763Szrj 1095*664f4763Szrj int 1096*664f4763Szrj auth_authorise_keyopts(struct ssh *ssh, struct passwd *pw, 1097*664f4763Szrj struct sshauthopt *opts, int allow_cert_authority, const char *loc) 1098*664f4763Szrj { 1099*664f4763Szrj const char *remote_ip = ssh_remote_ipaddr(ssh); 1100*664f4763Szrj const char *remote_host = auth_get_canonical_hostname(ssh, 1101*664f4763Szrj options.use_dns); 1102*664f4763Szrj time_t now = time(NULL); 1103*664f4763Szrj char buf[64]; 1104*664f4763Szrj 1105*664f4763Szrj /* 1106*664f4763Szrj * Check keys/principals file expiry time. 1107*664f4763Szrj * NB. validity interval in certificate is handled elsewhere. 1108*664f4763Szrj */ 1109*664f4763Szrj if (opts->valid_before && now > 0 && 1110*664f4763Szrj opts->valid_before < (uint64_t)now) { 1111*664f4763Szrj format_absolute_time(opts->valid_before, buf, sizeof(buf)); 1112*664f4763Szrj debug("%s: entry expired at %s", loc, buf); 1113*664f4763Szrj auth_debug_add("%s: entry expired at %s", loc, buf); 1114*664f4763Szrj return -1; 1115*664f4763Szrj } 1116*664f4763Szrj /* Consistency checks */ 1117*664f4763Szrj if (opts->cert_principals != NULL && !opts->cert_authority) { 1118*664f4763Szrj debug("%s: principals on non-CA key", loc); 1119*664f4763Szrj auth_debug_add("%s: principals on non-CA key", loc); 1120*664f4763Szrj /* deny access */ 1121*664f4763Szrj return -1; 1122*664f4763Szrj } 1123*664f4763Szrj /* cert-authority flag isn't valid in authorized_principals files */ 1124*664f4763Szrj if (!allow_cert_authority && opts->cert_authority) { 1125*664f4763Szrj debug("%s: cert-authority flag invalid here", loc); 1126*664f4763Szrj auth_debug_add("%s: cert-authority flag invalid here", loc); 1127*664f4763Szrj /* deny access */ 1128*664f4763Szrj return -1; 1129*664f4763Szrj } 1130*664f4763Szrj 1131*664f4763Szrj /* Perform from= checks */ 1132*664f4763Szrj if (opts->required_from_host_keys != NULL) { 1133*664f4763Szrj switch (match_host_and_ip(remote_host, remote_ip, 1134*664f4763Szrj opts->required_from_host_keys )) { 1135*664f4763Szrj case 1: 1136*664f4763Szrj /* Host name matches. */ 1137*664f4763Szrj break; 1138*664f4763Szrj case -1: 1139*664f4763Szrj default: 1140*664f4763Szrj debug("%s: invalid from criteria", loc); 1141*664f4763Szrj auth_debug_add("%s: invalid from criteria", loc); 1142*664f4763Szrj /* FALLTHROUGH */ 1143*664f4763Szrj case 0: 1144*664f4763Szrj logit("%s: Authentication tried for %.100s with " 1145*664f4763Szrj "correct key but not from a permitted " 1146*664f4763Szrj "host (host=%.200s, ip=%.200s, required=%.200s).", 1147*664f4763Szrj loc, pw->pw_name, remote_host, remote_ip, 1148*664f4763Szrj opts->required_from_host_keys); 1149*664f4763Szrj auth_debug_add("%s: Your host '%.200s' is not " 1150*664f4763Szrj "permitted to use this key for login.", 1151*664f4763Szrj loc, remote_host); 1152*664f4763Szrj /* deny access */ 1153*664f4763Szrj return -1; 1154*664f4763Szrj } 1155*664f4763Szrj } 1156*664f4763Szrj /* Check source-address restriction from certificate */ 1157*664f4763Szrj if (opts->required_from_host_cert != NULL) { 1158*664f4763Szrj switch (addr_match_cidr_list(remote_ip, 1159*664f4763Szrj opts->required_from_host_cert)) { 1160*664f4763Szrj case 1: 1161*664f4763Szrj /* accepted */ 1162*664f4763Szrj break; 1163*664f4763Szrj case -1: 1164*664f4763Szrj default: 1165*664f4763Szrj /* invalid */ 1166*664f4763Szrj error("%s: Certificate source-address invalid", 1167*664f4763Szrj loc); 1168*664f4763Szrj /* FALLTHROUGH */ 1169*664f4763Szrj case 0: 1170*664f4763Szrj logit("%s: Authentication tried for %.100s with valid " 1171*664f4763Szrj "certificate but not from a permitted source " 1172*664f4763Szrj "address (%.200s).", loc, pw->pw_name, remote_ip); 1173*664f4763Szrj auth_debug_add("%s: Your address '%.200s' is not " 1174*664f4763Szrj "permitted to use this certificate for login.", 1175*664f4763Szrj loc, remote_ip); 1176*664f4763Szrj return -1; 1177*664f4763Szrj } 1178*664f4763Szrj } 1179*664f4763Szrj /* 1180*664f4763Szrj * 1181*664f4763Szrj * XXX this is spammy. We should report remotely only for keys 1182*664f4763Szrj * that are successful in actual auth attempts, and not PK_OK 1183*664f4763Szrj * tests. 1184*664f4763Szrj */ 1185*664f4763Szrj auth_log_authopts(loc, opts, 1); 1186*664f4763Szrj 1187*664f4763Szrj return 0; 1188*664f4763Szrj } 1189