Imported Upstream version 1.6.6
[debian/sudo] / auth / sudo_auth.c
1 /*
2  * Copyright (c) 1999-2001 Todd C. Miller <Todd.Miller@courtesan.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
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.
15  *
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.
18  *
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.
22  *
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.
33  */
34
35 #include "config.h"
36
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <stdio.h>
40 #ifdef STDC_HEADERS
41 # include <stdlib.h>
42 # include <stddef.h>
43 #else
44 # ifdef HAVE_STDLIB_H
45 #  include <stdlib.h>
46 # endif
47 #endif /* STDC_HEADERS */
48 #ifdef HAVE_STRING_H
49 # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
50 #  include <memory.h>
51 # endif
52 # include <string.h>
53 #else
54 # ifdef HAVE_STRINGS_H
55 #  include <strings.h>
56 # endif
57 #endif /* HAVE_STRING_H */
58 #ifdef HAVE_UNISTD_H
59 # include <unistd.h>
60 #endif /* HAVE_UNISTD_H */
61 #include <pwd.h>
62 #include <time.h>
63 #include <signal.h>
64
65 #include "sudo.h"
66 #include "sudo_auth.h"
67 #include "insults.h"
68
69 #ifndef lint
70 static const char rcsid[] = "$Sudo: sudo_auth.c,v 1.25 2001/12/14 19:52:54 millert Exp $";
71 #endif /* lint */
72
73 sudo_auth auth_switch[] = {
74 #ifdef AUTH_STANDALONE
75     AUTH_STANDALONE
76 #else
77 #  ifndef WITHOUT_PASSWD
78     AUTH_ENTRY(0, "passwd", passwd_init, NULL, passwd_verify, NULL)
79 #  endif
80 #  if defined(HAVE_GETPRPWNAM) && !defined(WITHOUT_PASSWD)
81     AUTH_ENTRY(0, "secureware", secureware_init, NULL, secureware_verify, NULL)
82 #  endif
83 #  ifdef HAVE_AFS
84     AUTH_ENTRY(0, "afs", NULL, NULL, afs_verify, NULL)
85 #  endif
86 #  ifdef HAVE_DCE
87     AUTH_ENTRY(0, "dce", NULL, NULL, dce_verify, NULL)
88 #  endif
89 #  ifdef HAVE_KERB4
90     AUTH_ENTRY(0, "kerb4", kerb4_init, NULL, kerb4_verify, NULL)
91 #  endif
92 #  ifdef HAVE_KERB5
93     AUTH_ENTRY(0, "kerb5", kerb5_init, NULL, kerb5_verify, kerb5_cleanup)
94 #  endif
95 #  ifdef HAVE_SKEY
96     AUTH_ENTRY(0, "S/Key", NULL, rfc1938_setup, rfc1938_verify, NULL)
97 #  endif
98 #  ifdef HAVE_OPIE
99     AUTH_ENTRY(0, "OPIE", NULL, rfc1938_setup, rfc1938_verify, NULL)
100 #  endif
101 #endif /* AUTH_STANDALONE */
102     AUTH_ENTRY(0, NULL, NULL, NULL, NULL, NULL)
103 };
104
105 int nil_pw;             /* I hate resorting to globals like this... */
106
107 void
108 verify_user(pw, prompt)
109     struct passwd *pw;
110     char *prompt;
111 {
112     int counter = def_ival(I_PASSWD_TRIES) + 1;
113     int success = AUTH_FAILURE;
114     int status;
115     int flags;
116     char *p;
117     sudo_auth *auth;
118     sigaction_t sa, osa;
119
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);
125
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.");
132
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;
136
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);
142
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 */
148
149             if (NEEDS_USER(auth))
150                 set_perms(PERM_ROOT, 0);
151         }
152     }
153
154     while (--counter) {
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);
160
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 */
166
167                 if (NEEDS_USER(auth))
168                     set_perms(PERM_ROOT, 0);
169             }
170         }
171
172         /* Get the password unless the auth function will do it for us */
173         nil_pw = 0;
174 #ifdef AUTH_STANDALONE
175         p = prompt;
176 #else
177         p = (char *) tgetpass(prompt, def_ival(I_PASSWD_TIMEOUT) * 60,
178             tgetpass_flags);
179         if (!p || *p == '\0')
180             nil_pw = 1;
181 #endif /* AUTH_STANDALONE */
182
183         /* Call authentication functions. */
184         for (auth = auth_switch; p && auth->name; auth++) {
185             if (!IS_CONFIGURED(auth))
186                 continue;
187
188             if (NEEDS_USER(auth))
189                 set_perms(PERM_USER, 0);
190
191             success = auth->status = (auth->verify)(pw, p, auth);
192
193             if (NEEDS_USER(auth))
194                 set_perms(PERM_ROOT, 0);
195
196             if (auth->status != AUTH_FAILURE)
197                 goto cleanup;
198         }
199 #ifndef AUTH_STANDALONE
200         if (p)
201             (void) memset(p, 0, strlen(p));
202 #endif
203
204         /* Exit loop on nil password, but give it a chance to match first. */
205         if (nil_pw) {
206             if (counter == def_ival(I_PASSWD_TRIES))
207                 exit(1);
208             else
209                 break;
210         }
211
212         pass_warn(stderr);
213     }
214
215 cleanup:
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);
221
222             status = (auth->cleanup)(pw, auth);
223             if (status == AUTH_FATAL)   /* XXX log */
224                 exit(1);                /* assume error msg already printed */
225
226             if (NEEDS_USER(auth))
227                 set_perms(PERM_ROOT, 0);
228         }
229     }
230
231     switch (success) {
232         case AUTH_SUCCESS:
233             (void) sigaction(SIGTSTP, &osa, NULL);
234             return;
235         case AUTH_FAILURE:
236             if (def_flag(I_MAIL_BADPASS) || def_flag(I_MAIL_ALWAYS))
237                 flags = 0;
238             else
239                 flags = NO_MAIL;
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");
243         case AUTH_FATAL:
244             exit(1);
245     }
246     /* NOTREACHED */
247 }
248
249 void
250 pass_warn(fp)
251     FILE *fp;
252 {
253
254 #ifdef INSULT
255     if (def_flag(I_INSULTS))
256         (void) fprintf(fp, "%s\n", INSULT);
257     else
258 #endif
259         (void) fprintf(fp, "%s\n", def_str(I_BADPASS_MESSAGE));
260 }
261
262 void
263 dump_auth_methods()
264 {
265     sudo_auth *auth;
266
267     (void) fputs("Authentication methods:", stdout);
268     for (auth = auth_switch; auth->name; auth++)
269         (void) printf(" '%s'", auth->name);
270     (void) putchar('\n');
271 }