Annotation of embedaddon/sudo/plugins/sudoers/auth/sudo_auth.c, revision 1.1.1.2
1.1 misho 1: /*
2: * Copyright (c) 1999-2005, 2008-2010 Todd C. Miller <Todd.Miller@courtesan.com>
3: *
4: * Permission to use, copy, modify, and distribute this software for any
5: * purpose with or without fee is hereby granted, provided that the above
6: * copyright notice and this permission notice appear in all copies.
7: *
8: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15: *
16: * Sponsored in part by the Defense Advanced Research Projects
17: * Agency (DARPA) and Air Force Research Laboratory, Air Force
18: * Materiel Command, USAF, under agreement number F39502-99-1-0512.
19: */
20:
21: #include <config.h>
22:
23: #include <sys/types.h>
24: #include <sys/param.h>
25: #include <stdio.h>
26: #ifdef STDC_HEADERS
27: # include <stdlib.h>
28: # include <stddef.h>
29: #else
30: # ifdef HAVE_STDLIB_H
31: # include <stdlib.h>
32: # endif
33: #endif /* STDC_HEADERS */
34: #ifdef HAVE_STRING_H
35: # include <string.h>
36: #endif /* HAVE_STRING_H */
37: #ifdef HAVE_STRINGS_H
38: # include <strings.h>
39: #endif /* HAVE_STRINGS_H */
40: #ifdef HAVE_UNISTD_H
41: # include <unistd.h>
42: #endif /* HAVE_UNISTD_H */
43: #include <pwd.h>
44: #include <time.h>
45: #include <signal.h>
46:
47: #include "sudoers.h"
48: #include "sudo_auth.h"
49: #include "insults.h"
50:
51: static sudo_auth auth_switch[] = {
52: /* Standalone entries first */
53: #ifdef HAVE_PAM
1.1.1.2 ! misho 54: AUTH_ENTRY("pam", FLAG_STANDALONE, sudo_pam_init, NULL, sudo_pam_verify, sudo_pam_cleanup, sudo_pam_begin_session, sudo_pam_end_session)
1.1 misho 55: #endif
56: #ifdef HAVE_SECURID
1.1.1.2 ! misho 57: AUTH_ENTRY("SecurId", FLAG_STANDALONE, sudo_securid_init, sudo_securid_setup, sudo_securid_verify, NULL, NULL, NULL)
1.1 misho 58: #endif
59: #ifdef HAVE_SIA_SES_INIT
1.1.1.2 ! misho 60: AUTH_ENTRY("sia", FLAG_STANDALONE, NULL, sudo_sia_setup, sudo_sia_verify, sudo_sia_cleanup, NULL, NULL)
1.1 misho 61: #endif
62: #ifdef HAVE_AIXAUTH
1.1.1.2 ! misho 63: AUTH_ENTRY("aixauth", FLAG_STANDALONE, NULL, NULL, sudo_aix_verify, sudo_aix_cleanup, NULL, NULL)
1.1 misho 64: #endif
65: #ifdef HAVE_FWTK
1.1.1.2 ! misho 66: AUTH_ENTRY("fwtk", FLAG_STANDALONE, sudo_fwtk_init, NULL, sudo_fwtk_verify, sudo_fwtk_cleanup, NULL, NULL)
1.1 misho 67: #endif
68: #ifdef HAVE_BSD_AUTH_H
69: AUTH_ENTRY("bsdauth", FLAG_STANDALONE, bsdauth_init, NULL, bsdauth_verify, bsdauth_cleanup, NULL, NULL)
70: #endif
71:
72: /* Non-standalone entries */
73: #ifndef WITHOUT_PASSWD
1.1.1.2 ! misho 74: AUTH_ENTRY("passwd", 0, sudo_passwd_init, NULL, sudo_passwd_verify, sudo_passwd_cleanup, NULL, NULL)
1.1 misho 75: #endif
76: #if defined(HAVE_GETPRPWNAM) && !defined(WITHOUT_PASSWD)
1.1.1.2 ! misho 77: AUTH_ENTRY("secureware", 0, sudo_secureware_init, NULL, sudo_secureware_verify, sudo_secureware_cleanup, NULL, NULL)
1.1 misho 78: #endif
79: #ifdef HAVE_AFS
1.1.1.2 ! misho 80: AUTH_ENTRY("afs", 0, NULL, NULL, sudo_afs_verify, NULL, NULL, NULL)
1.1 misho 81: #endif
82: #ifdef HAVE_DCE
1.1.1.2 ! misho 83: AUTH_ENTRY("dce", 0, NULL, NULL, sudo_dce_verify, NULL, NULL, NULL)
1.1 misho 84: #endif
85: #ifdef HAVE_KERB5
1.1.1.2 ! misho 86: AUTH_ENTRY("kerb5", 0, sudo_krb5_init, sudo_krb5_setup, sudo_krb5_verify, sudo_krb5_cleanup, NULL, NULL)
1.1 misho 87: #endif
88: #ifdef HAVE_SKEY
1.1.1.2 ! misho 89: AUTH_ENTRY("S/Key", 0, NULL, sudo_rfc1938_setup, sudo_rfc1938_verify, NULL, NULL, NULL)
1.1 misho 90: #endif
91: #ifdef HAVE_OPIE
1.1.1.2 ! misho 92: AUTH_ENTRY("OPIE", 0, NULL, sudo_rfc1938_setup, sudo_rfc1938_verify, NULL, NULL, NULL)
1.1 misho 93: #endif
94: AUTH_ENTRY(NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL)
95: };
96:
97: static int standalone;
98:
99: extern char **NewArgv; /* XXX - for auditing */
100:
101: static void pass_warn(void);
102:
103: int
104: sudo_auth_init(struct passwd *pw)
105: {
106: sudo_auth *auth;
107: int status = AUTH_SUCCESS;
1.1.1.2 ! misho 108: debug_decl(sudo_auth_init, SUDO_DEBUG_AUTH)
1.1 misho 109:
110: if (auth_switch[0].name == NULL)
1.1.1.2 ! misho 111: debug_return_int(true);
1.1 misho 112:
113: /* Make sure we haven't mixed standalone and shared auth methods. */
114: standalone = IS_STANDALONE(&auth_switch[0]);
115: if (standalone && auth_switch[1].name != NULL) {
116: audit_failure(NewArgv, "invalid authentication methods");
1.1.1.2 ! misho 117: log_fatal(0, _("Invalid authentication methods compiled into sudo! "
1.1 misho 118: "You may mix standalone and non-standalone authentication."));
1.1.1.2 ! misho 119: debug_return_int(-1);
1.1 misho 120: }
121:
122: /* Set FLAG_ONEANDONLY if there is only one auth method. */
123: if (auth_switch[1].name == NULL)
124: SET(auth_switch[0].flags, FLAG_ONEANDONLY);
125:
126: /* Initialize auth methods and unconfigure the method if necessary. */
127: for (auth = auth_switch; auth->name; auth++) {
128: if (auth->init && !IS_DISABLED(auth)) {
129: if (NEEDS_USER(auth))
130: set_perms(PERM_USER);
131:
132: status = (auth->init)(pw, auth);
133:
134: if (NEEDS_USER(auth))
135: restore_perms();
136:
137: if (status == AUTH_FAILURE)
138: SET(auth->flags, FLAG_DISABLED);
139: else if (status == AUTH_FATAL) {
140: /* XXX log */
141: audit_failure(NewArgv, "authentication failure");
142: break; /* assume error msg already printed */
143: }
144: }
145: }
1.1.1.2 ! misho 146: debug_return_int(status == AUTH_FATAL ? -1 : true);
1.1 misho 147: }
148:
149: int
150: sudo_auth_cleanup(struct passwd *pw)
151: {
152: sudo_auth *auth;
153: int status = AUTH_SUCCESS;
1.1.1.2 ! misho 154: debug_decl(sudo_auth_cleanup, SUDO_DEBUG_AUTH)
1.1 misho 155:
156: /* Call cleanup routines. */
157: for (auth = auth_switch; auth->name; auth++) {
158: if (auth->cleanup && !IS_DISABLED(auth)) {
159: if (NEEDS_USER(auth))
160: set_perms(PERM_USER);
161:
162: status = (auth->cleanup)(pw, auth);
163:
164: if (NEEDS_USER(auth))
165: restore_perms();
166:
167: if (status == AUTH_FATAL) {
168: /* XXX log */
169: audit_failure(NewArgv, "authentication failure");
170: break; /* assume error msg already printed */
171: }
172: }
173: }
1.1.1.2 ! misho 174: debug_return_int(status == AUTH_FATAL ? -1 : true);
1.1 misho 175: }
176:
177: int
178: verify_user(struct passwd *pw, char *prompt)
179: {
180: int counter = def_passwd_tries + 1;
181: int success = AUTH_FAILURE;
182: int flags, status, rval;
183: char *p;
184: sudo_auth *auth;
185: sigaction_t sa, osa;
1.1.1.2 ! misho 186: debug_decl(verify_user, SUDO_DEBUG_AUTH)
1.1 misho 187:
188: /* Enable suspend during password entry. */
189: sigemptyset(&sa.sa_mask);
190: sa.sa_flags = SA_RESTART;
191: sa.sa_handler = SIG_DFL;
192: (void) sigaction(SIGTSTP, &sa, &osa);
193:
194: /* Make sure we have at least one auth method. */
195: /* XXX - check FLAG_DISABLED too */
196: if (auth_switch[0].name == NULL) {
197: audit_failure(NewArgv, "no authentication methods");
1.1.1.2 ! misho 198: log_fatal(0,
1.1 misho 199: _("There are no authentication methods compiled into sudo! "
200: "If you want to turn off authentication, use the "
201: "--disable-authentication configure option."));
1.1.1.2 ! misho 202: debug_return_int(-1);
1.1 misho 203: }
204:
205: while (--counter) {
206: /* Do any per-method setup and unconfigure the method if needed */
207: for (auth = auth_switch; auth->name; auth++) {
208: if (auth->setup && !IS_DISABLED(auth)) {
209: if (NEEDS_USER(auth))
210: set_perms(PERM_USER);
211:
212: status = (auth->setup)(pw, &prompt, auth);
213:
214: if (NEEDS_USER(auth))
215: restore_perms();
216:
217: if (status == AUTH_FAILURE)
218: SET(auth->flags, FLAG_DISABLED);
219: else if (status == AUTH_FATAL) {
220: /* XXX log */
221: audit_failure(NewArgv, "authentication failure");
1.1.1.2 ! misho 222: debug_return_int(-1);/* assume error msg already printed */
1.1 misho 223: }
224: }
225: }
226:
227: /* Get the password unless the auth function will do it for us */
228: if (standalone) {
229: p = prompt;
230: } else {
231: p = auth_getpass(prompt, def_passwd_timeout * 60,
232: SUDO_CONV_PROMPT_ECHO_OFF);
233: if (p == NULL)
234: break;
235: }
236:
237: /* Call authentication functions. */
238: for (auth = auth_switch; auth->name; auth++) {
239: if (IS_DISABLED(auth))
240: continue;
241:
242: if (NEEDS_USER(auth))
243: set_perms(PERM_USER);
244:
245: success = auth->status = (auth->verify)(pw, p, auth);
246:
247: if (NEEDS_USER(auth))
248: restore_perms();
249:
250: if (auth->status != AUTH_FAILURE)
251: goto done;
252: }
253: if (!standalone)
254: zero_bytes(p, strlen(p));
255: pass_warn();
256: }
257:
258: done:
259: switch (success) {
260: case AUTH_SUCCESS:
261: (void) sigaction(SIGTSTP, &osa, NULL);
1.1.1.2 ! misho 262: rval = true;
1.1 misho 263: break;
264: case AUTH_INTR:
265: case AUTH_FAILURE:
266: if (counter != def_passwd_tries) {
267: if (def_mail_badpass || def_mail_always)
268: flags = 0;
269: else
270: flags = NO_MAIL;
1.1.1.2 ! misho 271: log_fatal(flags, ngettext("%d incorrect password attempt",
1.1 misho 272: "%d incorrect password attempts",
273: def_passwd_tries - counter), def_passwd_tries - counter);
274: }
275: audit_failure(NewArgv, "authentication failure");
1.1.1.2 ! misho 276: rval = false;
1.1 misho 277: break;
278: case AUTH_FATAL:
279: default:
280: audit_failure(NewArgv, "authentication failure");
281: rval = -1;
282: break;
283: }
284:
1.1.1.2 ! misho 285: debug_return_int(rval);
1.1 misho 286: }
287:
288: int
1.1.1.2 ! misho 289: sudo_auth_begin_session(struct passwd *pw, char **user_env[])
1.1 misho 290: {
291: sudo_auth *auth;
292: int status;
1.1.1.2 ! misho 293: debug_decl(auth_begin_session, SUDO_DEBUG_AUTH)
1.1 misho 294:
295: for (auth = auth_switch; auth->name; auth++) {
296: if (auth->begin_session && !IS_DISABLED(auth)) {
1.1.1.2 ! misho 297: status = (auth->begin_session)(pw, user_env, auth);
1.1 misho 298: if (status == AUTH_FATAL) {
299: /* XXX log */
300: audit_failure(NewArgv, "authentication failure");
1.1.1.2 ! misho 301: debug_return_bool(-1); /* assume error msg already printed */
1.1 misho 302: }
303: }
304: }
1.1.1.2 ! misho 305: debug_return_bool(true);
1.1 misho 306: }
307:
308: int
309: sudo_auth_end_session(struct passwd *pw)
310: {
311: sudo_auth *auth;
312: int status;
1.1.1.2 ! misho 313: debug_decl(auth_end_session, SUDO_DEBUG_AUTH)
1.1 misho 314:
315: for (auth = auth_switch; auth->name; auth++) {
316: if (auth->end_session && !IS_DISABLED(auth)) {
317: status = (auth->end_session)(pw, auth);
318: if (status == AUTH_FATAL) {
319: /* XXX log */
1.1.1.2 ! misho 320: debug_return_bool(-1); /* assume error msg already printed */
1.1 misho 321: }
322: }
323: }
1.1.1.2 ! misho 324: debug_return_bool(true);
1.1 misho 325: }
326:
327: static void
328: pass_warn(void)
329: {
330: const char *warning = def_badpass_message;
1.1.1.2 ! misho 331: debug_decl(pass_warn, SUDO_DEBUG_AUTH)
1.1 misho 332:
333: #ifdef INSULT
334: if (def_insults)
335: warning = INSULT;
336: #endif
337: sudo_printf(SUDO_CONV_ERROR_MSG, "%s\n", warning);
1.1.1.2 ! misho 338:
! 339: debug_return;
1.1 misho 340: }
341:
342: char *
343: auth_getpass(const char *prompt, int timeout, int type)
344: {
345: struct sudo_conv_message msg;
346: struct sudo_conv_reply repl;
1.1.1.2 ! misho 347: debug_decl(auth_getpass, SUDO_DEBUG_AUTH)
1.1 misho 348:
349: /* Mask user input if pwfeedback set and echo is off. */
350: if (type == SUDO_CONV_PROMPT_ECHO_OFF && def_pwfeedback)
351: type = SUDO_CONV_PROMPT_MASK;
352:
353: /* If visiblepw set, do not error out if there is no tty. */
354: if (def_visiblepw)
355: type |= SUDO_CONV_PROMPT_ECHO_OK;
356:
357: /* Call conversation function */
358: memset(&msg, 0, sizeof(msg));
359: msg.msg_type = type;
360: msg.timeout = def_passwd_timeout * 60;
361: msg.msg = prompt;
362: memset(&repl, 0, sizeof(repl));
363: sudo_conv(1, &msg, &repl);
364: /* XXX - check for ENOTTY? */
1.1.1.2 ! misho 365: debug_return_str_masked(repl.reply);
1.1 misho 366: }
367:
368: void
369: dump_auth_methods(void)
370: {
371: sudo_auth *auth;
1.1.1.2 ! misho 372: debug_decl(dump_auth_methods, SUDO_DEBUG_AUTH)
1.1 misho 373:
374: sudo_printf(SUDO_CONV_INFO_MSG, _("Authentication methods:"));
375: for (auth = auth_switch; auth->name; auth++)
376: sudo_printf(SUDO_CONV_INFO_MSG, " '%s'", auth->name);
377: sudo_printf(SUDO_CONV_INFO_MSG, "\n");
1.1.1.2 ! misho 378:
! 379: debug_return;
1.1 misho 380: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>