Annotation of embedaddon/sudo/plugins/sudoers/auth/sudo_auth.c, revision 1.1.1.1
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
54: AUTH_ENTRY("pam", FLAG_STANDALONE, pam_init, NULL, pam_verify, pam_cleanup, pam_begin_session, pam_end_session)
55: #endif
56: #ifdef HAVE_SECURID
57: AUTH_ENTRY("SecurId", FLAG_STANDALONE, securid_init, securid_setup, securid_verify, NULL, NULL, NULL)
58: #endif
59: #ifdef HAVE_SIA_SES_INIT
60: AUTH_ENTRY("sia", FLAG_STANDALONE, NULL, sia_setup, sia_verify, sia_cleanup, NULL, NULL)
61: #endif
62: #ifdef HAVE_AIXAUTH
63: AUTH_ENTRY("aixauth", FLAG_STANDALONE, NULL, NULL, aixauth_verify, aixauth_cleanup, NULL, NULL)
64: #endif
65: #ifdef HAVE_FWTK
66: AUTH_ENTRY("fwtk", FLAG_STANDALONE, fwtk_init, NULL, fwtk_verify, fwtk_cleanup, NULL, NULL)
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
74: AUTH_ENTRY("passwd", 0, passwd_init, NULL, passwd_verify, passwd_cleanup, NULL, NULL)
75: #endif
76: #if defined(HAVE_GETPRPWNAM) && !defined(WITHOUT_PASSWD)
77: AUTH_ENTRY("secureware", 0, secureware_init, NULL, secureware_verify, secureware_cleanup, NULL, NULL)
78: #endif
79: #ifdef HAVE_AFS
80: AUTH_ENTRY("afs", 0, NULL, NULL, afs_verify, NULL, NULL, NULL)
81: #endif
82: #ifdef HAVE_DCE
83: AUTH_ENTRY("dce", 0, NULL, NULL, dce_verify, NULL, NULL, NULL)
84: #endif
85: #ifdef HAVE_KERB4
86: AUTH_ENTRY("kerb4", 0, kerb4_init, NULL, kerb4_verify, NULL, NULL, NULL)
87: #endif
88: #ifdef HAVE_KERB5
89: AUTH_ENTRY("kerb5", 0, kerb5_init, kerb5_setup, kerb5_verify, kerb5_cleanup, NULL, NULL)
90: #endif
91: #ifdef HAVE_SKEY
92: AUTH_ENTRY("S/Key", 0, NULL, rfc1938_setup, rfc1938_verify, NULL, NULL, NULL)
93: #endif
94: #ifdef HAVE_OPIE
95: AUTH_ENTRY("OPIE", 0, NULL, rfc1938_setup, rfc1938_verify, NULL, NULL, NULL)
96: #endif
97: AUTH_ENTRY(NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL)
98: };
99:
100: static int standalone;
101:
102: extern char **NewArgv; /* XXX - for auditing */
103:
104: static void pass_warn(void);
105:
106: int
107: sudo_auth_init(struct passwd *pw)
108: {
109: sudo_auth *auth;
110: int status = AUTH_SUCCESS;
111:
112: if (auth_switch[0].name == NULL)
113: return TRUE;
114:
115: /* Make sure we haven't mixed standalone and shared auth methods. */
116: standalone = IS_STANDALONE(&auth_switch[0]);
117: if (standalone && auth_switch[1].name != NULL) {
118: audit_failure(NewArgv, "invalid authentication methods");
119: log_error(0, _("Invalid authentication methods compiled into sudo! "
120: "You may mix standalone and non-standalone authentication."));
121: return -1;
122: }
123:
124: /* Set FLAG_ONEANDONLY if there is only one auth method. */
125: if (auth_switch[1].name == NULL)
126: SET(auth_switch[0].flags, FLAG_ONEANDONLY);
127:
128: /* Initialize auth methods and unconfigure the method if necessary. */
129: for (auth = auth_switch; auth->name; auth++) {
130: if (auth->init && !IS_DISABLED(auth)) {
131: if (NEEDS_USER(auth))
132: set_perms(PERM_USER);
133:
134: status = (auth->init)(pw, auth);
135:
136: if (NEEDS_USER(auth))
137: restore_perms();
138:
139: if (status == AUTH_FAILURE)
140: SET(auth->flags, FLAG_DISABLED);
141: else if (status == AUTH_FATAL) {
142: /* XXX log */
143: audit_failure(NewArgv, "authentication failure");
144: break; /* assume error msg already printed */
145: }
146: }
147: }
148: return status == AUTH_FATAL ? -1 : TRUE;
149: }
150:
151: int
152: sudo_auth_cleanup(struct passwd *pw)
153: {
154: sudo_auth *auth;
155: int status = AUTH_SUCCESS;
156:
157: /* Call cleanup routines. */
158: for (auth = auth_switch; auth->name; auth++) {
159: if (auth->cleanup && !IS_DISABLED(auth)) {
160: if (NEEDS_USER(auth))
161: set_perms(PERM_USER);
162:
163: status = (auth->cleanup)(pw, auth);
164:
165: if (NEEDS_USER(auth))
166: restore_perms();
167:
168: if (status == AUTH_FATAL) {
169: /* XXX log */
170: audit_failure(NewArgv, "authentication failure");
171: break; /* assume error msg already printed */
172: }
173: }
174: }
175: return status == AUTH_FATAL ? -1 : TRUE;
176: }
177:
178: int
179: verify_user(struct passwd *pw, char *prompt)
180: {
181: int counter = def_passwd_tries + 1;
182: int success = AUTH_FAILURE;
183: int flags, status, rval;
184: char *p;
185: sudo_auth *auth;
186: sigaction_t sa, osa;
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");
198: log_error(0,
199: _("There are no authentication methods compiled into sudo! "
200: "If you want to turn off authentication, use the "
201: "--disable-authentication configure option."));
202: return -1;
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");
222: return -1; /* assume error msg already printed */
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);
262: rval = TRUE;
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;
271: log_error(flags, ngettext("%d incorrect password attempt",
272: "%d incorrect password attempts",
273: def_passwd_tries - counter), def_passwd_tries - counter);
274: }
275: audit_failure(NewArgv, "authentication failure");
276: rval = FALSE;
277: break;
278: case AUTH_FATAL:
279: default:
280: audit_failure(NewArgv, "authentication failure");
281: rval = -1;
282: break;
283: }
284:
285: return rval;
286: }
287:
288: int
289: sudo_auth_begin_session(struct passwd *pw)
290: {
291: sudo_auth *auth;
292: int status;
293:
294: for (auth = auth_switch; auth->name; auth++) {
295: if (auth->begin_session && !IS_DISABLED(auth)) {
296: status = (auth->begin_session)(pw, auth);
297: if (status == AUTH_FATAL) {
298: /* XXX log */
299: audit_failure(NewArgv, "authentication failure");
300: return -1; /* assume error msg already printed */
301: }
302: }
303: }
304: return TRUE;
305: }
306:
307: int
308: sudo_auth_end_session(struct passwd *pw)
309: {
310: sudo_auth *auth;
311: int status;
312:
313: for (auth = auth_switch; auth->name; auth++) {
314: if (auth->end_session && !IS_DISABLED(auth)) {
315: status = (auth->end_session)(pw, auth);
316: if (status == AUTH_FATAL) {
317: /* XXX log */
318: return -1; /* assume error msg already printed */
319: }
320: }
321: }
322: return TRUE;
323: }
324:
325: static void
326: pass_warn(void)
327: {
328: const char *warning = def_badpass_message;
329:
330: #ifdef INSULT
331: if (def_insults)
332: warning = INSULT;
333: #endif
334: sudo_printf(SUDO_CONV_ERROR_MSG, "%s\n", warning);
335: }
336:
337: char *
338: auth_getpass(const char *prompt, int timeout, int type)
339: {
340: struct sudo_conv_message msg;
341: struct sudo_conv_reply repl;
342:
343: /* Mask user input if pwfeedback set and echo is off. */
344: if (type == SUDO_CONV_PROMPT_ECHO_OFF && def_pwfeedback)
345: type = SUDO_CONV_PROMPT_MASK;
346:
347: /* If visiblepw set, do not error out if there is no tty. */
348: if (def_visiblepw)
349: type |= SUDO_CONV_PROMPT_ECHO_OK;
350:
351: /* Call conversation function */
352: memset(&msg, 0, sizeof(msg));
353: msg.msg_type = type;
354: msg.timeout = def_passwd_timeout * 60;
355: msg.msg = prompt;
356: memset(&repl, 0, sizeof(repl));
357: sudo_conv(1, &msg, &repl);
358: /* XXX - check for ENOTTY? */
359: return repl.reply;
360: }
361:
362: void
363: dump_auth_methods(void)
364: {
365: sudo_auth *auth;
366:
367: sudo_printf(SUDO_CONV_INFO_MSG, _("Authentication methods:"));
368: for (auth = auth_switch; auth->name; auth++)
369: sudo_printf(SUDO_CONV_INFO_MSG, " '%s'", auth->name);
370: sudo_printf(SUDO_CONV_INFO_MSG, "\n");
371: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>