blob: 55629b320b84d536eec2a74e23c72b016bcc8f94 [file] [log] [blame]
djm@openbsd.org95767262016-03-07 19:02:43 +00001/* $OpenBSD: auth.c,v 1.114 2016/03/07 19:02:43 djm Exp $ */
Damien Miller116e6df2002-05-22 15:06:28 +10002/*
Ben Lindstrom92a2e382001-03-05 06:59:27 +00003 * Copyright (c) 2000 Markus Friedl. All rights reserved.
Damien Millere4340be2000-09-16 13:29:08 +11004 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Damien Millerb38eff82000-04-01 11:09:21 +100024 */
25
26#include "includes.h"
Damien Millerf17883e2006-03-15 11:45:54 +110027
28#include <sys/types.h>
29#include <sys/stat.h>
djm@openbsd.org95767262016-03-07 19:02:43 +000030#include <sys/socket.h>
Damien Millerb38eff82000-04-01 11:09:21 +100031
Damien Miller36cbe412006-08-05 12:54:24 +100032#include <netinet/in.h>
33
Darren Tucker39972492006-07-12 22:22:46 +100034#include <errno.h>
Darren Tucker33c787f2008-07-02 22:37:30 +100035#include <fcntl.h>
Damien Miller03e20032006-03-15 11:16:59 +110036#ifdef HAVE_PATHS_H
Damien Millera9263d02006-03-15 11:18:26 +110037# include <paths.h>
Damien Miller03e20032006-03-15 11:16:59 +110038#endif
Damien Miller9f2abc42006-07-10 20:53:08 +100039#include <pwd.h>
Damien Millerd2c208a2000-05-17 22:00:02 +100040#ifdef HAVE_LOGIN_H
41#include <login.h>
42#endif
Darren Tucker15ee7482004-02-22 09:43:15 +110043#ifdef USE_SHADOW
Damien Miller1f335fb2000-06-26 11:31:33 +100044#include <shadow.h>
Darren Tucker15ee7482004-02-22 09:43:15 +110045#endif
Ben Lindstrom68c3ce12001-06-10 17:24:51 +000046#ifdef HAVE_LIBGEN_H
Ben Lindstrombfb3a0e2001-06-05 20:25:05 +000047#include <libgen.h>
Ben Lindstrom68c3ce12001-06-10 17:24:51 +000048#endif
Darren Tucker5d196262006-07-12 22:15:16 +100049#include <stdarg.h>
Damien Millera7a73ee2006-08-05 11:37:59 +100050#include <stdio.h>
Damien Millere3476ed2006-07-24 14:13:33 +100051#include <string.h>
Damien Miller7acf5502008-07-09 20:54:37 +100052#include <unistd.h>
deraadt@openbsd.org087266e2015-01-20 23:14:00 +000053#include <limits.h>
djm@openbsd.org95767262016-03-07 19:02:43 +000054#include <netdb.h>
Ben Lindstrombfb3a0e2001-06-05 20:25:05 +000055
Ben Lindstrom226cfa02001-01-22 05:34:40 +000056#include "xmalloc.h"
57#include "match.h"
58#include "groupaccess.h"
59#include "log.h"
Damien Millerd7834352006-08-05 12:39:39 +100060#include "buffer.h"
Damien Miller7acefbb2014-07-18 14:11:24 +100061#include "misc.h"
Ben Lindstrom226cfa02001-01-22 05:34:40 +000062#include "servconf.h"
Damien Millerd7834352006-08-05 12:39:39 +100063#include "key.h"
64#include "hostfile.h"
Damien Millerefb4afe2000-04-12 18:45:05 +100065#include "auth.h"
Ben Lindstromdb65e8f2001-01-19 04:26:52 +000066#include "auth-options.h"
Ben Lindstrom226cfa02001-01-22 05:34:40 +000067#include "canohost.h"
Ben Lindstrom83647ce2001-06-25 04:30:16 +000068#include "uidswap.h"
Ben Lindstroma574cda2002-05-15 16:16:14 +000069#include "packet.h"
Darren Tucker42d9dc72005-02-02 17:10:11 +110070#include "loginrec.h"
Damien Millerd7834352006-08-05 12:39:39 +100071#ifdef GSSAPI
72#include "ssh-gss.h"
73#endif
Damien Miller1aed65e2010-03-04 21:53:35 +110074#include "authfile.h"
Darren Tucker269a1ea2005-02-03 00:20:53 +110075#include "monitor_wrap.h"
djm@openbsd.org5e39a492014-12-04 02:24:32 +000076#include "authfile.h"
77#include "ssherr.h"
Darren Tucker0acca372013-06-02 07:41:51 +100078#include "compat.h"
Damien Millerefb4afe2000-04-12 18:45:05 +100079
Damien Millerb38eff82000-04-01 11:09:21 +100080/* import */
81extern ServerOptions options;
Damien Miller7a8f5b32006-03-31 23:14:23 +110082extern int use_privsep;
Darren Tuckerb9aa0a02003-07-08 22:59:59 +100083extern Buffer loginmsg;
Damien Miller6433df02006-09-07 10:36:43 +100084extern struct passwd *privsep_pw;
Damien Millerb38eff82000-04-01 11:09:21 +100085
Ben Lindstroma574cda2002-05-15 16:16:14 +000086/* Debugging messages */
87Buffer auth_debug;
88int auth_debug_init;
89
Damien Millerb38eff82000-04-01 11:09:21 +100090/*
Kevin Steves7b61cfa2001-01-14 19:11:00 +000091 * Check if the user is allowed to log in via ssh. If user is listed
92 * in DenyUsers or one of user's groups is listed in DenyGroups, false
93 * will be returned. If AllowUsers isn't empty and user isn't listed
94 * there, or if AllowGroups isn't empty and one of user's groups isn't
95 * listed there, false will be returned.
Damien Millerb38eff82000-04-01 11:09:21 +100096 * If the user's shell is not executable, false will be returned.
Damien Miller4af51302000-04-16 11:18:38 +100097 * Otherwise true is returned.
Damien Millerb38eff82000-04-01 11:09:21 +100098 */
Damien Millereba71ba2000-04-29 23:57:08 +100099int
Damien Millerb38eff82000-04-01 11:09:21 +1000100allowed_user(struct passwd * pw)
101{
djm@openbsd.org95767262016-03-07 19:02:43 +0000102 struct ssh *ssh = active_state; /* XXX */
Damien Millerb38eff82000-04-01 11:09:21 +1000103 struct stat st;
Darren Tucker43a0dc62003-08-26 14:22:12 +1000104 const char *hostname = NULL, *ipaddr = NULL, *passwd = NULL;
Damien Millereccb9de2005-06-17 12:59:34 +1000105 u_int i;
Darren Tucker15ee7482004-02-22 09:43:15 +1100106#ifdef USE_SHADOW
Darren Tuckere41bba52003-08-25 11:51:19 +1000107 struct spwd *spw = NULL;
Tim Rice458c6bf2003-01-08 20:04:27 -0800108#endif
Damien Millerb38eff82000-04-01 11:09:21 +1000109
110 /* Shouldn't be called if pw is NULL, but better safe than sorry... */
Kevin Steves7b61cfa2001-01-14 19:11:00 +0000111 if (!pw || !pw->pw_name)
Damien Millerb38eff82000-04-01 11:09:21 +1000112 return 0;
113
Darren Tucker15ee7482004-02-22 09:43:15 +1100114#ifdef USE_SHADOW
Darren Tuckere41bba52003-08-25 11:51:19 +1000115 if (!options.use_pam)
116 spw = getspnam(pw->pw_name);
117#ifdef HAS_SHADOW_EXPIRE
Darren Tucker15ee7482004-02-22 09:43:15 +1100118 if (!options.use_pam && spw != NULL && auth_shadow_acctexpired(spw))
119 return 0;
Darren Tuckere41bba52003-08-25 11:51:19 +1000120#endif /* HAS_SHADOW_EXPIRE */
Darren Tucker15ee7482004-02-22 09:43:15 +1100121#endif /* USE_SHADOW */
Darren Tuckere41bba52003-08-25 11:51:19 +1000122
Damien Millera8e06ce2003-11-21 23:48:55 +1100123 /* grab passwd field for locked account check */
Damien Miller22989f12008-07-05 08:59:43 +1000124 passwd = pw->pw_passwd;
Darren Tucker15ee7482004-02-22 09:43:15 +1100125#ifdef USE_SHADOW
Darren Tuckere41bba52003-08-25 11:51:19 +1000126 if (spw != NULL)
Tim Rice99203ec2007-03-26 09:35:28 -0700127#ifdef USE_LIBIAF
Tim Rice2291c002005-08-26 13:15:19 -0700128 passwd = get_iaf_password(pw);
129#else
Darren Tuckere41bba52003-08-25 11:51:19 +1000130 passwd = spw->sp_pwdp;
Tim Rice99203ec2007-03-26 09:35:28 -0700131#endif /* USE_LIBIAF */
Damien Miller06817f92003-01-07 23:55:59 +1100132#endif
133
Damien Millera8e06ce2003-11-21 23:48:55 +1100134 /* check for locked account */
Darren Tucker43a0dc62003-08-26 14:22:12 +1000135 if (!options.use_pam && passwd && *passwd) {
Darren Tuckere41bba52003-08-25 11:51:19 +1000136 int locked = 0;
137
138#ifdef LOCKED_PASSWD_STRING
139 if (strcmp(passwd, LOCKED_PASSWD_STRING) == 0)
140 locked = 1;
141#endif
142#ifdef LOCKED_PASSWD_PREFIX
143 if (strncmp(passwd, LOCKED_PASSWD_PREFIX,
144 strlen(LOCKED_PASSWD_PREFIX)) == 0)
145 locked = 1;
146#endif
147#ifdef LOCKED_PASSWD_SUBSTR
148 if (strstr(passwd, LOCKED_PASSWD_SUBSTR))
149 locked = 1;
150#endif
Tim Rice99203ec2007-03-26 09:35:28 -0700151#ifdef USE_LIBIAF
Tim Ricead7d5472010-08-12 10:33:01 -0700152 free((void *) passwd);
Tim Rice99203ec2007-03-26 09:35:28 -0700153#endif /* USE_LIBIAF */
Darren Tuckere41bba52003-08-25 11:51:19 +1000154 if (locked) {
155 logit("User %.100s not allowed because account is locked",
156 pw->pw_name);
157 return 0;
158 }
159 }
160
Damien Milleref7df542000-05-19 00:03:23 +1000161 /*
Damien Miller47cf16b2010-02-12 09:25:29 +1100162 * Deny if shell does not exist or is not executable unless we
163 * are chrooting.
Damien Milleref7df542000-05-19 00:03:23 +1000164 */
Damien Miller47cf16b2010-02-12 09:25:29 +1100165 if (options.chroot_directory == NULL ||
166 strcasecmp(options.chroot_directory, "none") == 0) {
167 char *shell = xstrdup((pw->pw_shell[0] == '\0') ?
168 _PATH_BSHELL : pw->pw_shell); /* empty = /bin/sh */
Darren Tucker94881d82010-01-15 11:44:46 +1100169
Damien Miller47cf16b2010-02-12 09:25:29 +1100170 if (stat(shell, &st) != 0) {
171 logit("User %.100s not allowed because shell %.100s "
172 "does not exist", pw->pw_name, shell);
Darren Tuckera627d422013-06-02 07:31:17 +1000173 free(shell);
Damien Miller47cf16b2010-02-12 09:25:29 +1100174 return 0;
175 }
176 if (S_ISREG(st.st_mode) == 0 ||
177 (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) {
178 logit("User %.100s not allowed because shell %.100s "
179 "is not executable", pw->pw_name, shell);
Darren Tuckera627d422013-06-02 07:31:17 +1000180 free(shell);
Damien Miller47cf16b2010-02-12 09:25:29 +1100181 return 0;
182 }
Darren Tuckera627d422013-06-02 07:31:17 +1000183 free(shell);
Darren Tucker94881d82010-01-15 11:44:46 +1100184 }
Damien Milleref7df542000-05-19 00:03:23 +1000185
Darren Tuckera8f553d2005-03-14 23:17:27 +1100186 if (options.num_deny_users > 0 || options.num_allow_users > 0 ||
187 options.num_deny_groups > 0 || options.num_allow_groups > 0) {
djm@openbsd.org95767262016-03-07 19:02:43 +0000188 hostname = auth_get_canonical_hostname(ssh, options.use_dns);
189 ipaddr = ssh_remote_ipaddr(ssh);
Ben Lindstrom3fb5d002002-03-05 01:42:42 +0000190 }
191
Damien Millerb38eff82000-04-01 11:09:21 +1000192 /* Return false if user is listed in DenyUsers */
193 if (options.num_deny_users > 0) {
Damien Millerb38eff82000-04-01 11:09:21 +1000194 for (i = 0; i < options.num_deny_users; i++)
Ben Lindstrom6328ab32002-03-22 02:54:23 +0000195 if (match_user(pw->pw_name, hostname, ipaddr,
Ben Lindstrom6ef9ec62002-03-05 01:40:37 +0000196 options.deny_users[i])) {
Darren Tucker094cd0b2005-01-24 21:56:48 +1100197 logit("User %.100s from %.100s not allowed "
198 "because listed in DenyUsers",
199 pw->pw_name, hostname);
Damien Millerb38eff82000-04-01 11:09:21 +1000200 return 0;
Ben Lindstrom6ef9ec62002-03-05 01:40:37 +0000201 }
Damien Millerb38eff82000-04-01 11:09:21 +1000202 }
203 /* Return false if AllowUsers isn't empty and user isn't listed there */
204 if (options.num_allow_users > 0) {
Damien Millerb38eff82000-04-01 11:09:21 +1000205 for (i = 0; i < options.num_allow_users; i++)
Ben Lindstrom6328ab32002-03-22 02:54:23 +0000206 if (match_user(pw->pw_name, hostname, ipaddr,
Ben Lindstrom60260022001-07-04 04:56:44 +0000207 options.allow_users[i]))
Damien Millerb38eff82000-04-01 11:09:21 +1000208 break;
209 /* i < options.num_allow_users iff we break for loop */
Ben Lindstrom6ef9ec62002-03-05 01:40:37 +0000210 if (i >= options.num_allow_users) {
Darren Tucker094cd0b2005-01-24 21:56:48 +1100211 logit("User %.100s from %.100s not allowed because "
212 "not listed in AllowUsers", pw->pw_name, hostname);
Damien Millerb38eff82000-04-01 11:09:21 +1000213 return 0;
Ben Lindstrom6ef9ec62002-03-05 01:40:37 +0000214 }
Damien Millerb38eff82000-04-01 11:09:21 +1000215 }
Damien Millerb38eff82000-04-01 11:09:21 +1000216 if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
Kevin Steves7b61cfa2001-01-14 19:11:00 +0000217 /* Get the user's group access list (primary and supplementary) */
Ben Lindstrom6ef9ec62002-03-05 01:40:37 +0000218 if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
Darren Tucker094cd0b2005-01-24 21:56:48 +1100219 logit("User %.100s from %.100s not allowed because "
220 "not in any group", pw->pw_name, hostname);
Damien Millerb38eff82000-04-01 11:09:21 +1000221 return 0;
Ben Lindstrom6ef9ec62002-03-05 01:40:37 +0000222 }
Damien Millerb38eff82000-04-01 11:09:21 +1000223
Kevin Steves7b61cfa2001-01-14 19:11:00 +0000224 /* Return false if one of user's groups is listed in DenyGroups */
225 if (options.num_deny_groups > 0)
226 if (ga_match(options.deny_groups,
227 options.num_deny_groups)) {
228 ga_free();
Darren Tucker094cd0b2005-01-24 21:56:48 +1100229 logit("User %.100s from %.100s not allowed "
230 "because a group is listed in DenyGroups",
231 pw->pw_name, hostname);
Damien Millerb38eff82000-04-01 11:09:21 +1000232 return 0;
Kevin Steves7b61cfa2001-01-14 19:11:00 +0000233 }
Damien Millerb38eff82000-04-01 11:09:21 +1000234 /*
Kevin Steves7b61cfa2001-01-14 19:11:00 +0000235 * Return false if AllowGroups isn't empty and one of user's groups
Damien Millerb38eff82000-04-01 11:09:21 +1000236 * isn't listed there
237 */
Kevin Steves7b61cfa2001-01-14 19:11:00 +0000238 if (options.num_allow_groups > 0)
239 if (!ga_match(options.allow_groups,
240 options.num_allow_groups)) {
241 ga_free();
Darren Tucker094cd0b2005-01-24 21:56:48 +1100242 logit("User %.100s from %.100s not allowed "
243 "because none of user's groups are listed "
244 "in AllowGroups", pw->pw_name, hostname);
Damien Millerb38eff82000-04-01 11:09:21 +1000245 return 0;
Kevin Steves7b61cfa2001-01-14 19:11:00 +0000246 }
247 ga_free();
Damien Millerb38eff82000-04-01 11:09:21 +1000248 }
249
Darren Tucker0a9d43d2004-06-23 13:45:24 +1000250#ifdef CUSTOM_SYS_AUTH_ALLOWED_USER
Darren Tucker691d5232005-02-15 21:45:57 +1100251 if (!sys_auth_allowed_user(pw, &loginmsg))
Darren Tucker0a9d43d2004-06-23 13:45:24 +1000252 return 0;
253#endif
Damien Millerb38eff82000-04-01 11:09:21 +1000254
255 /* We found no reason not to let this user try to log on... */
256 return 1;
257}
Ben Lindstromdb65e8f2001-01-19 04:26:52 +0000258
Ben Lindstromdb65e8f2001-01-19 04:26:52 +0000259void
Darren Tucker0acca372013-06-02 07:41:51 +1000260auth_info(Authctxt *authctxt, const char *fmt, ...)
261{
262 va_list ap;
263 int i;
264
265 free(authctxt->info);
266 authctxt->info = NULL;
267
268 va_start(ap, fmt);
269 i = vasprintf(&authctxt->info, fmt, ap);
270 va_end(ap);
271
272 if (i < 0 || authctxt->info == NULL)
273 fatal("vasprintf failed");
274}
275
276void
Damien Miller15b05cf2012-12-03 09:53:20 +1100277auth_log(Authctxt *authctxt, int authenticated, int partial,
Darren Tucker0acca372013-06-02 07:41:51 +1000278 const char *method, const char *submethod)
Ben Lindstromdb65e8f2001-01-19 04:26:52 +0000279{
djm@openbsd.org95767262016-03-07 19:02:43 +0000280 struct ssh *ssh = active_state; /* XXX */
Ben Lindstromdb65e8f2001-01-19 04:26:52 +0000281 void (*authlog) (const char *fmt,...) = verbose;
282 char *authmsg;
283
Damien Miller7a8f5b32006-03-31 23:14:23 +1100284 if (use_privsep && !mm_is_monitor() && !authctxt->postponed)
285 return;
286
Ben Lindstromdb65e8f2001-01-19 04:26:52 +0000287 /* Raise logging level */
288 if (authenticated == 1 ||
289 !authctxt->valid ||
Darren Tucker89413db2004-05-24 10:36:23 +1000290 authctxt->failures >= options.max_authtries / 2 ||
Ben Lindstromdb65e8f2001-01-19 04:26:52 +0000291 strcmp(method, "password") == 0)
Damien Miller2a3f20e2003-04-09 21:12:00 +1000292 authlog = logit;
Ben Lindstromdb65e8f2001-01-19 04:26:52 +0000293
294 if (authctxt->postponed)
295 authmsg = "Postponed";
Damien Miller15b05cf2012-12-03 09:53:20 +1100296 else if (partial)
297 authmsg = "Partial";
Ben Lindstromdb65e8f2001-01-19 04:26:52 +0000298 else
299 authmsg = authenticated ? "Accepted" : "Failed";
300
Darren Tucker0acca372013-06-02 07:41:51 +1000301 authlog("%s %s%s%s for %s%.100s from %.200s port %d %s%s%s",
Ben Lindstromdb65e8f2001-01-19 04:26:52 +0000302 authmsg,
303 method,
Damien Miller15b05cf2012-12-03 09:53:20 +1100304 submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod,
Darren Tucker5cb30ad2004-08-12 22:40:24 +1000305 authctxt->valid ? "" : "invalid user ",
Damien Millerf6552072001-11-12 11:06:06 +1100306 authctxt->user,
djm@openbsd.org95767262016-03-07 19:02:43 +0000307 ssh_remote_ipaddr(ssh),
308 ssh_remote_port(ssh),
Darren Tucker0acca372013-06-02 07:41:51 +1000309 compat20 ? "ssh2" : "ssh1",
310 authctxt->info != NULL ? ": " : "",
311 authctxt->info != NULL ? authctxt->info : "");
312 free(authctxt->info);
313 authctxt->info = NULL;
Ben Lindstrome06eb682002-07-04 00:27:21 +0000314
Darren Tucker97363a82003-05-02 23:42:25 +1000315#ifdef CUSTOM_FAILED_LOGIN
Darren Tucker2fba9932005-02-02 23:30:24 +1100316 if (authenticated == 0 && !authctxt->postponed &&
317 (strcmp(method, "password") == 0 ||
Darren Tucker40d9a632005-02-04 15:19:44 +1100318 strncmp(method, "keyboard-interactive", 20) == 0 ||
319 strcmp(method, "challenge-response") == 0))
Darren Tucker42d9dc72005-02-02 17:10:11 +1100320 record_failed_login(authctxt->user,
Darren Tucker885fb2a2016-03-08 11:58:43 +1100321 auth_get_canonical_hostname(ssh, options.use_dns), "ssh");
Darren Tucker26d4e192006-08-30 22:33:09 +1000322# ifdef WITH_AIXAUTHENTICATE
323 if (authenticated)
324 sys_auth_record_login(authctxt->user,
Darren Tucker885fb2a2016-03-08 11:58:43 +1100325 auth_get_canonical_hostname(ssh, options.use_dns), "ssh",
326 &loginmsg);
Darren Tucker26d4e192006-08-30 22:33:09 +1000327# endif
Darren Tucker97363a82003-05-02 23:42:25 +1000328#endif
Darren Tucker2e0cf0d2005-02-08 21:52:47 +1100329#ifdef SSH_AUDIT_EVENTS
Darren Tuckerf14b2aa2006-05-21 18:26:40 +1000330 if (authenticated == 0 && !authctxt->postponed)
331 audit_event(audit_classify_auth(method));
Darren Tucker269a1ea2005-02-03 00:20:53 +1100332#endif
Ben Lindstromdb65e8f2001-01-19 04:26:52 +0000333}
334
Damien Miller686feb52014-07-03 21:29:38 +1000335
336void
337auth_maxtries_exceeded(Authctxt *authctxt)
338{
djm@openbsd.org95767262016-03-07 19:02:43 +0000339 struct ssh *ssh = active_state; /* XXX */
340
djm@openbsd.org6f621602015-02-25 17:29:38 +0000341 error("maximum authentication attempts exceeded for "
Damien Miller686feb52014-07-03 21:29:38 +1000342 "%s%.100s from %.200s port %d %s",
343 authctxt->valid ? "" : "invalid user ",
344 authctxt->user,
djm@openbsd.org95767262016-03-07 19:02:43 +0000345 ssh_remote_ipaddr(ssh),
346 ssh_remote_port(ssh),
Damien Miller686feb52014-07-03 21:29:38 +1000347 compat20 ? "ssh2" : "ssh1");
djm@openbsd.org6f621602015-02-25 17:29:38 +0000348 packet_disconnect("Too many authentication failures");
Damien Miller686feb52014-07-03 21:29:38 +1000349 /* NOTREACHED */
350}
351
Ben Lindstromdb65e8f2001-01-19 04:26:52 +0000352/*
Ben Lindstromd8a90212001-02-15 03:08:27 +0000353 * Check whether root logins are disallowed.
Ben Lindstromdb65e8f2001-01-19 04:26:52 +0000354 */
355int
Damien Miller15b05cf2012-12-03 09:53:20 +1100356auth_root_allowed(const char *method)
Ben Lindstromdb65e8f2001-01-19 04:26:52 +0000357{
djm@openbsd.org95767262016-03-07 19:02:43 +0000358 struct ssh *ssh = active_state; /* XXX */
359
Ben Lindstromd8a90212001-02-15 03:08:27 +0000360 switch (options.permit_root_login) {
361 case PERMIT_YES:
Ben Lindstromdb65e8f2001-01-19 04:26:52 +0000362 return 1;
Ben Lindstromd8a90212001-02-15 03:08:27 +0000363 case PERMIT_NO_PASSWD:
deraadt@openbsd.org1dc8d932015-08-06 14:53:21 +0000364 if (strcmp(method, "publickey") == 0 ||
365 strcmp(method, "hostbased") == 0 ||
djm@openbsd.org32a18192015-08-21 03:42:19 +0000366 strcmp(method, "gssapi-with-mic") == 0)
Ben Lindstromd8a90212001-02-15 03:08:27 +0000367 return 1;
368 break;
369 case PERMIT_FORCED_ONLY:
370 if (forced_command) {
Damien Miller996acd22003-04-09 20:59:48 +1000371 logit("Root login accepted for forced command.");
Ben Lindstromd8a90212001-02-15 03:08:27 +0000372 return 1;
373 }
374 break;
Ben Lindstromdb65e8f2001-01-19 04:26:52 +0000375 }
djm@openbsd.org95767262016-03-07 19:02:43 +0000376 logit("ROOT LOGIN REFUSED FROM %.200s port %d",
377 ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
Ben Lindstromd8a90212001-02-15 03:08:27 +0000378 return 0;
Ben Lindstromdb65e8f2001-01-19 04:26:52 +0000379}
Ben Lindstrombfb3a0e2001-06-05 20:25:05 +0000380
381
382/*
383 * Given a template and a passwd structure, build a filename
384 * by substituting % tokenised options. Currently, %% becomes '%',
385 * %h becomes the home directory and %u the username.
386 *
387 * This returns a buffer allocated by xmalloc.
388 */
Damien Millerd8478b62011-05-29 21:39:36 +1000389char *
Damien Miller6476cad2005-06-16 13:18:34 +1000390expand_authorized_keys(const char *filename, struct passwd *pw)
Ben Lindstrombfb3a0e2001-06-05 20:25:05 +0000391{
deraadt@openbsd.org087266e2015-01-20 23:14:00 +0000392 char *file, ret[PATH_MAX];
Damien Miller07d86be2006-03-26 14:19:21 +1100393 int i;
Ben Lindstrombfb3a0e2001-06-05 20:25:05 +0000394
Damien Miller6476cad2005-06-16 13:18:34 +1000395 file = percent_expand(filename, "h", pw->pw_dir,
396 "u", pw->pw_name, (char *)NULL);
Ben Lindstrombfb3a0e2001-06-05 20:25:05 +0000397
398 /*
399 * Ensure that filename starts anchored. If not, be backward
400 * compatible and prepend the '%h/'
401 */
Damien Miller6476cad2005-06-16 13:18:34 +1000402 if (*file == '/')
403 return (file);
Ben Lindstrombfb3a0e2001-06-05 20:25:05 +0000404
Damien Miller07d86be2006-03-26 14:19:21 +1100405 i = snprintf(ret, sizeof(ret), "%s/%s", pw->pw_dir, file);
406 if (i < 0 || (size_t)i >= sizeof(ret))
Damien Miller6476cad2005-06-16 13:18:34 +1000407 fatal("expand_authorized_keys: path too long");
Darren Tuckera627d422013-06-02 07:31:17 +1000408 free(file);
Damien Miller07d86be2006-03-26 14:19:21 +1100409 return (xstrdup(ret));
Ben Lindstrombfb3a0e2001-06-05 20:25:05 +0000410}
411
412char *
Damien Miller30da3442010-05-10 11:58:03 +1000413authorized_principals_file(struct passwd *pw)
414{
djm@openbsd.org7e8528c2015-05-01 04:17:51 +0000415 if (options.authorized_principals_file == NULL)
Damien Miller30da3442010-05-10 11:58:03 +1000416 return NULL;
417 return expand_authorized_keys(options.authorized_principals_file, pw);
418}
419
Ben Lindstrom83647ce2001-06-25 04:30:16 +0000420/* return ok if key exists in sysfile or userfile */
421HostStatus
422check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host,
423 const char *sysfile, const char *userfile)
424{
Ben Lindstrom83647ce2001-06-25 04:30:16 +0000425 char *user_hostfile;
426 struct stat st;
Ben Lindstrom65366a82001-12-06 16:32:47 +0000427 HostStatus host_status;
Damien Millerd925dcd2010-12-01 12:21:51 +1100428 struct hostkeys *hostkeys;
429 const struct hostkey_entry *found;
Ben Lindstrom83647ce2001-06-25 04:30:16 +0000430
Damien Millerd925dcd2010-12-01 12:21:51 +1100431 hostkeys = init_hostkeys();
432 load_hostkeys(hostkeys, host, sysfile);
433 if (userfile != NULL) {
Ben Lindstrom83647ce2001-06-25 04:30:16 +0000434 user_hostfile = tilde_expand_filename(userfile, pw->pw_uid);
435 if (options.strict_modes &&
436 (stat(user_hostfile, &st) == 0) &&
437 ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
Damien Miller9f0f5c62001-12-21 14:45:46 +1100438 (st.st_mode & 022) != 0)) {
Damien Miller996acd22003-04-09 20:59:48 +1000439 logit("Authentication refused for %.100s: "
Ben Lindstrom83647ce2001-06-25 04:30:16 +0000440 "bad owner or modes for %.200s",
441 pw->pw_name, user_hostfile);
Damien Miller48147d62010-06-26 09:39:25 +1000442 auth_debug_add("Ignored %.200s: bad ownership or modes",
443 user_hostfile);
Ben Lindstrom83647ce2001-06-25 04:30:16 +0000444 } else {
445 temporarily_use_uid(pw);
Damien Millerd925dcd2010-12-01 12:21:51 +1100446 load_hostkeys(hostkeys, host, user_hostfile);
Ben Lindstrom83647ce2001-06-25 04:30:16 +0000447 restore_uid();
448 }
Darren Tuckera627d422013-06-02 07:31:17 +1000449 free(user_hostfile);
Ben Lindstrom83647ce2001-06-25 04:30:16 +0000450 }
Damien Millerd925dcd2010-12-01 12:21:51 +1100451 host_status = check_key_in_hostkeys(hostkeys, key, &found);
452 if (host_status == HOST_REVOKED)
453 error("WARNING: revoked key for %s attempted authentication",
454 found->host);
455 else if (host_status == HOST_OK)
456 debug("%s: key for %s found at %s:%ld", __func__,
457 found->host, found->file, found->line);
458 else
459 debug("%s: key for host %s not found", __func__, host);
Ben Lindstrom83647ce2001-06-25 04:30:16 +0000460
Damien Millerd925dcd2010-12-01 12:21:51 +1100461 free_hostkeys(hostkeys);
462
Ben Lindstrom83647ce2001-06-25 04:30:16 +0000463 return host_status;
464}
465
Ben Lindstrombfb3a0e2001-06-05 20:25:05 +0000466/*
Damien Miller09d3e122012-10-31 08:58:58 +1100467 * Check a given path for security. This is defined as all components
Ben Lindstromd4ee3492002-08-20 18:42:13 +0000468 * of the path to the file must be owned by either the owner of
Ben Lindstrom60567ff2001-06-05 20:27:53 +0000469 * of the file or root and no directories must be group or world writable.
Ben Lindstrombfb3a0e2001-06-05 20:25:05 +0000470 *
471 * XXX Should any specific check be done for sym links ?
472 *
Damien Miller18de9132013-02-12 11:02:27 +1100473 * Takes a file name, its stat information (preferably from fstat() to
Damien Miller09d3e122012-10-31 08:58:58 +1100474 * avoid races), the uid of the expected owner, their home directory and an
Ben Lindstrombfb3a0e2001-06-05 20:25:05 +0000475 * error buffer plus max size as arguments.
476 *
477 * Returns 0 on success and -1 on failure
478 */
Damien Miller09d3e122012-10-31 08:58:58 +1100479int
480auth_secure_path(const char *name, struct stat *stp, const char *pw_dir,
481 uid_t uid, char *err, size_t errlen)
Ben Lindstrombfb3a0e2001-06-05 20:25:05 +0000482{
deraadt@openbsd.org087266e2015-01-20 23:14:00 +0000483 char buf[PATH_MAX], homedir[PATH_MAX];
Ben Lindstrombfb3a0e2001-06-05 20:25:05 +0000484 char *cp;
Ben Lindstrom485075e2002-11-09 15:45:12 +0000485 int comparehome = 0;
Ben Lindstrombfb3a0e2001-06-05 20:25:05 +0000486 struct stat st;
487
Damien Miller09d3e122012-10-31 08:58:58 +1100488 if (realpath(name, buf) == NULL) {
489 snprintf(err, errlen, "realpath %s failed: %s", name,
Ben Lindstrombfb3a0e2001-06-05 20:25:05 +0000490 strerror(errno));
491 return -1;
492 }
Damien Miller09d3e122012-10-31 08:58:58 +1100493 if (pw_dir != NULL && realpath(pw_dir, homedir) != NULL)
Ben Lindstrom485075e2002-11-09 15:45:12 +0000494 comparehome = 1;
Ben Lindstrombfb3a0e2001-06-05 20:25:05 +0000495
Damien Miller09d3e122012-10-31 08:58:58 +1100496 if (!S_ISREG(stp->st_mode)) {
497 snprintf(err, errlen, "%s is not a regular file", buf);
498 return -1;
499 }
Darren Tuckeraa97d132013-03-12 11:31:05 +1100500 if ((!platform_sys_dir_uid(stp->st_uid) && stp->st_uid != uid) ||
Damien Miller09d3e122012-10-31 08:58:58 +1100501 (stp->st_mode & 022) != 0) {
Ben Lindstrombfb3a0e2001-06-05 20:25:05 +0000502 snprintf(err, errlen, "bad ownership or modes for file %s",
503 buf);
504 return -1;
505 }
506
507 /* for each component of the canonical path, walking upwards */
508 for (;;) {
509 if ((cp = dirname(buf)) == NULL) {
510 snprintf(err, errlen, "dirname() failed");
511 return -1;
512 }
513 strlcpy(buf, cp, sizeof(buf));
514
Ben Lindstrombfb3a0e2001-06-05 20:25:05 +0000515 if (stat(buf, &st) < 0 ||
Darren Tuckeraa97d132013-03-12 11:31:05 +1100516 (!platform_sys_dir_uid(st.st_uid) && st.st_uid != uid) ||
Ben Lindstrombfb3a0e2001-06-05 20:25:05 +0000517 (st.st_mode & 022) != 0) {
Damien Miller9f0f5c62001-12-21 14:45:46 +1100518 snprintf(err, errlen,
Ben Lindstrombfb3a0e2001-06-05 20:25:05 +0000519 "bad ownership or modes for directory %s", buf);
520 return -1;
521 }
522
Darren Tuckere2b36742010-01-13 22:42:34 +1100523 /* If are past the homedir then we can stop */
Damien Miller1dd66e52011-05-29 21:40:42 +1000524 if (comparehome && strcmp(homedir, buf) == 0)
Damien Miller0ae6e002001-07-14 12:21:34 +1000525 break;
Damien Miller1dd66e52011-05-29 21:40:42 +1000526
Ben Lindstrombfb3a0e2001-06-05 20:25:05 +0000527 /*
528 * dirname should always complete with a "/" path,
529 * but we can be paranoid and check for "." too
530 */
531 if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0))
532 break;
533 }
534 return 0;
535}
Ben Lindstrom2ae18f42002-03-22 01:24:38 +0000536
Damien Miller09d3e122012-10-31 08:58:58 +1100537/*
538 * Version of secure_path() that accepts an open file descriptor to
539 * avoid races.
540 *
541 * Returns 0 on success and -1 on failure
542 */
543static int
544secure_filename(FILE *f, const char *file, struct passwd *pw,
545 char *err, size_t errlen)
546{
Damien Miller09d3e122012-10-31 08:58:58 +1100547 struct stat st;
548
549 /* check the open file to avoid races */
550 if (fstat(fileno(f), &st) < 0) {
551 snprintf(err, errlen, "cannot stat file %s: %s",
Damien Miller4e14a582013-01-09 15:54:48 +1100552 file, strerror(errno));
Damien Miller09d3e122012-10-31 08:58:58 +1100553 return -1;
554 }
555 return auth_secure_path(file, &st, pw->pw_dir, pw->pw_uid, err, errlen);
556}
557
Damien Miller30da3442010-05-10 11:58:03 +1000558static FILE *
559auth_openfile(const char *file, struct passwd *pw, int strict_modes,
560 int log_missing, char *file_type)
Darren Tucker33c787f2008-07-02 22:37:30 +1000561{
562 char line[1024];
563 struct stat st;
564 int fd;
565 FILE *f;
566
Darren Tucker43551522010-01-10 19:27:17 +1100567 if ((fd = open(file, O_RDONLY|O_NONBLOCK)) == -1) {
Damien Miller30da3442010-05-10 11:58:03 +1000568 if (log_missing || errno != ENOENT)
569 debug("Could not open %s '%s': %s", file_type, file,
Darren Tucker43551522010-01-10 19:27:17 +1100570 strerror(errno));
Darren Tucker33c787f2008-07-02 22:37:30 +1000571 return NULL;
Darren Tucker43551522010-01-10 19:27:17 +1100572 }
Darren Tucker33c787f2008-07-02 22:37:30 +1000573
574 if (fstat(fd, &st) < 0) {
575 close(fd);
576 return NULL;
577 }
578 if (!S_ISREG(st.st_mode)) {
Damien Miller30da3442010-05-10 11:58:03 +1000579 logit("User %s %s %s is not a regular file",
580 pw->pw_name, file_type, file);
Darren Tucker33c787f2008-07-02 22:37:30 +1000581 close(fd);
582 return NULL;
583 }
584 unset_nonblock(fd);
585 if ((f = fdopen(fd, "r")) == NULL) {
586 close(fd);
587 return NULL;
588 }
Damien Miller6a740e72010-12-01 12:01:51 +1100589 if (strict_modes &&
Darren Tucker33c787f2008-07-02 22:37:30 +1000590 secure_filename(f, file, pw, line, sizeof(line)) != 0) {
591 fclose(f);
592 logit("Authentication refused: %s", line);
Damien Miller48147d62010-06-26 09:39:25 +1000593 auth_debug_add("Ignored %s: %s", file_type, line);
Darren Tucker33c787f2008-07-02 22:37:30 +1000594 return NULL;
595 }
596
597 return f;
598}
599
Damien Miller30da3442010-05-10 11:58:03 +1000600
601FILE *
602auth_openkeyfile(const char *file, struct passwd *pw, int strict_modes)
603{
604 return auth_openfile(file, pw, strict_modes, 1, "authorized keys");
605}
606
607FILE *
608auth_openprincipals(const char *file, struct passwd *pw, int strict_modes)
609{
610 return auth_openfile(file, pw, strict_modes, 0,
611 "authorized principals");
612}
613
Ben Lindstrom2ae18f42002-03-22 01:24:38 +0000614struct passwd *
615getpwnamallow(const char *user)
616{
djm@openbsd.org95767262016-03-07 19:02:43 +0000617 struct ssh *ssh = active_state; /* XXX */
Ben Lindstromb481e132002-03-22 01:35:47 +0000618#ifdef HAVE_LOGIN_CAP
619 extern login_cap_t *lc;
620#ifdef BSD_AUTH
621 auth_session_t *as;
622#endif
623#endif
Ben Lindstrom2ae18f42002-03-22 01:24:38 +0000624 struct passwd *pw;
Darren Tuckerfbcf8272012-05-19 19:37:01 +1000625 struct connection_info *ci = get_connection_info(1, options.use_dns);
Ben Lindstrom2ae18f42002-03-22 01:24:38 +0000626
Darren Tuckerfbcf8272012-05-19 19:37:01 +1000627 ci->user = user;
628 parse_server_match_config(&options, ci);
Darren Tucker45150472006-07-12 22:34:17 +1000629
Darren Tuckerb3d20a32010-03-07 11:56:59 +1100630#if defined(_AIX) && defined(HAVE_SETAUTHDB)
631 aix_setauthdb(user);
632#endif
633
Ben Lindstrom2ae18f42002-03-22 01:24:38 +0000634 pw = getpwnam(user);
Darren Tuckerb3d20a32010-03-07 11:56:59 +1100635
636#if defined(_AIX) && defined(HAVE_SETAUTHDB)
637 aix_restoreauthdb();
638#endif
Damien Milleracc9b292010-03-01 04:36:54 +1100639#ifdef HAVE_CYGWIN
640 /*
641 * Windows usernames are case-insensitive. To avoid later problems
642 * when trying to match the username, the user is only allowed to
643 * login if the username is given in the same case as stored in the
644 * user database.
645 */
646 if (pw != NULL && strcmp(user, pw->pw_name) != 0) {
647 logit("Login name %.100s does not match stored username %.100s",
648 user, pw->pw_name);
649 pw = NULL;
650 }
651#endif
Damien Miller6f0a1882002-09-22 01:26:51 +1000652 if (pw == NULL) {
djm@openbsd.org95767262016-03-07 19:02:43 +0000653 logit("Invalid user %.100s from %.100s port %d",
654 user, ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
Darren Tucker97363a82003-05-02 23:42:25 +1000655#ifdef CUSTOM_FAILED_LOGIN
Darren Tucker42d9dc72005-02-02 17:10:11 +1100656 record_failed_login(user,
Darren Tucker885fb2a2016-03-08 11:58:43 +1100657 auth_get_canonical_hostname(ssh, options.use_dns), "ssh");
Ben Lindstromf5397c02002-11-09 16:11:10 +0000658#endif
Darren Tucker2e0cf0d2005-02-08 21:52:47 +1100659#ifdef SSH_AUDIT_EVENTS
660 audit_event(SSH_INVALID_USER);
661#endif /* SSH_AUDIT_EVENTS */
Damien Miller6f0a1882002-09-22 01:26:51 +1000662 return (NULL);
663 }
664 if (!allowed_user(pw))
Ben Lindstromb481e132002-03-22 01:35:47 +0000665 return (NULL);
666#ifdef HAVE_LOGIN_CAP
667 if ((lc = login_getclass(pw->pw_class)) == NULL) {
668 debug("unable to get login class: %s", user);
669 return (NULL);
670 }
671#ifdef BSD_AUTH
672 if ((as = auth_open()) == NULL || auth_setpwd(as, pw) != 0 ||
Damien Miller13e35a02002-05-22 14:04:11 +1000673 auth_approval(as, lc, pw->pw_name, "ssh") <= 0) {
Ben Lindstromb481e132002-03-22 01:35:47 +0000674 debug("Approval failure for %s", user);
Ben Lindstrom2ae18f42002-03-22 01:24:38 +0000675 pw = NULL;
Ben Lindstromb481e132002-03-22 01:35:47 +0000676 }
677 if (as != NULL)
678 auth_close(as);
679#endif
680#endif
Ben Lindstromf34e4eb2002-03-22 03:08:30 +0000681 if (pw != NULL)
682 return (pwcopy(pw));
683 return (NULL);
Ben Lindstrom2ae18f42002-03-22 01:24:38 +0000684}
Ben Lindstroma574cda2002-05-15 16:16:14 +0000685
Damien Miller1aed65e2010-03-04 21:53:35 +1100686/* Returns 1 if key is revoked by revoked_keys_file, 0 otherwise */
687int
688auth_key_is_revoked(Key *key)
689{
djm@openbsd.org5e39a492014-12-04 02:24:32 +0000690 char *fp = NULL;
691 int r;
Damien Miller1aed65e2010-03-04 21:53:35 +1100692
693 if (options.revoked_keys_file == NULL)
694 return 0;
djm@openbsd.org56d1c832014-12-21 22:27:55 +0000695 if ((fp = sshkey_fingerprint(key, options.fingerprint_hash,
696 SSH_FP_DEFAULT)) == NULL) {
djm@openbsd.org5e39a492014-12-04 02:24:32 +0000697 r = SSH_ERR_ALLOC_FAIL;
698 error("%s: fingerprint key: %s", __func__, ssh_err(r));
699 goto out;
700 }
701
702 r = sshkey_check_revoked(key, options.revoked_keys_file);
703 switch (r) {
Damien Millerf3747bf2013-01-18 11:44:04 +1100704 case 0:
djm@openbsd.org5e39a492014-12-04 02:24:32 +0000705 break; /* not revoked */
706 case SSH_ERR_KEY_REVOKED:
707 error("Authentication key %s %s revoked by file %s",
708 sshkey_type(key), fp, options.revoked_keys_file);
709 goto out;
Damien Millerf3747bf2013-01-18 11:44:04 +1100710 default:
djm@openbsd.org5e39a492014-12-04 02:24:32 +0000711 error("Error checking authentication key %s %s in "
712 "revoked keys file %s: %s", sshkey_type(key), fp,
713 options.revoked_keys_file, ssh_err(r));
714 goto out;
Damien Millerf3747bf2013-01-18 11:44:04 +1100715 }
djm@openbsd.org5e39a492014-12-04 02:24:32 +0000716
717 /* Success */
718 r = 0;
719
720 out:
721 free(fp);
722 return r == 0 ? 0 : 1;
Damien Miller1aed65e2010-03-04 21:53:35 +1100723}
724
Ben Lindstroma574cda2002-05-15 16:16:14 +0000725void
726auth_debug_add(const char *fmt,...)
727{
728 char buf[1024];
729 va_list args;
730
731 if (!auth_debug_init)
732 return;
733
734 va_start(args, fmt);
735 vsnprintf(buf, sizeof(buf), fmt, args);
736 va_end(args);
737 buffer_put_cstring(&auth_debug, buf);
738}
739
740void
741auth_debug_send(void)
742{
743 char *msg;
744
745 if (!auth_debug_init)
746 return;
747 while (buffer_len(&auth_debug)) {
748 msg = buffer_get_string(&auth_debug, NULL);
749 packet_send_debug("%s", msg);
Darren Tuckera627d422013-06-02 07:31:17 +1000750 free(msg);
Ben Lindstroma574cda2002-05-15 16:16:14 +0000751 }
752}
753
754void
755auth_debug_reset(void)
756{
757 if (auth_debug_init)
758 buffer_clear(&auth_debug);
759 else {
760 buffer_init(&auth_debug);
761 auth_debug_init = 1;
762 }
763}
Damien Miller856f0be2003-09-03 07:32:45 +1000764
765struct passwd *
766fakepw(void)
767{
768 static struct passwd fake;
769
770 memset(&fake, 0, sizeof(fake));
771 fake.pw_name = "NOUSER";
772 fake.pw_passwd =
Damien Miller787b2ec2003-11-21 23:56:47 +1100773 "$2a$06$r3.juUaHZDlIbQaO2dS9FuYxL1W9M81R1Tc92PoSNmzvpEqLkLGrK";
Damien Miller6332da22013-04-23 14:25:52 +1000774#ifdef HAVE_STRUCT_PASSWD_PW_GECOS
Damien Miller856f0be2003-09-03 07:32:45 +1000775 fake.pw_gecos = "NOUSER";
Damien Miller6332da22013-04-23 14:25:52 +1000776#endif
Damien Miller143c2ef2006-12-05 09:08:54 +1100777 fake.pw_uid = privsep_pw == NULL ? (uid_t)-1 : privsep_pw->pw_uid;
778 fake.pw_gid = privsep_pw == NULL ? (gid_t)-1 : privsep_pw->pw_gid;
Damien Miller6332da22013-04-23 14:25:52 +1000779#ifdef HAVE_STRUCT_PASSWD_PW_CLASS
Damien Miller856f0be2003-09-03 07:32:45 +1000780 fake.pw_class = "";
781#endif
782 fake.pw_dir = "/nonexist";
783 fake.pw_shell = "/nonexist";
784
785 return (&fake);
786}
djm@openbsd.org95767262016-03-07 19:02:43 +0000787
788/*
789 * Returns the remote DNS hostname as a string. The returned string must not
790 * be freed. NB. this will usually trigger a DNS query the first time it is
791 * called.
792 * This function does additional checks on the hostname to mitigate some
793 * attacks on legacy rhosts-style authentication.
794 * XXX is RhostsRSAAuthentication vulnerable to these?
795 * XXX Can we remove these checks? (or if not, remove RhostsRSAAuthentication?)
796 */
797
798static char *
799remote_hostname(struct ssh *ssh)
800{
801 struct sockaddr_storage from;
802 socklen_t fromlen;
803 struct addrinfo hints, *ai, *aitop;
804 char name[NI_MAXHOST], ntop2[NI_MAXHOST];
805 const char *ntop = ssh_remote_ipaddr(ssh);
806
807 /* Get IP address of client. */
808 fromlen = sizeof(from);
809 memset(&from, 0, sizeof(from));
810 if (getpeername(ssh_packet_get_connection_in(ssh),
811 (struct sockaddr *)&from, &fromlen) < 0) {
812 debug("getpeername failed: %.100s", strerror(errno));
813 return strdup(ntop);
814 }
815
816 ipv64_normalise_mapped(&from, &fromlen);
817 if (from.ss_family == AF_INET6)
818 fromlen = sizeof(struct sockaddr_in6);
819
820 debug3("Trying to reverse map address %.100s.", ntop);
821 /* Map the IP address to a host name. */
822 if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
823 NULL, 0, NI_NAMEREQD) != 0) {
824 /* Host name not found. Use ip address. */
825 return strdup(ntop);
826 }
827
828 /*
829 * if reverse lookup result looks like a numeric hostname,
830 * someone is trying to trick us by PTR record like following:
831 * 1.1.1.10.in-addr.arpa. IN PTR 2.3.4.5
832 */
833 memset(&hints, 0, sizeof(hints));
834 hints.ai_socktype = SOCK_DGRAM; /*dummy*/
835 hints.ai_flags = AI_NUMERICHOST;
836 if (getaddrinfo(name, NULL, &hints, &ai) == 0) {
837 logit("Nasty PTR record \"%s\" is set up for %s, ignoring",
838 name, ntop);
839 freeaddrinfo(ai);
840 return strdup(ntop);
841 }
842
843 /* Names are stored in lowercase. */
844 lowercase(name);
845
846 /*
847 * Map it back to an IP address and check that the given
848 * address actually is an address of this host. This is
849 * necessary because anyone with access to a name server can
850 * define arbitrary names for an IP address. Mapping from
851 * name to IP address can be trusted better (but can still be
852 * fooled if the intruder has access to the name server of
853 * the domain).
854 */
855 memset(&hints, 0, sizeof(hints));
856 hints.ai_family = from.ss_family;
857 hints.ai_socktype = SOCK_STREAM;
858 if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {
859 logit("reverse mapping checking getaddrinfo for %.700s "
860 "[%s] failed - POSSIBLE BREAK-IN ATTEMPT!", name, ntop);
861 return strdup(ntop);
862 }
863 /* Look for the address from the list of addresses. */
864 for (ai = aitop; ai; ai = ai->ai_next) {
865 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,
866 sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&
867 (strcmp(ntop, ntop2) == 0))
868 break;
869 }
870 freeaddrinfo(aitop);
871 /* If we reached the end of the list, the address was not there. */
872 if (ai == NULL) {
873 /* Address not found for the host name. */
874 logit("Address %.100s maps to %.600s, but this does not "
875 "map back to the address - POSSIBLE BREAK-IN ATTEMPT!",
876 ntop, name);
877 return strdup(ntop);
878 }
879 return strdup(name);
880}
881
882/*
883 * Return the canonical name of the host in the other side of the current
884 * connection. The host name is cached, so it is efficient to call this
885 * several times.
886 */
887
888const char *
889auth_get_canonical_hostname(struct ssh *ssh, int use_dns)
890{
891 static char *dnsname;
892
893 if (!use_dns)
894 return ssh_remote_ipaddr(ssh);
895 else if (dnsname != NULL)
896 return dnsname;
897 else {
898 dnsname = remote_hostname(ssh);
899 return dnsname;
900 }
901}