1*ce74bacaSMatthew Dillon /* $OpenBSD: auth.c,v 1.124 2017/09/12 06:32:07 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> 3118de8d7fSPeter Avalos 3218de8d7fSPeter Avalos #include <netinet/in.h> 3318de8d7fSPeter Avalos 3418de8d7fSPeter Avalos #include <errno.h> 3518de8d7fSPeter Avalos #include <fcntl.h> 3618de8d7fSPeter Avalos #ifdef HAVE_PATHS_H 3718de8d7fSPeter Avalos # include <paths.h> 3818de8d7fSPeter Avalos #endif 3918de8d7fSPeter Avalos #include <pwd.h> 4018de8d7fSPeter Avalos #ifdef HAVE_LOGIN_H 4118de8d7fSPeter Avalos #include <login.h> 4218de8d7fSPeter Avalos #endif 4318de8d7fSPeter Avalos #ifdef USE_SHADOW 4418de8d7fSPeter Avalos #include <shadow.h> 4518de8d7fSPeter Avalos #endif 4618de8d7fSPeter Avalos #include <stdarg.h> 4718de8d7fSPeter Avalos #include <stdio.h> 4818de8d7fSPeter Avalos #include <string.h> 4918de8d7fSPeter Avalos #include <unistd.h> 50e9778795SPeter Avalos #include <limits.h> 51e9778795SPeter Avalos #include <netdb.h> 5218de8d7fSPeter Avalos 5318de8d7fSPeter Avalos #include "xmalloc.h" 5418de8d7fSPeter Avalos #include "match.h" 5518de8d7fSPeter Avalos #include "groupaccess.h" 5618de8d7fSPeter Avalos #include "log.h" 5718de8d7fSPeter Avalos #include "buffer.h" 5836e94dc5SPeter Avalos #include "misc.h" 5918de8d7fSPeter Avalos #include "servconf.h" 6018de8d7fSPeter Avalos #include "key.h" 6118de8d7fSPeter Avalos #include "hostfile.h" 6218de8d7fSPeter Avalos #include "auth.h" 6318de8d7fSPeter Avalos #include "auth-options.h" 6418de8d7fSPeter Avalos #include "canohost.h" 6518de8d7fSPeter Avalos #include "uidswap.h" 6618de8d7fSPeter Avalos #include "packet.h" 6718de8d7fSPeter Avalos #include "loginrec.h" 6818de8d7fSPeter Avalos #ifdef GSSAPI 6918de8d7fSPeter Avalos #include "ssh-gss.h" 7018de8d7fSPeter Avalos #endif 71856ea928SPeter Avalos #include "authfile.h" 7218de8d7fSPeter Avalos #include "monitor_wrap.h" 73e9778795SPeter Avalos #include "authfile.h" 74e9778795SPeter Avalos #include "ssherr.h" 7536e94dc5SPeter Avalos #include "compat.h" 7618de8d7fSPeter Avalos 7718de8d7fSPeter Avalos /* import */ 7818de8d7fSPeter Avalos extern ServerOptions options; 7918de8d7fSPeter Avalos extern int use_privsep; 8018de8d7fSPeter Avalos extern Buffer loginmsg; 8118de8d7fSPeter Avalos extern struct passwd *privsep_pw; 8218de8d7fSPeter Avalos 8318de8d7fSPeter Avalos /* Debugging messages */ 8418de8d7fSPeter Avalos Buffer auth_debug; 8518de8d7fSPeter Avalos int auth_debug_init; 8618de8d7fSPeter Avalos 8718de8d7fSPeter Avalos /* 8818de8d7fSPeter Avalos * Check if the user is allowed to log in via ssh. If user is listed 8918de8d7fSPeter Avalos * in DenyUsers or one of user's groups is listed in DenyGroups, false 9018de8d7fSPeter Avalos * will be returned. If AllowUsers isn't empty and user isn't listed 9118de8d7fSPeter Avalos * there, or if AllowGroups isn't empty and one of user's groups isn't 9218de8d7fSPeter Avalos * listed there, false will be returned. 9318de8d7fSPeter Avalos * If the user's shell is not executable, false will be returned. 9418de8d7fSPeter Avalos * Otherwise true is returned. 9518de8d7fSPeter Avalos */ 9618de8d7fSPeter Avalos int 9718de8d7fSPeter Avalos allowed_user(struct passwd * pw) 9818de8d7fSPeter Avalos { 99e9778795SPeter Avalos struct ssh *ssh = active_state; /* XXX */ 10018de8d7fSPeter Avalos struct stat st; 10118de8d7fSPeter Avalos const char *hostname = NULL, *ipaddr = NULL, *passwd = NULL; 10218de8d7fSPeter Avalos u_int i; 103*ce74bacaSMatthew Dillon int r; 10418de8d7fSPeter Avalos #ifdef USE_SHADOW 10518de8d7fSPeter Avalos struct spwd *spw = NULL; 10618de8d7fSPeter Avalos #endif 10718de8d7fSPeter Avalos 10818de8d7fSPeter Avalos /* Shouldn't be called if pw is NULL, but better safe than sorry... */ 10918de8d7fSPeter Avalos if (!pw || !pw->pw_name) 11018de8d7fSPeter Avalos return 0; 11118de8d7fSPeter Avalos 11218de8d7fSPeter Avalos #ifdef USE_SHADOW 11318de8d7fSPeter Avalos if (!options.use_pam) 11418de8d7fSPeter Avalos spw = getspnam(pw->pw_name); 11518de8d7fSPeter Avalos #ifdef HAS_SHADOW_EXPIRE 11618de8d7fSPeter Avalos if (!options.use_pam && spw != NULL && auth_shadow_acctexpired(spw)) 11718de8d7fSPeter Avalos return 0; 11818de8d7fSPeter Avalos #endif /* HAS_SHADOW_EXPIRE */ 11918de8d7fSPeter Avalos #endif /* USE_SHADOW */ 12018de8d7fSPeter Avalos 12118de8d7fSPeter Avalos /* grab passwd field for locked account check */ 12218de8d7fSPeter Avalos passwd = pw->pw_passwd; 12318de8d7fSPeter Avalos #ifdef USE_SHADOW 12418de8d7fSPeter Avalos if (spw != NULL) 12518de8d7fSPeter Avalos #ifdef USE_LIBIAF 12618de8d7fSPeter Avalos passwd = get_iaf_password(pw); 12718de8d7fSPeter Avalos #else 12818de8d7fSPeter Avalos passwd = spw->sp_pwdp; 12918de8d7fSPeter Avalos #endif /* USE_LIBIAF */ 13018de8d7fSPeter Avalos #endif 13118de8d7fSPeter Avalos 13218de8d7fSPeter Avalos /* check for locked account */ 13318de8d7fSPeter Avalos if (!options.use_pam && passwd && *passwd) { 13418de8d7fSPeter Avalos int locked = 0; 13518de8d7fSPeter Avalos 13618de8d7fSPeter Avalos #ifdef LOCKED_PASSWD_STRING 13718de8d7fSPeter Avalos if (strcmp(passwd, LOCKED_PASSWD_STRING) == 0) 13818de8d7fSPeter Avalos locked = 1; 13918de8d7fSPeter Avalos #endif 14018de8d7fSPeter Avalos #ifdef LOCKED_PASSWD_PREFIX 14118de8d7fSPeter Avalos if (strncmp(passwd, LOCKED_PASSWD_PREFIX, 14218de8d7fSPeter Avalos strlen(LOCKED_PASSWD_PREFIX)) == 0) 14318de8d7fSPeter Avalos locked = 1; 14418de8d7fSPeter Avalos #endif 14518de8d7fSPeter Avalos #ifdef LOCKED_PASSWD_SUBSTR 14618de8d7fSPeter Avalos if (strstr(passwd, LOCKED_PASSWD_SUBSTR)) 14718de8d7fSPeter Avalos locked = 1; 14818de8d7fSPeter Avalos #endif 14918de8d7fSPeter Avalos #ifdef USE_LIBIAF 150856ea928SPeter Avalos free((void *) passwd); 15118de8d7fSPeter Avalos #endif /* USE_LIBIAF */ 15218de8d7fSPeter Avalos if (locked) { 15318de8d7fSPeter Avalos logit("User %.100s not allowed because account is locked", 15418de8d7fSPeter Avalos pw->pw_name); 15518de8d7fSPeter Avalos return 0; 15618de8d7fSPeter Avalos } 15718de8d7fSPeter Avalos } 15818de8d7fSPeter Avalos 15918de8d7fSPeter Avalos /* 160856ea928SPeter Avalos * Deny if shell does not exist or is not executable unless we 161856ea928SPeter Avalos * are chrooting. 16218de8d7fSPeter Avalos */ 163856ea928SPeter Avalos if (options.chroot_directory == NULL || 164856ea928SPeter Avalos strcasecmp(options.chroot_directory, "none") == 0) { 165856ea928SPeter Avalos char *shell = xstrdup((pw->pw_shell[0] == '\0') ? 166856ea928SPeter Avalos _PATH_BSHELL : pw->pw_shell); /* empty = /bin/sh */ 16718de8d7fSPeter Avalos 16818de8d7fSPeter Avalos if (stat(shell, &st) != 0) { 169856ea928SPeter Avalos logit("User %.100s not allowed because shell %.100s " 170856ea928SPeter Avalos "does not exist", pw->pw_name, shell); 17136e94dc5SPeter Avalos free(shell); 17218de8d7fSPeter Avalos return 0; 17318de8d7fSPeter Avalos } 17418de8d7fSPeter Avalos if (S_ISREG(st.st_mode) == 0 || 17518de8d7fSPeter Avalos (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) { 176856ea928SPeter Avalos logit("User %.100s not allowed because shell %.100s " 177856ea928SPeter Avalos "is not executable", pw->pw_name, shell); 17836e94dc5SPeter Avalos free(shell); 17918de8d7fSPeter Avalos return 0; 18018de8d7fSPeter Avalos } 18136e94dc5SPeter Avalos free(shell); 182856ea928SPeter Avalos } 18318de8d7fSPeter Avalos 18418de8d7fSPeter Avalos if (options.num_deny_users > 0 || options.num_allow_users > 0 || 18518de8d7fSPeter Avalos options.num_deny_groups > 0 || options.num_allow_groups > 0) { 186e9778795SPeter Avalos hostname = auth_get_canonical_hostname(ssh, options.use_dns); 187e9778795SPeter Avalos ipaddr = ssh_remote_ipaddr(ssh); 18818de8d7fSPeter Avalos } 18918de8d7fSPeter Avalos 19018de8d7fSPeter Avalos /* Return false if user is listed in DenyUsers */ 19118de8d7fSPeter Avalos if (options.num_deny_users > 0) { 192*ce74bacaSMatthew Dillon for (i = 0; i < options.num_deny_users; i++) { 193*ce74bacaSMatthew Dillon r = match_user(pw->pw_name, hostname, ipaddr, 194*ce74bacaSMatthew Dillon options.deny_users[i]); 195*ce74bacaSMatthew Dillon if (r < 0) { 196*ce74bacaSMatthew Dillon fatal("Invalid DenyUsers pattern \"%.100s\"", 197*ce74bacaSMatthew Dillon options.deny_users[i]); 198*ce74bacaSMatthew Dillon } else if (r != 0) { 19918de8d7fSPeter Avalos logit("User %.100s from %.100s not allowed " 20018de8d7fSPeter Avalos "because listed in DenyUsers", 20118de8d7fSPeter Avalos pw->pw_name, hostname); 20218de8d7fSPeter Avalos return 0; 20318de8d7fSPeter Avalos } 20418de8d7fSPeter Avalos } 205*ce74bacaSMatthew Dillon } 20618de8d7fSPeter Avalos /* Return false if AllowUsers isn't empty and user isn't listed there */ 20718de8d7fSPeter Avalos if (options.num_allow_users > 0) { 208*ce74bacaSMatthew Dillon for (i = 0; i < options.num_allow_users; i++) { 209*ce74bacaSMatthew Dillon r = match_user(pw->pw_name, hostname, ipaddr, 210*ce74bacaSMatthew Dillon options.allow_users[i]); 211*ce74bacaSMatthew Dillon if (r < 0) { 212*ce74bacaSMatthew Dillon fatal("Invalid AllowUsers pattern \"%.100s\"", 213*ce74bacaSMatthew Dillon options.allow_users[i]); 214*ce74bacaSMatthew Dillon } else if (r == 1) 21518de8d7fSPeter Avalos break; 216*ce74bacaSMatthew Dillon } 21718de8d7fSPeter Avalos /* i < options.num_allow_users iff we break for loop */ 21818de8d7fSPeter Avalos if (i >= options.num_allow_users) { 21918de8d7fSPeter Avalos logit("User %.100s from %.100s not allowed because " 22018de8d7fSPeter Avalos "not listed in AllowUsers", pw->pw_name, hostname); 22118de8d7fSPeter Avalos return 0; 22218de8d7fSPeter Avalos } 22318de8d7fSPeter Avalos } 22418de8d7fSPeter Avalos if (options.num_deny_groups > 0 || options.num_allow_groups > 0) { 22518de8d7fSPeter Avalos /* Get the user's group access list (primary and supplementary) */ 22618de8d7fSPeter Avalos if (ga_init(pw->pw_name, pw->pw_gid) == 0) { 22718de8d7fSPeter Avalos logit("User %.100s from %.100s not allowed because " 22818de8d7fSPeter Avalos "not in any group", pw->pw_name, hostname); 22918de8d7fSPeter Avalos return 0; 23018de8d7fSPeter Avalos } 23118de8d7fSPeter Avalos 23218de8d7fSPeter Avalos /* Return false if one of user's groups is listed in DenyGroups */ 23318de8d7fSPeter Avalos if (options.num_deny_groups > 0) 23418de8d7fSPeter Avalos if (ga_match(options.deny_groups, 23518de8d7fSPeter Avalos options.num_deny_groups)) { 23618de8d7fSPeter Avalos ga_free(); 23718de8d7fSPeter Avalos logit("User %.100s from %.100s not allowed " 23818de8d7fSPeter Avalos "because a group is listed in DenyGroups", 23918de8d7fSPeter Avalos pw->pw_name, hostname); 24018de8d7fSPeter Avalos return 0; 24118de8d7fSPeter Avalos } 24218de8d7fSPeter Avalos /* 24318de8d7fSPeter Avalos * Return false if AllowGroups isn't empty and one of user's groups 24418de8d7fSPeter Avalos * isn't listed there 24518de8d7fSPeter Avalos */ 24618de8d7fSPeter Avalos if (options.num_allow_groups > 0) 24718de8d7fSPeter Avalos if (!ga_match(options.allow_groups, 24818de8d7fSPeter Avalos options.num_allow_groups)) { 24918de8d7fSPeter Avalos ga_free(); 25018de8d7fSPeter Avalos logit("User %.100s from %.100s not allowed " 25118de8d7fSPeter Avalos "because none of user's groups are listed " 25218de8d7fSPeter Avalos "in AllowGroups", pw->pw_name, hostname); 25318de8d7fSPeter Avalos return 0; 25418de8d7fSPeter Avalos } 25518de8d7fSPeter Avalos ga_free(); 25618de8d7fSPeter Avalos } 25718de8d7fSPeter Avalos 25818de8d7fSPeter Avalos #ifdef CUSTOM_SYS_AUTH_ALLOWED_USER 25918de8d7fSPeter Avalos if (!sys_auth_allowed_user(pw, &loginmsg)) 26018de8d7fSPeter Avalos return 0; 26118de8d7fSPeter Avalos #endif 26218de8d7fSPeter Avalos 26318de8d7fSPeter Avalos /* We found no reason not to let this user try to log on... */ 26418de8d7fSPeter Avalos return 1; 26518de8d7fSPeter Avalos } 26618de8d7fSPeter Avalos 267*ce74bacaSMatthew Dillon /* 268*ce74bacaSMatthew Dillon * Formats any key left in authctxt->auth_method_key for inclusion in 269*ce74bacaSMatthew Dillon * auth_log()'s message. Also includes authxtct->auth_method_info if present. 270*ce74bacaSMatthew Dillon */ 271*ce74bacaSMatthew Dillon static char * 272*ce74bacaSMatthew Dillon format_method_key(Authctxt *authctxt) 27336e94dc5SPeter Avalos { 274*ce74bacaSMatthew Dillon const struct sshkey *key = authctxt->auth_method_key; 275*ce74bacaSMatthew Dillon const char *methinfo = authctxt->auth_method_info; 276*ce74bacaSMatthew Dillon char *fp, *ret = NULL; 27736e94dc5SPeter Avalos 278*ce74bacaSMatthew Dillon if (key == NULL) 279*ce74bacaSMatthew Dillon return NULL; 28036e94dc5SPeter Avalos 281*ce74bacaSMatthew Dillon if (key_is_cert(key)) { 282*ce74bacaSMatthew Dillon fp = sshkey_fingerprint(key->cert->signature_key, 283*ce74bacaSMatthew Dillon options.fingerprint_hash, SSH_FP_DEFAULT); 284*ce74bacaSMatthew Dillon xasprintf(&ret, "%s ID %s (serial %llu) CA %s %s%s%s", 285*ce74bacaSMatthew Dillon sshkey_type(key), key->cert->key_id, 286*ce74bacaSMatthew Dillon (unsigned long long)key->cert->serial, 287*ce74bacaSMatthew Dillon sshkey_type(key->cert->signature_key), 288*ce74bacaSMatthew Dillon fp == NULL ? "(null)" : fp, 289*ce74bacaSMatthew Dillon methinfo == NULL ? "" : ", ", 290*ce74bacaSMatthew Dillon methinfo == NULL ? "" : methinfo); 291*ce74bacaSMatthew Dillon free(fp); 292*ce74bacaSMatthew Dillon } else { 293*ce74bacaSMatthew Dillon fp = sshkey_fingerprint(key, options.fingerprint_hash, 294*ce74bacaSMatthew Dillon SSH_FP_DEFAULT); 295*ce74bacaSMatthew Dillon xasprintf(&ret, "%s %s%s%s", sshkey_type(key), 296*ce74bacaSMatthew Dillon fp == NULL ? "(null)" : fp, 297*ce74bacaSMatthew Dillon methinfo == NULL ? "" : ", ", 298*ce74bacaSMatthew Dillon methinfo == NULL ? "" : methinfo); 299*ce74bacaSMatthew Dillon free(fp); 300*ce74bacaSMatthew Dillon } 301*ce74bacaSMatthew Dillon return ret; 30236e94dc5SPeter Avalos } 30336e94dc5SPeter Avalos 30436e94dc5SPeter Avalos void 30536e94dc5SPeter Avalos auth_log(Authctxt *authctxt, int authenticated, int partial, 30636e94dc5SPeter Avalos const char *method, const char *submethod) 30718de8d7fSPeter Avalos { 308e9778795SPeter Avalos struct ssh *ssh = active_state; /* XXX */ 30918de8d7fSPeter Avalos void (*authlog) (const char *fmt,...) = verbose; 310*ce74bacaSMatthew Dillon const char *authmsg; 311*ce74bacaSMatthew Dillon char *extra = NULL; 31218de8d7fSPeter Avalos 31318de8d7fSPeter Avalos if (use_privsep && !mm_is_monitor() && !authctxt->postponed) 31418de8d7fSPeter Avalos return; 31518de8d7fSPeter Avalos 31618de8d7fSPeter Avalos /* Raise logging level */ 31718de8d7fSPeter Avalos if (authenticated == 1 || 31818de8d7fSPeter Avalos !authctxt->valid || 31918de8d7fSPeter Avalos authctxt->failures >= options.max_authtries / 2 || 32018de8d7fSPeter Avalos strcmp(method, "password") == 0) 32118de8d7fSPeter Avalos authlog = logit; 32218de8d7fSPeter Avalos 32318de8d7fSPeter Avalos if (authctxt->postponed) 32418de8d7fSPeter Avalos authmsg = "Postponed"; 32536e94dc5SPeter Avalos else if (partial) 32636e94dc5SPeter Avalos authmsg = "Partial"; 32718de8d7fSPeter Avalos else 32818de8d7fSPeter Avalos authmsg = authenticated ? "Accepted" : "Failed"; 32918de8d7fSPeter Avalos 330*ce74bacaSMatthew Dillon if ((extra = format_method_key(authctxt)) == NULL) { 331*ce74bacaSMatthew Dillon if (authctxt->auth_method_info != NULL) 332*ce74bacaSMatthew Dillon extra = xstrdup(authctxt->auth_method_info); 333*ce74bacaSMatthew Dillon } 334*ce74bacaSMatthew Dillon 335*ce74bacaSMatthew Dillon authlog("%s %s%s%s for %s%.100s from %.200s port %d ssh2%s%s", 33618de8d7fSPeter Avalos authmsg, 33718de8d7fSPeter Avalos method, 33836e94dc5SPeter Avalos submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod, 33918de8d7fSPeter Avalos authctxt->valid ? "" : "invalid user ", 34018de8d7fSPeter Avalos authctxt->user, 341e9778795SPeter Avalos ssh_remote_ipaddr(ssh), 342e9778795SPeter Avalos ssh_remote_port(ssh), 343*ce74bacaSMatthew Dillon extra != NULL ? ": " : "", 344*ce74bacaSMatthew Dillon extra != NULL ? extra : ""); 345*ce74bacaSMatthew Dillon 346*ce74bacaSMatthew Dillon free(extra); 34718de8d7fSPeter Avalos 34818de8d7fSPeter Avalos #ifdef CUSTOM_FAILED_LOGIN 34918de8d7fSPeter Avalos if (authenticated == 0 && !authctxt->postponed && 35018de8d7fSPeter Avalos (strcmp(method, "password") == 0 || 35118de8d7fSPeter Avalos strncmp(method, "keyboard-interactive", 20) == 0 || 35218de8d7fSPeter Avalos strcmp(method, "challenge-response") == 0)) 35318de8d7fSPeter Avalos record_failed_login(authctxt->user, 354e9778795SPeter Avalos auth_get_canonical_hostname(ssh, options.use_dns), "ssh"); 35518de8d7fSPeter Avalos # ifdef WITH_AIXAUTHENTICATE 35618de8d7fSPeter Avalos if (authenticated) 35718de8d7fSPeter Avalos sys_auth_record_login(authctxt->user, 358e9778795SPeter Avalos auth_get_canonical_hostname(ssh, options.use_dns), "ssh", 359e9778795SPeter Avalos &loginmsg); 36018de8d7fSPeter Avalos # endif 36118de8d7fSPeter Avalos #endif 36218de8d7fSPeter Avalos #ifdef SSH_AUDIT_EVENTS 36318de8d7fSPeter Avalos if (authenticated == 0 && !authctxt->postponed) 36418de8d7fSPeter Avalos audit_event(audit_classify_auth(method)); 36518de8d7fSPeter Avalos #endif 36618de8d7fSPeter Avalos } 36718de8d7fSPeter Avalos 36836e94dc5SPeter Avalos 36936e94dc5SPeter Avalos void 37036e94dc5SPeter Avalos auth_maxtries_exceeded(Authctxt *authctxt) 37136e94dc5SPeter Avalos { 372e9778795SPeter Avalos struct ssh *ssh = active_state; /* XXX */ 373e9778795SPeter Avalos 374e9778795SPeter Avalos error("maximum authentication attempts exceeded for " 375*ce74bacaSMatthew Dillon "%s%.100s from %.200s port %d ssh2", 37636e94dc5SPeter Avalos authctxt->valid ? "" : "invalid user ", 37736e94dc5SPeter Avalos authctxt->user, 378e9778795SPeter Avalos ssh_remote_ipaddr(ssh), 379*ce74bacaSMatthew Dillon ssh_remote_port(ssh)); 380e9778795SPeter Avalos packet_disconnect("Too many authentication failures"); 38136e94dc5SPeter Avalos /* NOTREACHED */ 38236e94dc5SPeter Avalos } 38336e94dc5SPeter Avalos 38418de8d7fSPeter Avalos /* 38518de8d7fSPeter Avalos * Check whether root logins are disallowed. 38618de8d7fSPeter Avalos */ 38718de8d7fSPeter Avalos int 38836e94dc5SPeter Avalos auth_root_allowed(const char *method) 38918de8d7fSPeter Avalos { 390e9778795SPeter Avalos struct ssh *ssh = active_state; /* XXX */ 391e9778795SPeter Avalos 39218de8d7fSPeter Avalos switch (options.permit_root_login) { 39318de8d7fSPeter Avalos case PERMIT_YES: 39418de8d7fSPeter Avalos return 1; 39518de8d7fSPeter Avalos case PERMIT_NO_PASSWD: 396e9778795SPeter Avalos if (strcmp(method, "publickey") == 0 || 397e9778795SPeter Avalos strcmp(method, "hostbased") == 0 || 398e9778795SPeter Avalos strcmp(method, "gssapi-with-mic") == 0) 39918de8d7fSPeter Avalos return 1; 40018de8d7fSPeter Avalos break; 40118de8d7fSPeter Avalos case PERMIT_FORCED_ONLY: 40218de8d7fSPeter Avalos if (forced_command) { 40318de8d7fSPeter Avalos logit("Root login accepted for forced command."); 40418de8d7fSPeter Avalos return 1; 40518de8d7fSPeter Avalos } 40618de8d7fSPeter Avalos break; 40718de8d7fSPeter Avalos } 408e9778795SPeter Avalos logit("ROOT LOGIN REFUSED FROM %.200s port %d", 409e9778795SPeter Avalos ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); 41018de8d7fSPeter Avalos return 0; 41118de8d7fSPeter Avalos } 41218de8d7fSPeter Avalos 41318de8d7fSPeter Avalos 41418de8d7fSPeter Avalos /* 41518de8d7fSPeter Avalos * Given a template and a passwd structure, build a filename 41618de8d7fSPeter Avalos * by substituting % tokenised options. Currently, %% becomes '%', 41718de8d7fSPeter Avalos * %h becomes the home directory and %u the username. 41818de8d7fSPeter Avalos * 41918de8d7fSPeter Avalos * This returns a buffer allocated by xmalloc. 42018de8d7fSPeter Avalos */ 4211c188a7fSPeter Avalos char * 42218de8d7fSPeter Avalos expand_authorized_keys(const char *filename, struct passwd *pw) 42318de8d7fSPeter Avalos { 424e9778795SPeter Avalos char *file, ret[PATH_MAX]; 42518de8d7fSPeter Avalos int i; 42618de8d7fSPeter Avalos 42718de8d7fSPeter Avalos file = percent_expand(filename, "h", pw->pw_dir, 42818de8d7fSPeter Avalos "u", pw->pw_name, (char *)NULL); 42918de8d7fSPeter Avalos 43018de8d7fSPeter Avalos /* 43118de8d7fSPeter Avalos * Ensure that filename starts anchored. If not, be backward 43218de8d7fSPeter Avalos * compatible and prepend the '%h/' 43318de8d7fSPeter Avalos */ 43418de8d7fSPeter Avalos if (*file == '/') 43518de8d7fSPeter Avalos return (file); 43618de8d7fSPeter Avalos 43718de8d7fSPeter Avalos i = snprintf(ret, sizeof(ret), "%s/%s", pw->pw_dir, file); 43818de8d7fSPeter Avalos if (i < 0 || (size_t)i >= sizeof(ret)) 43918de8d7fSPeter Avalos fatal("expand_authorized_keys: path too long"); 44036e94dc5SPeter Avalos free(file); 44118de8d7fSPeter Avalos return (xstrdup(ret)); 44218de8d7fSPeter Avalos } 44318de8d7fSPeter Avalos 44418de8d7fSPeter Avalos char * 445856ea928SPeter Avalos authorized_principals_file(struct passwd *pw) 446856ea928SPeter Avalos { 447e9778795SPeter Avalos if (options.authorized_principals_file == NULL) 448856ea928SPeter Avalos return NULL; 449856ea928SPeter Avalos return expand_authorized_keys(options.authorized_principals_file, pw); 450856ea928SPeter Avalos } 451856ea928SPeter Avalos 45218de8d7fSPeter Avalos /* return ok if key exists in sysfile or userfile */ 45318de8d7fSPeter Avalos HostStatus 454*ce74bacaSMatthew Dillon check_key_in_hostfiles(struct passwd *pw, struct sshkey *key, const char *host, 45518de8d7fSPeter Avalos const char *sysfile, const char *userfile) 45618de8d7fSPeter Avalos { 45718de8d7fSPeter Avalos char *user_hostfile; 45818de8d7fSPeter Avalos struct stat st; 45918de8d7fSPeter Avalos HostStatus host_status; 4609f304aafSPeter Avalos struct hostkeys *hostkeys; 4619f304aafSPeter Avalos const struct hostkey_entry *found; 46218de8d7fSPeter Avalos 4639f304aafSPeter Avalos hostkeys = init_hostkeys(); 4649f304aafSPeter Avalos load_hostkeys(hostkeys, host, sysfile); 4659f304aafSPeter Avalos if (userfile != NULL) { 46618de8d7fSPeter Avalos user_hostfile = tilde_expand_filename(userfile, pw->pw_uid); 46718de8d7fSPeter Avalos if (options.strict_modes && 46818de8d7fSPeter Avalos (stat(user_hostfile, &st) == 0) && 46918de8d7fSPeter Avalos ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || 47018de8d7fSPeter Avalos (st.st_mode & 022) != 0)) { 47118de8d7fSPeter Avalos logit("Authentication refused for %.100s: " 47218de8d7fSPeter Avalos "bad owner or modes for %.200s", 47318de8d7fSPeter Avalos pw->pw_name, user_hostfile); 474856ea928SPeter Avalos auth_debug_add("Ignored %.200s: bad ownership or modes", 475856ea928SPeter Avalos user_hostfile); 47618de8d7fSPeter Avalos } else { 47718de8d7fSPeter Avalos temporarily_use_uid(pw); 4789f304aafSPeter Avalos load_hostkeys(hostkeys, host, user_hostfile); 47918de8d7fSPeter Avalos restore_uid(); 48018de8d7fSPeter Avalos } 48136e94dc5SPeter Avalos free(user_hostfile); 48218de8d7fSPeter Avalos } 4839f304aafSPeter Avalos host_status = check_key_in_hostkeys(hostkeys, key, &found); 4849f304aafSPeter Avalos if (host_status == HOST_REVOKED) 4859f304aafSPeter Avalos error("WARNING: revoked key for %s attempted authentication", 4869f304aafSPeter Avalos found->host); 4879f304aafSPeter Avalos else if (host_status == HOST_OK) 4889f304aafSPeter Avalos debug("%s: key for %s found at %s:%ld", __func__, 4899f304aafSPeter Avalos found->host, found->file, found->line); 4909f304aafSPeter Avalos else 4919f304aafSPeter Avalos debug("%s: key for host %s not found", __func__, host); 49218de8d7fSPeter Avalos 4939f304aafSPeter Avalos free_hostkeys(hostkeys); 4949f304aafSPeter Avalos 49518de8d7fSPeter Avalos return host_status; 49618de8d7fSPeter Avalos } 49718de8d7fSPeter Avalos 498856ea928SPeter Avalos static FILE * 499856ea928SPeter Avalos auth_openfile(const char *file, struct passwd *pw, int strict_modes, 500856ea928SPeter Avalos int log_missing, char *file_type) 50118de8d7fSPeter Avalos { 50218de8d7fSPeter Avalos char line[1024]; 50318de8d7fSPeter Avalos struct stat st; 50418de8d7fSPeter Avalos int fd; 50518de8d7fSPeter Avalos FILE *f; 50618de8d7fSPeter Avalos 507856ea928SPeter Avalos if ((fd = open(file, O_RDONLY|O_NONBLOCK)) == -1) { 508856ea928SPeter Avalos if (log_missing || errno != ENOENT) 509856ea928SPeter Avalos debug("Could not open %s '%s': %s", file_type, file, 510856ea928SPeter Avalos strerror(errno)); 51118de8d7fSPeter Avalos return NULL; 512856ea928SPeter Avalos } 51318de8d7fSPeter Avalos 51418de8d7fSPeter Avalos if (fstat(fd, &st) < 0) { 51518de8d7fSPeter Avalos close(fd); 51618de8d7fSPeter Avalos return NULL; 51718de8d7fSPeter Avalos } 51818de8d7fSPeter Avalos if (!S_ISREG(st.st_mode)) { 519856ea928SPeter Avalos logit("User %s %s %s is not a regular file", 520856ea928SPeter Avalos pw->pw_name, file_type, file); 52118de8d7fSPeter Avalos close(fd); 52218de8d7fSPeter Avalos return NULL; 52318de8d7fSPeter Avalos } 52418de8d7fSPeter Avalos unset_nonblock(fd); 52518de8d7fSPeter Avalos if ((f = fdopen(fd, "r")) == NULL) { 52618de8d7fSPeter Avalos close(fd); 52718de8d7fSPeter Avalos return NULL; 52818de8d7fSPeter Avalos } 5299f304aafSPeter Avalos if (strict_modes && 530*ce74bacaSMatthew Dillon safe_path_fd(fileno(f), file, pw, line, sizeof(line)) != 0) { 53118de8d7fSPeter Avalos fclose(f); 53218de8d7fSPeter Avalos logit("Authentication refused: %s", line); 533856ea928SPeter Avalos auth_debug_add("Ignored %s: %s", file_type, line); 53418de8d7fSPeter Avalos return NULL; 53518de8d7fSPeter Avalos } 53618de8d7fSPeter Avalos 53718de8d7fSPeter Avalos return f; 53818de8d7fSPeter Avalos } 53918de8d7fSPeter Avalos 540856ea928SPeter Avalos 541856ea928SPeter Avalos FILE * 542856ea928SPeter Avalos auth_openkeyfile(const char *file, struct passwd *pw, int strict_modes) 543856ea928SPeter Avalos { 544856ea928SPeter Avalos return auth_openfile(file, pw, strict_modes, 1, "authorized keys"); 545856ea928SPeter Avalos } 546856ea928SPeter Avalos 547856ea928SPeter Avalos FILE * 548856ea928SPeter Avalos auth_openprincipals(const char *file, struct passwd *pw, int strict_modes) 549856ea928SPeter Avalos { 550856ea928SPeter Avalos return auth_openfile(file, pw, strict_modes, 0, 551856ea928SPeter Avalos "authorized principals"); 552856ea928SPeter Avalos } 553856ea928SPeter Avalos 55418de8d7fSPeter Avalos struct passwd * 55518de8d7fSPeter Avalos getpwnamallow(const char *user) 55618de8d7fSPeter Avalos { 557e9778795SPeter Avalos struct ssh *ssh = active_state; /* XXX */ 55818de8d7fSPeter Avalos #ifdef HAVE_LOGIN_CAP 55918de8d7fSPeter Avalos extern login_cap_t *lc; 56018de8d7fSPeter Avalos #ifdef BSD_AUTH 56118de8d7fSPeter Avalos auth_session_t *as; 56218de8d7fSPeter Avalos #endif 56318de8d7fSPeter Avalos #endif 56418de8d7fSPeter Avalos struct passwd *pw; 56599e85e0dSPeter Avalos struct connection_info *ci = get_connection_info(1, options.use_dns); 56618de8d7fSPeter Avalos 56799e85e0dSPeter Avalos ci->user = user; 56899e85e0dSPeter Avalos parse_server_match_config(&options, ci); 569*ce74bacaSMatthew Dillon log_change_level(options.log_level); 570*ce74bacaSMatthew Dillon process_permitopen(ssh, &options); 57118de8d7fSPeter Avalos 572856ea928SPeter Avalos #if defined(_AIX) && defined(HAVE_SETAUTHDB) 573856ea928SPeter Avalos aix_setauthdb(user); 574856ea928SPeter Avalos #endif 575856ea928SPeter Avalos 57618de8d7fSPeter Avalos pw = getpwnam(user); 577856ea928SPeter Avalos 578856ea928SPeter Avalos #if defined(_AIX) && defined(HAVE_SETAUTHDB) 579856ea928SPeter Avalos aix_restoreauthdb(); 580856ea928SPeter Avalos #endif 581856ea928SPeter Avalos #ifdef HAVE_CYGWIN 582856ea928SPeter Avalos /* 583856ea928SPeter Avalos * Windows usernames are case-insensitive. To avoid later problems 584856ea928SPeter Avalos * when trying to match the username, the user is only allowed to 585856ea928SPeter Avalos * login if the username is given in the same case as stored in the 586856ea928SPeter Avalos * user database. 587856ea928SPeter Avalos */ 588856ea928SPeter Avalos if (pw != NULL && strcmp(user, pw->pw_name) != 0) { 589856ea928SPeter Avalos logit("Login name %.100s does not match stored username %.100s", 590856ea928SPeter Avalos user, pw->pw_name); 591856ea928SPeter Avalos pw = NULL; 592856ea928SPeter Avalos } 593856ea928SPeter Avalos #endif 59418de8d7fSPeter Avalos if (pw == NULL) { 595e9778795SPeter Avalos logit("Invalid user %.100s from %.100s port %d", 596e9778795SPeter Avalos user, ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); 59718de8d7fSPeter Avalos #ifdef CUSTOM_FAILED_LOGIN 59818de8d7fSPeter Avalos record_failed_login(user, 599e9778795SPeter Avalos auth_get_canonical_hostname(ssh, options.use_dns), "ssh"); 60018de8d7fSPeter Avalos #endif 60118de8d7fSPeter Avalos #ifdef SSH_AUDIT_EVENTS 60218de8d7fSPeter Avalos audit_event(SSH_INVALID_USER); 60318de8d7fSPeter Avalos #endif /* SSH_AUDIT_EVENTS */ 60418de8d7fSPeter Avalos return (NULL); 60518de8d7fSPeter Avalos } 60618de8d7fSPeter Avalos if (!allowed_user(pw)) 60718de8d7fSPeter Avalos return (NULL); 60818de8d7fSPeter Avalos #ifdef HAVE_LOGIN_CAP 60918de8d7fSPeter Avalos if ((lc = login_getclass(pw->pw_class)) == NULL) { 61018de8d7fSPeter Avalos debug("unable to get login class: %s", user); 61118de8d7fSPeter Avalos return (NULL); 61218de8d7fSPeter Avalos } 61318de8d7fSPeter Avalos #ifdef BSD_AUTH 61418de8d7fSPeter Avalos if ((as = auth_open()) == NULL || auth_setpwd(as, pw) != 0 || 61518de8d7fSPeter Avalos auth_approval(as, lc, pw->pw_name, "ssh") <= 0) { 61618de8d7fSPeter Avalos debug("Approval failure for %s", user); 61718de8d7fSPeter Avalos pw = NULL; 61818de8d7fSPeter Avalos } 61918de8d7fSPeter Avalos if (as != NULL) 62018de8d7fSPeter Avalos auth_close(as); 62118de8d7fSPeter Avalos #endif 62218de8d7fSPeter Avalos #endif 62318de8d7fSPeter Avalos if (pw != NULL) 62418de8d7fSPeter Avalos return (pwcopy(pw)); 62518de8d7fSPeter Avalos return (NULL); 62618de8d7fSPeter Avalos } 62718de8d7fSPeter Avalos 628856ea928SPeter Avalos /* Returns 1 if key is revoked by revoked_keys_file, 0 otherwise */ 629856ea928SPeter Avalos int 630*ce74bacaSMatthew Dillon auth_key_is_revoked(struct sshkey *key) 631856ea928SPeter Avalos { 632e9778795SPeter Avalos char *fp = NULL; 633e9778795SPeter Avalos int r; 634856ea928SPeter Avalos 635856ea928SPeter Avalos if (options.revoked_keys_file == NULL) 636856ea928SPeter Avalos return 0; 637e9778795SPeter Avalos if ((fp = sshkey_fingerprint(key, options.fingerprint_hash, 638e9778795SPeter Avalos SSH_FP_DEFAULT)) == NULL) { 639e9778795SPeter Avalos r = SSH_ERR_ALLOC_FAIL; 640e9778795SPeter Avalos error("%s: fingerprint key: %s", __func__, ssh_err(r)); 641e9778795SPeter Avalos goto out; 642e9778795SPeter Avalos } 643e9778795SPeter Avalos 644e9778795SPeter Avalos r = sshkey_check_revoked(key, options.revoked_keys_file); 645e9778795SPeter Avalos switch (r) { 64636e94dc5SPeter Avalos case 0: 647e9778795SPeter Avalos break; /* not revoked */ 648e9778795SPeter Avalos case SSH_ERR_KEY_REVOKED: 649e9778795SPeter Avalos error("Authentication key %s %s revoked by file %s", 650e9778795SPeter Avalos sshkey_type(key), fp, options.revoked_keys_file); 651e9778795SPeter Avalos goto out; 65236e94dc5SPeter Avalos default: 653e9778795SPeter Avalos error("Error checking authentication key %s %s in " 654e9778795SPeter Avalos "revoked keys file %s: %s", sshkey_type(key), fp, 655e9778795SPeter Avalos options.revoked_keys_file, ssh_err(r)); 656e9778795SPeter Avalos goto out; 65736e94dc5SPeter Avalos } 658e9778795SPeter Avalos 659e9778795SPeter Avalos /* Success */ 660e9778795SPeter Avalos r = 0; 661e9778795SPeter Avalos 662e9778795SPeter Avalos out: 663e9778795SPeter Avalos free(fp); 664e9778795SPeter Avalos return r == 0 ? 0 : 1; 665856ea928SPeter Avalos } 666856ea928SPeter Avalos 66718de8d7fSPeter Avalos void 66818de8d7fSPeter Avalos auth_debug_add(const char *fmt,...) 66918de8d7fSPeter Avalos { 67018de8d7fSPeter Avalos char buf[1024]; 67118de8d7fSPeter Avalos va_list args; 67218de8d7fSPeter Avalos 67318de8d7fSPeter Avalos if (!auth_debug_init) 67418de8d7fSPeter Avalos return; 67518de8d7fSPeter Avalos 67618de8d7fSPeter Avalos va_start(args, fmt); 67718de8d7fSPeter Avalos vsnprintf(buf, sizeof(buf), fmt, args); 67818de8d7fSPeter Avalos va_end(args); 67918de8d7fSPeter Avalos buffer_put_cstring(&auth_debug, buf); 68018de8d7fSPeter Avalos } 68118de8d7fSPeter Avalos 68218de8d7fSPeter Avalos void 68318de8d7fSPeter Avalos auth_debug_send(void) 68418de8d7fSPeter Avalos { 68518de8d7fSPeter Avalos char *msg; 68618de8d7fSPeter Avalos 68718de8d7fSPeter Avalos if (!auth_debug_init) 68818de8d7fSPeter Avalos return; 68918de8d7fSPeter Avalos while (buffer_len(&auth_debug)) { 69018de8d7fSPeter Avalos msg = buffer_get_string(&auth_debug, NULL); 69118de8d7fSPeter Avalos packet_send_debug("%s", msg); 69236e94dc5SPeter Avalos free(msg); 69318de8d7fSPeter Avalos } 69418de8d7fSPeter Avalos } 69518de8d7fSPeter Avalos 69618de8d7fSPeter Avalos void 69718de8d7fSPeter Avalos auth_debug_reset(void) 69818de8d7fSPeter Avalos { 69918de8d7fSPeter Avalos if (auth_debug_init) 70018de8d7fSPeter Avalos buffer_clear(&auth_debug); 70118de8d7fSPeter Avalos else { 70218de8d7fSPeter Avalos buffer_init(&auth_debug); 70318de8d7fSPeter Avalos auth_debug_init = 1; 70418de8d7fSPeter Avalos } 70518de8d7fSPeter Avalos } 70618de8d7fSPeter Avalos 70718de8d7fSPeter Avalos struct passwd * 70818de8d7fSPeter Avalos fakepw(void) 70918de8d7fSPeter Avalos { 71018de8d7fSPeter Avalos static struct passwd fake; 71118de8d7fSPeter Avalos 71218de8d7fSPeter Avalos memset(&fake, 0, sizeof(fake)); 71318de8d7fSPeter Avalos fake.pw_name = "NOUSER"; 71418de8d7fSPeter Avalos fake.pw_passwd = 71518de8d7fSPeter Avalos "$2a$06$r3.juUaHZDlIbQaO2dS9FuYxL1W9M81R1Tc92PoSNmzvpEqLkLGrK"; 71636e94dc5SPeter Avalos #ifdef HAVE_STRUCT_PASSWD_PW_GECOS 71718de8d7fSPeter Avalos fake.pw_gecos = "NOUSER"; 71836e94dc5SPeter Avalos #endif 71918de8d7fSPeter Avalos fake.pw_uid = privsep_pw == NULL ? (uid_t)-1 : privsep_pw->pw_uid; 72018de8d7fSPeter Avalos fake.pw_gid = privsep_pw == NULL ? (gid_t)-1 : privsep_pw->pw_gid; 72136e94dc5SPeter Avalos #ifdef HAVE_STRUCT_PASSWD_PW_CLASS 72218de8d7fSPeter Avalos fake.pw_class = ""; 72318de8d7fSPeter Avalos #endif 72418de8d7fSPeter Avalos fake.pw_dir = "/nonexist"; 72518de8d7fSPeter Avalos fake.pw_shell = "/nonexist"; 72618de8d7fSPeter Avalos 72718de8d7fSPeter Avalos return (&fake); 72818de8d7fSPeter Avalos } 729e9778795SPeter Avalos 730e9778795SPeter Avalos /* 731e9778795SPeter Avalos * Returns the remote DNS hostname as a string. The returned string must not 732e9778795SPeter Avalos * be freed. NB. this will usually trigger a DNS query the first time it is 733e9778795SPeter Avalos * called. 734e9778795SPeter Avalos * This function does additional checks on the hostname to mitigate some 735e9778795SPeter Avalos * attacks on legacy rhosts-style authentication. 736e9778795SPeter Avalos * XXX is RhostsRSAAuthentication vulnerable to these? 737e9778795SPeter Avalos * XXX Can we remove these checks? (or if not, remove RhostsRSAAuthentication?) 738e9778795SPeter Avalos */ 739e9778795SPeter Avalos 740e9778795SPeter Avalos static char * 741e9778795SPeter Avalos remote_hostname(struct ssh *ssh) 742e9778795SPeter Avalos { 743e9778795SPeter Avalos struct sockaddr_storage from; 744e9778795SPeter Avalos socklen_t fromlen; 745e9778795SPeter Avalos struct addrinfo hints, *ai, *aitop; 746e9778795SPeter Avalos char name[NI_MAXHOST], ntop2[NI_MAXHOST]; 747e9778795SPeter Avalos const char *ntop = ssh_remote_ipaddr(ssh); 748e9778795SPeter Avalos 749e9778795SPeter Avalos /* Get IP address of client. */ 750e9778795SPeter Avalos fromlen = sizeof(from); 751e9778795SPeter Avalos memset(&from, 0, sizeof(from)); 752e9778795SPeter Avalos if (getpeername(ssh_packet_get_connection_in(ssh), 753e9778795SPeter Avalos (struct sockaddr *)&from, &fromlen) < 0) { 754e9778795SPeter Avalos debug("getpeername failed: %.100s", strerror(errno)); 755e9778795SPeter Avalos return strdup(ntop); 756e9778795SPeter Avalos } 757e9778795SPeter Avalos 758e9778795SPeter Avalos ipv64_normalise_mapped(&from, &fromlen); 759e9778795SPeter Avalos if (from.ss_family == AF_INET6) 760e9778795SPeter Avalos fromlen = sizeof(struct sockaddr_in6); 761e9778795SPeter Avalos 762e9778795SPeter Avalos debug3("Trying to reverse map address %.100s.", ntop); 763e9778795SPeter Avalos /* Map the IP address to a host name. */ 764e9778795SPeter Avalos if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name), 765e9778795SPeter Avalos NULL, 0, NI_NAMEREQD) != 0) { 766e9778795SPeter Avalos /* Host name not found. Use ip address. */ 767e9778795SPeter Avalos return strdup(ntop); 768e9778795SPeter Avalos } 769e9778795SPeter Avalos 770e9778795SPeter Avalos /* 771e9778795SPeter Avalos * if reverse lookup result looks like a numeric hostname, 772e9778795SPeter Avalos * someone is trying to trick us by PTR record like following: 773e9778795SPeter Avalos * 1.1.1.10.in-addr.arpa. IN PTR 2.3.4.5 774e9778795SPeter Avalos */ 775e9778795SPeter Avalos memset(&hints, 0, sizeof(hints)); 776e9778795SPeter Avalos hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 777e9778795SPeter Avalos hints.ai_flags = AI_NUMERICHOST; 778e9778795SPeter Avalos if (getaddrinfo(name, NULL, &hints, &ai) == 0) { 779e9778795SPeter Avalos logit("Nasty PTR record \"%s\" is set up for %s, ignoring", 780e9778795SPeter Avalos name, ntop); 781e9778795SPeter Avalos freeaddrinfo(ai); 782e9778795SPeter Avalos return strdup(ntop); 783e9778795SPeter Avalos } 784e9778795SPeter Avalos 785e9778795SPeter Avalos /* Names are stored in lowercase. */ 786e9778795SPeter Avalos lowercase(name); 787e9778795SPeter Avalos 788e9778795SPeter Avalos /* 789e9778795SPeter Avalos * Map it back to an IP address and check that the given 790e9778795SPeter Avalos * address actually is an address of this host. This is 791e9778795SPeter Avalos * necessary because anyone with access to a name server can 792e9778795SPeter Avalos * define arbitrary names for an IP address. Mapping from 793e9778795SPeter Avalos * name to IP address can be trusted better (but can still be 794e9778795SPeter Avalos * fooled if the intruder has access to the name server of 795e9778795SPeter Avalos * the domain). 796e9778795SPeter Avalos */ 797e9778795SPeter Avalos memset(&hints, 0, sizeof(hints)); 798e9778795SPeter Avalos hints.ai_family = from.ss_family; 799e9778795SPeter Avalos hints.ai_socktype = SOCK_STREAM; 800e9778795SPeter Avalos if (getaddrinfo(name, NULL, &hints, &aitop) != 0) { 801e9778795SPeter Avalos logit("reverse mapping checking getaddrinfo for %.700s " 802e9778795SPeter Avalos "[%s] failed.", name, ntop); 803e9778795SPeter Avalos return strdup(ntop); 804e9778795SPeter Avalos } 805e9778795SPeter Avalos /* Look for the address from the list of addresses. */ 806e9778795SPeter Avalos for (ai = aitop; ai; ai = ai->ai_next) { 807e9778795SPeter Avalos if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2, 808e9778795SPeter Avalos sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 && 809e9778795SPeter Avalos (strcmp(ntop, ntop2) == 0)) 810e9778795SPeter Avalos break; 811e9778795SPeter Avalos } 812e9778795SPeter Avalos freeaddrinfo(aitop); 813e9778795SPeter Avalos /* If we reached the end of the list, the address was not there. */ 814e9778795SPeter Avalos if (ai == NULL) { 815e9778795SPeter Avalos /* Address not found for the host name. */ 816e9778795SPeter Avalos logit("Address %.100s maps to %.600s, but this does not " 817e9778795SPeter Avalos "map back to the address.", ntop, name); 818e9778795SPeter Avalos return strdup(ntop); 819e9778795SPeter Avalos } 820e9778795SPeter Avalos return strdup(name); 821e9778795SPeter Avalos } 822e9778795SPeter Avalos 823e9778795SPeter Avalos /* 824e9778795SPeter Avalos * Return the canonical name of the host in the other side of the current 825e9778795SPeter Avalos * connection. The host name is cached, so it is efficient to call this 826e9778795SPeter Avalos * several times. 827e9778795SPeter Avalos */ 828e9778795SPeter Avalos 829e9778795SPeter Avalos const char * 830e9778795SPeter Avalos auth_get_canonical_hostname(struct ssh *ssh, int use_dns) 831e9778795SPeter Avalos { 832e9778795SPeter Avalos static char *dnsname; 833e9778795SPeter Avalos 834e9778795SPeter Avalos if (!use_dns) 835e9778795SPeter Avalos return ssh_remote_ipaddr(ssh); 836e9778795SPeter Avalos else if (dnsname != NULL) 837e9778795SPeter Avalos return dnsname; 838e9778795SPeter Avalos else { 839e9778795SPeter Avalos dnsname = remote_hostname(ssh); 840e9778795SPeter Avalos return dnsname; 841e9778795SPeter Avalos } 842e9778795SPeter Avalos } 843