Annotation of src/usr.bin/ssh/auth.c, Revision 1.51.2.1
1.1 markus 1: /*
1.19 deraadt 2: * Copyright (c) 2000 Markus Friedl. All rights reserved.
1.9 deraadt 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.
1.1 markus 23: */
24:
25: #include "includes.h"
1.51.2.1! brad 26: RCSID("$OpenBSD: auth.c,v 1.56 2004/07/28 09:40:29 markus Exp $");
1.22 markus 27:
28: #include <libgen.h>
1.1 markus 29:
30: #include "xmalloc.h"
1.13 markus 31: #include "match.h"
1.14 markus 32: #include "groupaccess.h"
33: #include "log.h"
1.1 markus 34: #include "servconf.h"
1.2 markus 35: #include "auth.h"
1.13 markus 36: #include "auth-options.h"
1.14 markus 37: #include "canohost.h"
1.22 markus 38: #include "buffer.h"
39: #include "bufaux.h"
1.24 markus 40: #include "uidswap.h"
1.40 markus 41: #include "misc.h"
1.42 markus 42: #include "bufaux.h"
43: #include "packet.h"
1.2 markus 44:
1.1 markus 45: /* import */
46: extern ServerOptions options;
47:
1.42 markus 48: /* Debugging messages */
49: Buffer auth_debug;
50: int auth_debug_init;
51:
1.1 markus 52: /*
1.12 markus 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.
1.1 markus 58: * If the user's shell is not executable, false will be returned.
1.4 markus 59: * Otherwise true is returned.
1.1 markus 60: */
1.5 markus 61: int
1.1 markus 62: allowed_user(struct passwd * pw)
63: {
64: struct stat st;
1.35 markus 65: const char *hostname = NULL, *ipaddr = NULL;
1.21 markus 66: char *shell;
1.1 markus 67: int i;
68:
69: /* Shouldn't be called if pw is NULL, but better safe than sorry... */
1.12 markus 70: if (!pw || !pw->pw_name)
1.1 markus 71: return 0;
72:
1.7 deraadt 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:
1.1 markus 79: /* deny if shell does not exists or is not executable */
1.34 stevesk 80: if (stat(shell, &st) != 0) {
1.47 itojun 81: logit("User %.100s not allowed because shell %.100s does not exist",
1.34 stevesk 82: pw->pw_name, shell);
1.1 markus 83: return 0;
1.34 stevesk 84: }
1.36 itojun 85: if (S_ISREG(st.st_mode) == 0 ||
86: (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) {
1.47 itojun 87: logit("User %.100s not allowed because shell %.100s is not executable",
1.34 stevesk 88: pw->pw_name, shell);
1.1 markus 89: return 0;
1.34 stevesk 90: }
1.1 markus 91:
1.35 markus 92: if (options.num_deny_users > 0 || options.num_allow_users > 0) {
1.48 markus 93: hostname = get_canonical_hostname(options.use_dns);
1.35 markus 94: ipaddr = get_remote_ipaddr();
95: }
96:
1.1 markus 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++)
1.39 markus 100: if (match_user(pw->pw_name, hostname, ipaddr,
1.34 stevesk 101: options.deny_users[i])) {
1.47 itojun 102: logit("User %.100s not allowed because listed in DenyUsers",
1.39 markus 103: pw->pw_name);
1.1 markus 104: return 0;
1.34 stevesk 105: }
1.1 markus 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++)
1.39 markus 110: if (match_user(pw->pw_name, hostname, ipaddr,
1.26 markus 111: options.allow_users[i]))
1.1 markus 112: break;
113: /* i < options.num_allow_users iff we break for loop */
1.34 stevesk 114: if (i >= options.num_allow_users) {
1.47 itojun 115: logit("User %.100s not allowed because not listed in AllowUsers",
1.34 stevesk 116: pw->pw_name);
1.1 markus 117: return 0;
1.34 stevesk 118: }
1.1 markus 119: }
120: if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
1.12 markus 121: /* Get the user's group access list (primary and supplementary) */
1.34 stevesk 122: if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
1.47 itojun 123: logit("User %.100s not allowed because not in any group",
1.34 stevesk 124: pw->pw_name);
1.1 markus 125: return 0;
1.34 stevesk 126: }
1.1 markus 127:
1.12 markus 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();
1.47 itojun 133: logit("User %.100s not allowed because a group is listed in DenyGroups",
1.34 stevesk 134: pw->pw_name);
1.1 markus 135: return 0;
1.12 markus 136: }
1.1 markus 137: /*
1.12 markus 138: * Return false if AllowGroups isn't empty and one of user's groups
1.1 markus 139: * isn't listed there
140: */
1.12 markus 141: if (options.num_allow_groups > 0)
142: if (!ga_match(options.allow_groups,
143: options.num_allow_groups)) {
144: ga_free();
1.47 itojun 145: logit("User %.100s not allowed because none of user's groups are listed in AllowGroups",
1.34 stevesk 146: pw->pw_name);
1.1 markus 147: return 0;
1.12 markus 148: }
149: ga_free();
1.1 markus 150: }
151: /* We found no reason not to let this user try to log on... */
152: return 1;
1.13 markus 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 ||
1.51.2.1! brad 164: authctxt->failures >= options.max_authtries / 2 ||
1.13 markus 165: strcmp(method, "password") == 0)
1.47 itojun 166: authlog = logit;
1.13 markus 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,
1.51.2.1! brad 176: authctxt->valid ? "" : "invalid user ",
1.29 markus 177: authctxt->user,
1.13 markus 178: get_remote_ipaddr(),
179: get_remote_port(),
180: info);
181: }
182:
183: /*
1.17 markus 184: * Check whether root logins are disallowed.
1.13 markus 185: */
186: int
1.17 markus 187: auth_root_allowed(char *method)
1.13 markus 188: {
1.17 markus 189: switch (options.permit_root_login) {
190: case PERMIT_YES:
1.13 markus 191: return 1;
1.17 markus 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) {
1.47 itojun 199: logit("Root login accepted for forced command.");
1.17 markus 200: return 1;
201: }
202: break;
1.13 markus 203: }
1.47 itojun 204: logit("ROOT LOGIN REFUSED FROM %.200s", get_remote_ipaddr());
1.22 markus 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,
1.31 deraadt 241: strlen(pw->pw_name));
1.22 markus 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: }
1.24 markus 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;
1.30 stevesk 284: HostStatus host_status;
1.24 markus 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) ||
1.31 deraadt 295: (st.st_mode & 022) != 0)) {
1.47 itojun 296: logit("Authentication refused for %.100s: "
1.24 markus 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:
1.22 markus 314:
315: /*
316: * Check a given file for security. This is defined as all components
1.44 stevesk 317: * of the path to the file must be owned by either the owner of
1.23 markus 318: * of the file or root and no directories must be group or world writable.
1.22 markus 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
1.25 provos 328: secure_filename(FILE *f, const char *file, struct passwd *pw,
329: char *err, size_t errlen)
1.22 markus 330: {
1.25 provos 331: uid_t uid = pw->pw_uid;
1.28 markus 332: char buf[MAXPATHLEN], homedir[MAXPATHLEN];
1.22 markus 333: char *cp;
1.46 markus 334: int comparehome = 0;
1.22 markus 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: }
1.46 markus 342: if (realpath(pw->pw_dir, homedir) != NULL)
343: comparehome = 1;
1.22 markus 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));
1.25 provos 361:
1.22 markus 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) {
1.31 deraadt 366: snprintf(err, errlen,
1.22 markus 367: "bad ownership or modes for directory %s", buf);
368: return -1;
369: }
370:
1.27 markus 371: /* If are passed the homedir then we can stop */
1.46 markus 372: if (comparehome && strcmp(homedir, buf) == 0) {
1.27 markus 373: debug3("secure_filename: terminating check at '%s'",
374: buf);
375: break;
376: }
1.22 markus 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: }
1.17 markus 384: return 0;
1.37 provos 385: }
386:
387: struct passwd *
388: getpwnamallow(const char *user)
389: {
1.38 provos 390: #ifdef HAVE_LOGIN_CAP
391: extern login_cap_t *lc;
392: #ifdef BSD_AUTH
393: auth_session_t *as;
394: #endif
395: #endif
1.37 provos 396: struct passwd *pw;
397:
398: pw = getpwnam(user);
1.45 stevesk 399: if (pw == NULL) {
1.51.2.1! brad 400: logit("Invalid user %.100s from %.100s",
1.45 stevesk 401: user, get_remote_ipaddr());
402: return (NULL);
403: }
404: if (!allowed_user(pw))
1.38 provos 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 ||
1.43 millert 413: auth_approval(as, lc, pw->pw_name, "ssh") <= 0) {
1.38 provos 414: debug("Approval failure for %s", user);
1.37 provos 415: pw = NULL;
1.38 provos 416: }
417: if (as != NULL)
418: auth_close(as);
419: #endif
420: #endif
1.41 markus 421: if (pw != NULL)
422: return (pwcopy(pw));
423: return (NULL);
1.42 markus 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: }
1.49 markus 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 =
1.51 djm 474: "$2a$06$r3.juUaHZDlIbQaO2dS9FuYxL1W9M81R1Tc92PoSNmzvpEqLkLGrK";
1.49 markus 475: fake.pw_gecos = "NOUSER";
1.51.2.1! brad 476: fake.pw_uid = (uid_t)-1;
! 477: fake.pw_gid = (gid_t)-1;
1.49 markus 478: fake.pw_class = "";
479: fake.pw_dir = "/nonexist";
480: fake.pw_shell = "/nonexist";
481:
482: return (&fake);
1.1 markus 483: }