Annotation of src/usr.bin/ssh/auth.c, Revision 1.34
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.34 ! stevesk 26: RCSID("$OpenBSD: auth.c,v 1.33 2002/02/28 19:36:28 stevesk 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"
41: #include "tildexpand.h"
1.2 markus 42:
1.1 markus 43: /* import */
44: extern ServerOptions options;
45:
46: /*
1.12 markus 47: * Check if the user is allowed to log in via ssh. If user is listed
48: * in DenyUsers or one of user's groups is listed in DenyGroups, false
49: * will be returned. If AllowUsers isn't empty and user isn't listed
50: * there, or if AllowGroups isn't empty and one of user's groups isn't
51: * listed there, false will be returned.
1.1 markus 52: * If the user's shell is not executable, false will be returned.
1.4 markus 53: * Otherwise true is returned.
1.1 markus 54: */
1.5 markus 55: int
1.1 markus 56: allowed_user(struct passwd * pw)
57: {
58: struct stat st;
1.21 markus 59: char *shell;
1.1 markus 60: int i;
61:
62: /* Shouldn't be called if pw is NULL, but better safe than sorry... */
1.12 markus 63: if (!pw || !pw->pw_name)
1.1 markus 64: return 0;
65:
1.7 deraadt 66: /*
67: * Get the shell from the password data. An empty shell field is
68: * legal, and means /bin/sh.
69: */
70: shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
71:
1.1 markus 72: /* deny if shell does not exists or is not executable */
1.34 ! stevesk 73: if (stat(shell, &st) != 0) {
! 74: log("User %.100s not allowed because shell %.100s does not exist",
! 75: pw->pw_name, shell);
1.1 markus 76: return 0;
1.34 ! stevesk 77: }
! 78: if (!((st.st_mode & S_IFREG) && (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)))) {
! 79: log("User %.100s not allowed because shell %.100s is not executable",
! 80: pw->pw_name, shell);
1.1 markus 81: return 0;
1.34 ! stevesk 82: }
1.1 markus 83:
84: /* Return false if user is listed in DenyUsers */
85: if (options.num_deny_users > 0) {
86: for (i = 0; i < options.num_deny_users; i++)
1.33 stevesk 87: if (match_user(pw->pw_name, options.verify_reverse_mapping,
1.34 ! stevesk 88: options.deny_users[i])) {
! 89: log("User %.100s not allowed because listed in DenyUsers",
! 90: pw->pw_name);
1.1 markus 91: return 0;
1.34 ! stevesk 92: }
1.1 markus 93: }
94: /* Return false if AllowUsers isn't empty and user isn't listed there */
95: if (options.num_allow_users > 0) {
96: for (i = 0; i < options.num_allow_users; i++)
1.33 stevesk 97: if (match_user(pw->pw_name, options.verify_reverse_mapping,
1.26 markus 98: options.allow_users[i]))
1.1 markus 99: break;
100: /* i < options.num_allow_users iff we break for loop */
1.34 ! stevesk 101: if (i >= options.num_allow_users) {
! 102: log("User %.100s not allowed because not listed in AllowUsers",
! 103: pw->pw_name);
1.1 markus 104: return 0;
1.34 ! stevesk 105: }
1.1 markus 106: }
107: if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
1.12 markus 108: /* Get the user's group access list (primary and supplementary) */
1.34 ! stevesk 109: if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
! 110: log("User %.100s not allowed because not in any group",
! 111: pw->pw_name);
1.1 markus 112: return 0;
1.34 ! stevesk 113: }
1.1 markus 114:
1.12 markus 115: /* Return false if one of user's groups is listed in DenyGroups */
116: if (options.num_deny_groups > 0)
117: if (ga_match(options.deny_groups,
118: options.num_deny_groups)) {
119: ga_free();
1.34 ! stevesk 120: log("User %.100s not allowed because a group is listed in DenyGroups",
! 121: pw->pw_name);
1.1 markus 122: return 0;
1.12 markus 123: }
1.1 markus 124: /*
1.12 markus 125: * Return false if AllowGroups isn't empty and one of user's groups
1.1 markus 126: * isn't listed there
127: */
1.12 markus 128: if (options.num_allow_groups > 0)
129: if (!ga_match(options.allow_groups,
130: options.num_allow_groups)) {
131: ga_free();
1.34 ! stevesk 132: log("User %.100s not allowed because none of user's groups are listed in AllowGroups",
! 133: pw->pw_name);
1.1 markus 134: return 0;
1.12 markus 135: }
136: ga_free();
1.1 markus 137: }
138: /* We found no reason not to let this user try to log on... */
139: return 1;
1.13 markus 140: }
141:
142: Authctxt *
143: authctxt_new(void)
144: {
1.16 stevesk 145: Authctxt *authctxt = xmalloc(sizeof(*authctxt));
146: memset(authctxt, 0, sizeof(*authctxt));
147: return authctxt;
1.13 markus 148: }
149:
150: void
151: auth_log(Authctxt *authctxt, int authenticated, char *method, char *info)
152: {
153: void (*authlog) (const char *fmt,...) = verbose;
154: char *authmsg;
155:
156: /* Raise logging level */
157: if (authenticated == 1 ||
158: !authctxt->valid ||
159: authctxt->failures >= AUTH_FAIL_LOG ||
160: strcmp(method, "password") == 0)
161: authlog = log;
162:
163: if (authctxt->postponed)
164: authmsg = "Postponed";
165: else
166: authmsg = authenticated ? "Accepted" : "Failed";
167:
168: authlog("%s %s for %s%.100s from %.200s port %d%s",
169: authmsg,
170: method,
171: authctxt->valid ? "" : "illegal user ",
1.29 markus 172: authctxt->user,
1.13 markus 173: get_remote_ipaddr(),
174: get_remote_port(),
175: info);
176: }
177:
178: /*
1.17 markus 179: * Check whether root logins are disallowed.
1.13 markus 180: */
181: int
1.17 markus 182: auth_root_allowed(char *method)
1.13 markus 183: {
1.17 markus 184: switch (options.permit_root_login) {
185: case PERMIT_YES:
1.13 markus 186: return 1;
1.17 markus 187: break;
188: case PERMIT_NO_PASSWD:
189: if (strcmp(method, "password") != 0)
190: return 1;
191: break;
192: case PERMIT_FORCED_ONLY:
193: if (forced_command) {
194: log("Root login accepted for forced command.");
195: return 1;
196: }
197: break;
1.13 markus 198: }
1.17 markus 199: log("ROOT LOGIN REFUSED FROM %.200s", get_remote_ipaddr());
1.22 markus 200: return 0;
201: }
202:
203:
204: /*
205: * Given a template and a passwd structure, build a filename
206: * by substituting % tokenised options. Currently, %% becomes '%',
207: * %h becomes the home directory and %u the username.
208: *
209: * This returns a buffer allocated by xmalloc.
210: */
211: char *
212: expand_filename(const char *filename, struct passwd *pw)
213: {
214: Buffer buffer;
215: char *file;
216: const char *cp;
217:
218: /*
219: * Build the filename string in the buffer by making the appropriate
220: * substitutions to the given file name.
221: */
222: buffer_init(&buffer);
223: for (cp = filename; *cp; cp++) {
224: if (cp[0] == '%' && cp[1] == '%') {
225: buffer_append(&buffer, "%", 1);
226: cp++;
227: continue;
228: }
229: if (cp[0] == '%' && cp[1] == 'h') {
230: buffer_append(&buffer, pw->pw_dir, strlen(pw->pw_dir));
231: cp++;
232: continue;
233: }
234: if (cp[0] == '%' && cp[1] == 'u') {
235: buffer_append(&buffer, pw->pw_name,
1.31 deraadt 236: strlen(pw->pw_name));
1.22 markus 237: cp++;
238: continue;
239: }
240: buffer_append(&buffer, cp, 1);
241: }
242: buffer_append(&buffer, "\0", 1);
243:
244: /*
245: * Ensure that filename starts anchored. If not, be backward
246: * compatible and prepend the '%h/'
247: */
248: file = xmalloc(MAXPATHLEN);
249: cp = buffer_ptr(&buffer);
250: if (*cp != '/')
251: snprintf(file, MAXPATHLEN, "%s/%s", pw->pw_dir, cp);
252: else
253: strlcpy(file, cp, MAXPATHLEN);
254:
255: buffer_free(&buffer);
256: return file;
257: }
258:
259: char *
260: authorized_keys_file(struct passwd *pw)
261: {
262: return expand_filename(options.authorized_keys_file, pw);
263: }
264:
265: char *
266: authorized_keys_file2(struct passwd *pw)
267: {
268: return expand_filename(options.authorized_keys_file2, pw);
269: }
1.24 markus 270:
271: /* return ok if key exists in sysfile or userfile */
272: HostStatus
273: check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host,
274: const char *sysfile, const char *userfile)
275: {
276: Key *found;
277: char *user_hostfile;
278: struct stat st;
1.30 stevesk 279: HostStatus host_status;
1.24 markus 280:
281: /* Check if we know the host and its host key. */
282: found = key_new(key->type);
283: host_status = check_host_in_hostfile(sysfile, host, key, found, NULL);
284:
285: if (host_status != HOST_OK && userfile != NULL) {
286: user_hostfile = tilde_expand_filename(userfile, pw->pw_uid);
287: if (options.strict_modes &&
288: (stat(user_hostfile, &st) == 0) &&
289: ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
1.31 deraadt 290: (st.st_mode & 022) != 0)) {
1.24 markus 291: log("Authentication refused for %.100s: "
292: "bad owner or modes for %.200s",
293: pw->pw_name, user_hostfile);
294: } else {
295: temporarily_use_uid(pw);
296: host_status = check_host_in_hostfile(user_hostfile,
297: host, key, found, NULL);
298: restore_uid();
299: }
300: xfree(user_hostfile);
301: }
302: key_free(found);
303:
304: debug2("check_key_in_hostfiles: key %s for %s", host_status == HOST_OK ?
305: "ok" : "not found", host);
306: return host_status;
307: }
308:
1.22 markus 309:
310: /*
311: * Check a given file for security. This is defined as all components
312: * of the path to the file must either be owned by either the owner of
1.23 markus 313: * of the file or root and no directories must be group or world writable.
1.22 markus 314: *
315: * XXX Should any specific check be done for sym links ?
316: *
317: * Takes an open file descriptor, the file name, a uid and and
318: * error buffer plus max size as arguments.
319: *
320: * Returns 0 on success and -1 on failure
321: */
322: int
1.25 provos 323: secure_filename(FILE *f, const char *file, struct passwd *pw,
324: char *err, size_t errlen)
1.22 markus 325: {
1.25 provos 326: uid_t uid = pw->pw_uid;
1.28 markus 327: char buf[MAXPATHLEN], homedir[MAXPATHLEN];
1.22 markus 328: char *cp;
329: struct stat st;
330:
331: if (realpath(file, buf) == NULL) {
332: snprintf(err, errlen, "realpath %s failed: %s", file,
333: strerror(errno));
334: return -1;
335: }
1.28 markus 336: if (realpath(pw->pw_dir, homedir) == NULL) {
337: snprintf(err, errlen, "realpath %s failed: %s", pw->pw_dir,
338: strerror(errno));
339: return -1;
340: }
1.22 markus 341:
342: /* check the open file to avoid races */
343: if (fstat(fileno(f), &st) < 0 ||
344: (st.st_uid != 0 && st.st_uid != uid) ||
345: (st.st_mode & 022) != 0) {
346: snprintf(err, errlen, "bad ownership or modes for file %s",
347: buf);
348: return -1;
349: }
350:
351: /* for each component of the canonical path, walking upwards */
352: for (;;) {
353: if ((cp = dirname(buf)) == NULL) {
354: snprintf(err, errlen, "dirname() failed");
355: return -1;
356: }
357: strlcpy(buf, cp, sizeof(buf));
1.25 provos 358:
1.22 markus 359: debug3("secure_filename: checking '%s'", buf);
360: if (stat(buf, &st) < 0 ||
361: (st.st_uid != 0 && st.st_uid != uid) ||
362: (st.st_mode & 022) != 0) {
1.31 deraadt 363: snprintf(err, errlen,
1.22 markus 364: "bad ownership or modes for directory %s", buf);
365: return -1;
366: }
367:
1.27 markus 368: /* If are passed the homedir then we can stop */
1.28 markus 369: if (strcmp(homedir, buf) == 0) {
1.27 markus 370: debug3("secure_filename: terminating check at '%s'",
371: buf);
372: break;
373: }
1.22 markus 374: /*
375: * dirname should always complete with a "/" path,
376: * but we can be paranoid and check for "." too
377: */
378: if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0))
379: break;
380: }
1.17 markus 381: return 0;
1.1 markus 382: }