xref: /openbsd-src/usr.bin/ssh/auth.c (revision 11efff7f3ac2b3cfeff0c0cddc14294d9b3aca4f)
1 /*
2  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24 
25 #include "includes.h"
26 RCSID("$OpenBSD: auth.c,v 1.56 2004/07/28 09:40:29 markus Exp $");
27 
28 #include <libgen.h>
29 
30 #include "xmalloc.h"
31 #include "match.h"
32 #include "groupaccess.h"
33 #include "log.h"
34 #include "servconf.h"
35 #include "auth.h"
36 #include "auth-options.h"
37 #include "canohost.h"
38 #include "buffer.h"
39 #include "bufaux.h"
40 #include "uidswap.h"
41 #include "misc.h"
42 #include "bufaux.h"
43 #include "packet.h"
44 
45 /* import */
46 extern ServerOptions options;
47 
48 /* Debugging messages */
49 Buffer auth_debug;
50 int auth_debug_init;
51 
52 /*
53  * Check if the user is allowed to log in via ssh. If user is listed
54  * in DenyUsers or one of user's groups is listed in DenyGroups, false
55  * will be returned. If AllowUsers isn't empty and user isn't listed
56  * there, or if AllowGroups isn't empty and one of user's groups isn't
57  * listed there, false will be returned.
58  * If the user's shell is not executable, false will be returned.
59  * Otherwise true is returned.
60  */
61 int
62 allowed_user(struct passwd * pw)
63 {
64 	struct stat st;
65 	const char *hostname = NULL, *ipaddr = NULL;
66 	char *shell;
67 	int i;
68 
69 	/* Shouldn't be called if pw is NULL, but better safe than sorry... */
70 	if (!pw || !pw->pw_name)
71 		return 0;
72 
73 	/*
74 	 * Get the shell from the password data.  An empty shell field is
75 	 * legal, and means /bin/sh.
76 	 */
77 	shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
78 
79 	/* deny if shell does not exists or is not executable */
80 	if (stat(shell, &st) != 0) {
81 		logit("User %.100s not allowed because shell %.100s does not exist",
82 		    pw->pw_name, shell);
83 		return 0;
84 	}
85 	if (S_ISREG(st.st_mode) == 0 ||
86 	    (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) {
87 		logit("User %.100s not allowed because shell %.100s is not executable",
88 		    pw->pw_name, shell);
89 		return 0;
90 	}
91 
92 	if (options.num_deny_users > 0 || options.num_allow_users > 0) {
93 		hostname = get_canonical_hostname(options.use_dns);
94 		ipaddr = get_remote_ipaddr();
95 	}
96 
97 	/* Return false if user is listed in DenyUsers */
98 	if (options.num_deny_users > 0) {
99 		for (i = 0; i < options.num_deny_users; i++)
100 			if (match_user(pw->pw_name, hostname, ipaddr,
101 			    options.deny_users[i])) {
102 				logit("User %.100s not allowed because listed in DenyUsers",
103 				    pw->pw_name);
104 				return 0;
105 			}
106 	}
107 	/* Return false if AllowUsers isn't empty and user isn't listed there */
108 	if (options.num_allow_users > 0) {
109 		for (i = 0; i < options.num_allow_users; i++)
110 			if (match_user(pw->pw_name, hostname, ipaddr,
111 			    options.allow_users[i]))
112 				break;
113 		/* i < options.num_allow_users iff we break for loop */
114 		if (i >= options.num_allow_users) {
115 			logit("User %.100s not allowed because not listed in AllowUsers",
116 			    pw->pw_name);
117 			return 0;
118 		}
119 	}
120 	if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
121 		/* Get the user's group access list (primary and supplementary) */
122 		if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
123 			logit("User %.100s not allowed because not in any group",
124 			    pw->pw_name);
125 			return 0;
126 		}
127 
128 		/* Return false if one of user's groups is listed in DenyGroups */
129 		if (options.num_deny_groups > 0)
130 			if (ga_match(options.deny_groups,
131 			    options.num_deny_groups)) {
132 				ga_free();
133 				logit("User %.100s not allowed because a group is listed in DenyGroups",
134 				    pw->pw_name);
135 				return 0;
136 			}
137 		/*
138 		 * Return false if AllowGroups isn't empty and one of user's groups
139 		 * isn't listed there
140 		 */
141 		if (options.num_allow_groups > 0)
142 			if (!ga_match(options.allow_groups,
143 			    options.num_allow_groups)) {
144 				ga_free();
145 				logit("User %.100s not allowed because none of user's groups are listed in AllowGroups",
146 				    pw->pw_name);
147 				return 0;
148 			}
149 		ga_free();
150 	}
151 	/* We found no reason not to let this user try to log on... */
152 	return 1;
153 }
154 
155 void
156 auth_log(Authctxt *authctxt, int authenticated, char *method, char *info)
157 {
158 	void (*authlog) (const char *fmt,...) = verbose;
159 	char *authmsg;
160 
161 	/* Raise logging level */
162 	if (authenticated == 1 ||
163 	    !authctxt->valid ||
164 	    authctxt->failures >= options.max_authtries / 2 ||
165 	    strcmp(method, "password") == 0)
166 		authlog = logit;
167 
168 	if (authctxt->postponed)
169 		authmsg = "Postponed";
170 	else
171 		authmsg = authenticated ? "Accepted" : "Failed";
172 
173 	authlog("%s %s for %s%.100s from %.200s port %d%s",
174 	    authmsg,
175 	    method,
176 	    authctxt->valid ? "" : "invalid user ",
177 	    authctxt->user,
178 	    get_remote_ipaddr(),
179 	    get_remote_port(),
180 	    info);
181 }
182 
183 /*
184  * Check whether root logins are disallowed.
185  */
186 int
187 auth_root_allowed(char *method)
188 {
189 	switch (options.permit_root_login) {
190 	case PERMIT_YES:
191 		return 1;
192 		break;
193 	case PERMIT_NO_PASSWD:
194 		if (strcmp(method, "password") != 0)
195 			return 1;
196 		break;
197 	case PERMIT_FORCED_ONLY:
198 		if (forced_command) {
199 			logit("Root login accepted for forced command.");
200 			return 1;
201 		}
202 		break;
203 	}
204 	logit("ROOT LOGIN REFUSED FROM %.200s", get_remote_ipaddr());
205 	return 0;
206 }
207 
208 
209 /*
210  * Given a template and a passwd structure, build a filename
211  * by substituting % tokenised options. Currently, %% becomes '%',
212  * %h becomes the home directory and %u the username.
213  *
214  * This returns a buffer allocated by xmalloc.
215  */
216 char *
217 expand_filename(const char *filename, struct passwd *pw)
218 {
219 	Buffer buffer;
220 	char *file;
221 	const char *cp;
222 
223 	/*
224 	 * Build the filename string in the buffer by making the appropriate
225 	 * substitutions to the given file name.
226 	 */
227 	buffer_init(&buffer);
228 	for (cp = filename; *cp; cp++) {
229 		if (cp[0] == '%' && cp[1] == '%') {
230 			buffer_append(&buffer, "%", 1);
231 			cp++;
232 			continue;
233 		}
234 		if (cp[0] == '%' && cp[1] == 'h') {
235 			buffer_append(&buffer, pw->pw_dir, strlen(pw->pw_dir));
236 			cp++;
237 			continue;
238 		}
239 		if (cp[0] == '%' && cp[1] == 'u') {
240 			buffer_append(&buffer, pw->pw_name,
241 			    strlen(pw->pw_name));
242 			cp++;
243 			continue;
244 		}
245 		buffer_append(&buffer, cp, 1);
246 	}
247 	buffer_append(&buffer, "\0", 1);
248 
249 	/*
250 	 * Ensure that filename starts anchored. If not, be backward
251 	 * compatible and prepend the '%h/'
252 	 */
253 	file = xmalloc(MAXPATHLEN);
254 	cp = buffer_ptr(&buffer);
255 	if (*cp != '/')
256 		snprintf(file, MAXPATHLEN, "%s/%s", pw->pw_dir, cp);
257 	else
258 		strlcpy(file, cp, MAXPATHLEN);
259 
260 	buffer_free(&buffer);
261 	return file;
262 }
263 
264 char *
265 authorized_keys_file(struct passwd *pw)
266 {
267 	return expand_filename(options.authorized_keys_file, pw);
268 }
269 
270 char *
271 authorized_keys_file2(struct passwd *pw)
272 {
273 	return expand_filename(options.authorized_keys_file2, pw);
274 }
275 
276 /* return ok if key exists in sysfile or userfile */
277 HostStatus
278 check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host,
279     const char *sysfile, const char *userfile)
280 {
281 	Key *found;
282 	char *user_hostfile;
283 	struct stat st;
284 	HostStatus host_status;
285 
286 	/* Check if we know the host and its host key. */
287 	found = key_new(key->type);
288 	host_status = check_host_in_hostfile(sysfile, host, key, found, NULL);
289 
290 	if (host_status != HOST_OK && userfile != NULL) {
291 		user_hostfile = tilde_expand_filename(userfile, pw->pw_uid);
292 		if (options.strict_modes &&
293 		    (stat(user_hostfile, &st) == 0) &&
294 		    ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
295 		    (st.st_mode & 022) != 0)) {
296 			logit("Authentication refused for %.100s: "
297 			    "bad owner or modes for %.200s",
298 			    pw->pw_name, user_hostfile);
299 		} else {
300 			temporarily_use_uid(pw);
301 			host_status = check_host_in_hostfile(user_hostfile,
302 			    host, key, found, NULL);
303 			restore_uid();
304 		}
305 		xfree(user_hostfile);
306 	}
307 	key_free(found);
308 
309 	debug2("check_key_in_hostfiles: key %s for %s", host_status == HOST_OK ?
310 	    "ok" : "not found", host);
311 	return host_status;
312 }
313 
314 
315 /*
316  * Check a given file for security. This is defined as all components
317  * of the path to the file must be owned by either the owner of
318  * of the file or root and no directories must be group or world writable.
319  *
320  * XXX Should any specific check be done for sym links ?
321  *
322  * Takes an open file descriptor, the file name, a uid and and
323  * error buffer plus max size as arguments.
324  *
325  * Returns 0 on success and -1 on failure
326  */
327 int
328 secure_filename(FILE *f, const char *file, struct passwd *pw,
329     char *err, size_t errlen)
330 {
331 	uid_t uid = pw->pw_uid;
332 	char buf[MAXPATHLEN], homedir[MAXPATHLEN];
333 	char *cp;
334 	int comparehome = 0;
335 	struct stat st;
336 
337 	if (realpath(file, buf) == NULL) {
338 		snprintf(err, errlen, "realpath %s failed: %s", file,
339 		    strerror(errno));
340 		return -1;
341 	}
342 	if (realpath(pw->pw_dir, homedir) != NULL)
343 		comparehome = 1;
344 
345 	/* check the open file to avoid races */
346 	if (fstat(fileno(f), &st) < 0 ||
347 	    (st.st_uid != 0 && st.st_uid != uid) ||
348 	    (st.st_mode & 022) != 0) {
349 		snprintf(err, errlen, "bad ownership or modes for file %s",
350 		    buf);
351 		return -1;
352 	}
353 
354 	/* for each component of the canonical path, walking upwards */
355 	for (;;) {
356 		if ((cp = dirname(buf)) == NULL) {
357 			snprintf(err, errlen, "dirname() failed");
358 			return -1;
359 		}
360 		strlcpy(buf, cp, sizeof(buf));
361 
362 		debug3("secure_filename: checking '%s'", buf);
363 		if (stat(buf, &st) < 0 ||
364 		    (st.st_uid != 0 && st.st_uid != uid) ||
365 		    (st.st_mode & 022) != 0) {
366 			snprintf(err, errlen,
367 			    "bad ownership or modes for directory %s", buf);
368 			return -1;
369 		}
370 
371 		/* If are passed the homedir then we can stop */
372 		if (comparehome && strcmp(homedir, buf) == 0) {
373 			debug3("secure_filename: terminating check at '%s'",
374 			    buf);
375 			break;
376 		}
377 		/*
378 		 * dirname should always complete with a "/" path,
379 		 * but we can be paranoid and check for "." too
380 		 */
381 		if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0))
382 			break;
383 	}
384 	return 0;
385 }
386 
387 struct passwd *
388 getpwnamallow(const char *user)
389 {
390 #ifdef HAVE_LOGIN_CAP
391 	extern login_cap_t *lc;
392 #ifdef BSD_AUTH
393 	auth_session_t *as;
394 #endif
395 #endif
396 	struct passwd *pw;
397 
398 	pw = getpwnam(user);
399 	if (pw == NULL) {
400 		logit("Invalid user %.100s from %.100s",
401 		    user, get_remote_ipaddr());
402 		return (NULL);
403 	}
404 	if (!allowed_user(pw))
405 		return (NULL);
406 #ifdef HAVE_LOGIN_CAP
407 	if ((lc = login_getclass(pw->pw_class)) == NULL) {
408 		debug("unable to get login class: %s", user);
409 		return (NULL);
410 	}
411 #ifdef BSD_AUTH
412 	if ((as = auth_open()) == NULL || auth_setpwd(as, pw) != 0 ||
413 	    auth_approval(as, lc, pw->pw_name, "ssh") <= 0) {
414 		debug("Approval failure for %s", user);
415 		pw = NULL;
416 	}
417 	if (as != NULL)
418 		auth_close(as);
419 #endif
420 #endif
421 	if (pw != NULL)
422 		return (pwcopy(pw));
423 	return (NULL);
424 }
425 
426 void
427 auth_debug_add(const char *fmt,...)
428 {
429 	char buf[1024];
430 	va_list args;
431 
432 	if (!auth_debug_init)
433 		return;
434 
435 	va_start(args, fmt);
436 	vsnprintf(buf, sizeof(buf), fmt, args);
437 	va_end(args);
438 	buffer_put_cstring(&auth_debug, buf);
439 }
440 
441 void
442 auth_debug_send(void)
443 {
444 	char *msg;
445 
446 	if (!auth_debug_init)
447 		return;
448 	while (buffer_len(&auth_debug)) {
449 		msg = buffer_get_string(&auth_debug, NULL);
450 		packet_send_debug("%s", msg);
451 		xfree(msg);
452 	}
453 }
454 
455 void
456 auth_debug_reset(void)
457 {
458 	if (auth_debug_init)
459 		buffer_clear(&auth_debug);
460 	else {
461 		buffer_init(&auth_debug);
462 		auth_debug_init = 1;
463 	}
464 }
465 
466 struct passwd *
467 fakepw(void)
468 {
469 	static struct passwd fake;
470 
471 	memset(&fake, 0, sizeof(fake));
472 	fake.pw_name = "NOUSER";
473 	fake.pw_passwd =
474 	    "$2a$06$r3.juUaHZDlIbQaO2dS9FuYxL1W9M81R1Tc92PoSNmzvpEqLkLGrK";
475 	fake.pw_gecos = "NOUSER";
476 	fake.pw_uid = (uid_t)-1;
477 	fake.pw_gid = (gid_t)-1;
478 	fake.pw_class = "";
479 	fake.pw_dir = "/nonexist";
480 	fake.pw_shell = "/nonexist";
481 
482 	return (&fake);
483 }
484