2 * Copyright (c) 1999-2001 Todd C. Miller <Todd.Miller@courtesan.com>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
19 * 4. Products derived from this software may not be called "Sudo" nor
20 * may "Sudo" appear in their names without specific prior written
21 * permission from the author.
23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
25 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
26 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 #include <sys/types.h>
38 #include <sys/param.h>
47 #endif /* STDC_HEADERS */
49 # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
54 # ifdef HAVE_STRINGS_H
57 #endif /* HAVE_STRING_H */
60 #endif /* HAVE_UNISTD_H */
66 #include "sudo_auth.h"
70 static const char rcsid[] = "$Sudo: sudo_auth.c,v 1.25 2001/12/14 19:52:54 millert Exp $";
73 sudo_auth auth_switch[] = {
74 #ifdef AUTH_STANDALONE
77 # ifndef WITHOUT_PASSWD
78 AUTH_ENTRY(0, "passwd", passwd_init, NULL, passwd_verify, NULL)
80 # if defined(HAVE_GETPRPWNAM) && !defined(WITHOUT_PASSWD)
81 AUTH_ENTRY(0, "secureware", secureware_init, NULL, secureware_verify, NULL)
84 AUTH_ENTRY(0, "afs", NULL, NULL, afs_verify, NULL)
87 AUTH_ENTRY(0, "dce", NULL, NULL, dce_verify, NULL)
90 AUTH_ENTRY(0, "kerb4", kerb4_init, NULL, kerb4_verify, NULL)
93 AUTH_ENTRY(0, "kerb5", kerb5_init, NULL, kerb5_verify, kerb5_cleanup)
96 AUTH_ENTRY(0, "S/Key", NULL, rfc1938_setup, rfc1938_verify, NULL)
99 AUTH_ENTRY(0, "OPIE", NULL, rfc1938_setup, rfc1938_verify, NULL)
101 #endif /* AUTH_STANDALONE */
102 AUTH_ENTRY(0, NULL, NULL, NULL, NULL, NULL)
105 int nil_pw; /* I hate resorting to globals like this... */
108 verify_user(pw, prompt)
112 int counter = def_ival(I_PASSWD_TRIES) + 1;
113 int success = AUTH_FAILURE;
120 /* Enable suspend during password entry. */
121 sigemptyset(&sa.sa_mask);
122 sa.sa_flags = SA_RESTART;
123 sa.sa_handler = SIG_DFL;
124 (void) sigaction(SIGTSTP, &sa, &osa);
126 /* Make sure we have at least one auth method. */
127 if (auth_switch[0].name == NULL)
128 log_error(0, "%s %s %s",
129 "There are no authentication methods compiled into sudo!",
130 "If you want to turn off authentication, use the",
131 "--disable-authentication configure option.");
133 /* Set FLAG_ONEANDONLY if there is only one auth method. */
134 if (auth_switch[1].name == NULL)
135 auth_switch[0].flags |= FLAG_ONEANDONLY;
137 /* Initialize auth methods and unconfigure the method if necessary. */
138 for (auth = auth_switch; auth->name; auth++) {
139 if (auth->init && IS_CONFIGURED(auth)) {
140 if (NEEDS_USER(auth))
141 set_perms(PERM_USER, 0);
143 status = (auth->init)(pw, &prompt, auth);
144 if (status == AUTH_FAILURE)
145 auth->flags &= ~FLAG_CONFIGURED;
146 else if (status == AUTH_FATAL) /* XXX log */
147 exit(1); /* assume error msg already printed */
149 if (NEEDS_USER(auth))
150 set_perms(PERM_ROOT, 0);
155 /* Do any per-method setup and unconfigure the method if needed */
156 for (auth = auth_switch; auth->name; auth++) {
157 if (auth->setup && IS_CONFIGURED(auth)) {
158 if (NEEDS_USER(auth))
159 set_perms(PERM_USER, 0);
161 status = (auth->setup)(pw, &prompt, auth);
162 if (status == AUTH_FAILURE)
163 auth->flags &= ~FLAG_CONFIGURED;
164 else if (status == AUTH_FATAL) /* XXX log */
165 exit(1); /* assume error msg already printed */
167 if (NEEDS_USER(auth))
168 set_perms(PERM_ROOT, 0);
172 /* Get the password unless the auth function will do it for us */
174 #ifdef AUTH_STANDALONE
177 p = (char *) tgetpass(prompt, def_ival(I_PASSWD_TIMEOUT) * 60,
179 if (!p || *p == '\0')
181 #endif /* AUTH_STANDALONE */
183 /* Call authentication functions. */
184 for (auth = auth_switch; p && auth->name; auth++) {
185 if (!IS_CONFIGURED(auth))
188 if (NEEDS_USER(auth))
189 set_perms(PERM_USER, 0);
191 success = auth->status = (auth->verify)(pw, p, auth);
193 if (NEEDS_USER(auth))
194 set_perms(PERM_ROOT, 0);
196 if (auth->status != AUTH_FAILURE)
199 #ifndef AUTH_STANDALONE
201 (void) memset(p, 0, strlen(p));
204 /* Exit loop on nil password, but give it a chance to match first. */
206 if (counter == def_ival(I_PASSWD_TRIES))
216 /* Call cleanup routines. */
217 for (auth = auth_switch; auth->name; auth++) {
218 if (auth->cleanup && IS_CONFIGURED(auth)) {
219 if (NEEDS_USER(auth))
220 set_perms(PERM_USER, 0);
222 status = (auth->cleanup)(pw, auth);
223 if (status == AUTH_FATAL) /* XXX log */
224 exit(1); /* assume error msg already printed */
226 if (NEEDS_USER(auth))
227 set_perms(PERM_ROOT, 0);
233 (void) sigaction(SIGTSTP, &osa, NULL);
236 if (def_flag(I_MAIL_BADPASS) || def_flag(I_MAIL_ALWAYS))
240 log_error(flags, "%d incorrect password attempt%s",
241 def_ival(I_PASSWD_TRIES) - counter,
242 (def_ival(I_PASSWD_TRIES) - counter == 1) ? "" : "s");
255 if (def_flag(I_INSULTS))
256 (void) fprintf(fp, "%s\n", INSULT);
259 (void) fprintf(fp, "%s\n", def_str(I_BADPASS_MESSAGE));
267 (void) fputs("Authentication methods:", stdout);
268 for (auth = auth_switch; auth->name; auth++)
269 (void) printf(" '%s'", auth->name);
270 (void) putchar('\n');