Imported Upstream version 1.6.6
[debian/sudo] / auth / rfc1938.c
1 /*
2  * Copyright (c) 1994-1996, 1998-1999, 2001
3  *      Todd C. Miller <Todd.Miller@courtesan.com>.  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 # include <string.h>
50 #else
51 # ifdef HAVE_STRINGS_H
52 #  include <strings.h>
53 # endif
54 #endif /* HAVE_STRING_H */
55 #ifdef HAVE_UNISTD_H
56 # include <unistd.h>
57 #endif /* HAVE_UNISTD_H */
58 #include <pwd.h>
59
60 #if defined(HAVE_SKEY)
61 #include <skey.h>
62 #define RFC1938                 skey
63 #define rfc1938challenge        skeychallenge
64 #define rfc1938verify           skeyverify
65 #elif defined(HAVE_OPIE)
66 #include <opie.h>
67 #define RFC1938                 opie
68 #define rfc1938challenge        opiechallenge
69 #define rfc1938verify           opieverify
70 #endif
71
72 #include "sudo.h"
73 #include "sudo_auth.h"
74
75 #ifndef lint
76 static const char rcsid[] = "$Sudo: rfc1938.c,v 1.9 2001/12/14 19:52:53 millert Exp $";
77 #endif /* lint */
78
79 int
80 rfc1938_setup(pw, promptp, auth)
81     struct passwd *pw;
82     char **promptp;
83     sudo_auth *auth;
84 {
85     char challenge[256];
86     static char *orig_prompt = NULL, *new_prompt = NULL;
87     static int op_len, np_size;
88     static struct RFC1938 rfc1938;
89
90     /* Stash a pointer to the rfc1938 struct if we have not initialized */
91     if (!auth->data)
92         auth->data = &rfc1938;
93
94     /* Save the original prompt */
95     if (orig_prompt == NULL) {
96         orig_prompt = *promptp;
97         op_len = strlen(orig_prompt);
98
99         /* Ignore trailing colon (we will add our own) */
100         if (orig_prompt[op_len - 1] == ':')
101             op_len--;
102         else if (op_len >= 2 && orig_prompt[op_len - 1] == ' '
103             && orig_prompt[op_len - 2] == ':')
104             op_len -= 2;
105     }
106
107 #ifdef HAVE_SKEY
108     /* Close old stream */
109     if (rfc1938.keyfile)
110         (void) fclose(rfc1938.keyfile);
111 #endif
112
113     /*
114      * Look up the user and get the rfc1938 challenge.
115      * If the user is not in the OTP db, only post a fatal error if
116      * we are running alone (since they may just use a normal passwd).
117      */
118     if (rfc1938challenge(&rfc1938, pw->pw_name, challenge) != 0) {
119         if (IS_ONEANDONLY(auth)) {
120             (void) fprintf(stderr,
121                            "%s: You do not exist in the %s database.\n",
122                            Argv[0], auth->name);
123             return(AUTH_FATAL);
124         } else {
125             return(AUTH_FAILURE);
126         }
127     }
128
129     /* Get space for new prompt with embedded challenge */
130     if (np_size < op_len + strlen(challenge) + 7) {
131         np_size = op_len + strlen(challenge) + 7;
132         new_prompt = (char *) erealloc(new_prompt, np_size);
133     }
134
135     if (def_flag(I_LONG_OTP_PROMPT))
136         (void) sprintf(new_prompt, "%s\n%s", challenge, orig_prompt);
137     else
138         (void) sprintf(new_prompt, "%.*s [ %s ]:", op_len, orig_prompt,
139             challenge);
140
141     *promptp = new_prompt;
142     return(AUTH_SUCCESS);
143 }
144
145 int
146 rfc1938_verify(pw, pass, auth)
147     struct passwd *pw;
148     char *pass;
149     sudo_auth *auth;
150 {
151
152     if (rfc1938verify((struct RFC1938 *) auth->data, pass) == 0)
153         return(AUTH_SUCCESS);
154     else
155         return(AUTH_FAILURE);
156 }