Initial import from FreeBSD RELENG_4:
[dragonfly.git] / contrib / libpam / modules / pam_ftp / pam_ftp.c
1 /* pam_ftp module */
2
3 /*
4  * $Id: pam_ftp.c,v 1.2 2000/11/19 23:54:03 agmorgan Exp $
5  * $FreeBSD: src/contrib/libpam/modules/pam_ftp/pam_ftp.c,v 1.3.2.2 2001/06/11 15:28:17 markm Exp $
6  *
7  * Written by Andrew Morgan <morgan@linux.kernel.org> 1996/3/11
8  *
9  */
10
11 #define PLEASE_ENTER_PASSWORD "Password required for %s."
12 #define GUEST_LOGIN_PROMPT "Guest login ok, " \
13 "send your complete e-mail address as password."
14
15 /* the following is a password that "can't be correct" */
16 #define BLOCK_PASSWORD "\177BAD PASSWPRD\177"
17
18 #include <security/_pam_aconf.h>
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <syslog.h>
24 #include <stdarg.h>
25 #include <string.h>
26
27 /*
28  * here, we make a definition for the externally accessible function
29  * in this file (this definition is required for static a module
30  * but strongly encouraged generally) it is used to instruct the
31  * modules include file to define the function prototypes.
32  */
33
34 #define PAM_SM_AUTH
35
36 #include <security/pam_modules.h>
37 #include <security/_pam_macros.h>
38
39 /* some syslogging */
40
41 static void _pam_log(int err, const char *format, ...)
42 {
43     va_list args;
44
45     va_start(args, format);
46     openlog("PAM-ftp", LOG_CONS|LOG_PID, LOG_AUTH);
47     vsyslog(err, format, args);
48     va_end(args);
49     closelog();
50 }
51
52 static int converse(pam_handle_t *pamh, int nargs
53                     , struct pam_message **message
54                     , struct pam_response **response)
55 {
56     int retval;
57     struct pam_conv *conv;
58
59     D(("begin to converse\n"));
60
61     retval = pam_get_item( pamh, PAM_CONV, (const void **) &conv ) ; 
62     if ( retval == PAM_SUCCESS ) {
63
64         retval = conv->conv(nargs, ( const struct pam_message ** ) message
65                             , response, conv->appdata_ptr);
66
67         D(("returned from application's conversation function\n"));
68
69         if ((retval != PAM_SUCCESS) && (retval != PAM_CONV_AGAIN)) {
70             _pam_log(LOG_DEBUG, "conversation failure [%s]"
71                      , pam_strerror(pamh, retval));
72         }
73
74     } else {
75         _pam_log(LOG_ERR, "couldn't obtain coversation function [%s]"
76                  , pam_strerror(pamh, retval));
77     }
78
79     D(("ready to return from module conversation\n"));
80
81     return retval;                  /* propagate error status */
82 }
83
84 /* argument parsing */
85
86 #define PAM_DEBUG_ARG       01
87 #define PAM_IGNORE_EMAIL    02
88 #define PAM_NO_ANON         04
89
90 static int _pam_parse(int argc, const char **argv, char **users)
91 {
92     int ctrl=0;
93
94     /* step through arguments */
95     for (ctrl=0; argc-- > 0; ++argv) {
96
97         /* generic options */
98
99         if (!strcmp(*argv,"debug"))
100             ctrl |= PAM_DEBUG_ARG;
101         else if (!strncmp(*argv,"users=",6)) {
102             *users = x_strdup(6+*argv);
103             if (*users == NULL) {
104                 ctrl |= PAM_NO_ANON;
105                 _pam_log(LOG_CRIT, "failed to duplicate user list - anon off");
106             }
107         } else if (!strcmp(*argv,"ignore")) {
108             ctrl |= PAM_IGNORE_EMAIL;
109         } else {
110             _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv);
111         }
112     }
113
114     return ctrl;
115 }
116
117 /*
118  * check if name is in list or default list. place users name in *_user
119  * return 1 if listed 0 if not.
120  */
121
122 static int lookup(const char *name, char *list, const char **_user)
123 {
124     int anon = 0;
125
126     *_user = name;                 /* this is the default */
127     if (list) {
128         const char *l;
129         char *x;
130
131         x = list;
132         while ((l = strtok(x, ","))) {
133             x = NULL;
134             if (!strcmp(name, l)) {
135                 *_user = list;
136                 anon = 1;
137             }
138         }
139     } else {
140 #define MAX_L 2
141         static const char *l[MAX_L] = { "ftp", "anonymous" };
142         int i;
143
144         for (i=0; i<MAX_L; ++i) {
145             if (!strcmp(l[i], name)) {
146                 *_user = l[0];
147                 anon = 1;
148                 break;
149             }
150         }
151     }
152
153     return anon;
154 }
155
156 /* --- authentication management functions (only) --- */
157
158 PAM_EXTERN
159 int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc
160                         ,const char **argv)
161 {
162     int retval, anon=0, ctrl;
163     const char *user;
164     char *users=NULL;
165
166     /*
167      * this module checks if the user name is ftp or annonymous. If
168      * this is the case, it can set the PAM_RUSER to the entered email
169      * address and SUCCEEDS, otherwise it FAILS.
170      */
171
172     ctrl = _pam_parse(argc, argv, &users);
173
174     retval = pam_get_user(pamh, &user, NULL);
175     if (retval != PAM_SUCCESS || user == NULL) {
176         _pam_log(LOG_ERR, "no user specified");
177         return PAM_USER_UNKNOWN;
178     }
179
180     if (!(ctrl & PAM_NO_ANON)) {
181         anon = lookup(user, users, &user);
182     }
183
184     if (anon) {
185         retval = pam_set_item(pamh, PAM_USER, (const void *)user);
186         if (retval != PAM_SUCCESS || user == NULL) {
187             _pam_log(LOG_ERR, "user resetting failed");
188             return PAM_USER_UNKNOWN;
189         }
190     }
191
192     /*
193      * OK. we require an email address for user or the user's password.
194      * - build conversation and get their input.
195      */
196
197     {
198         struct pam_message msg[1], *mesg[1];
199         struct pam_response *resp=NULL;
200         const char *token;
201         char *prompt=NULL;
202         int i=0;
203
204         if (!anon) {
205             prompt = malloc(strlen(PLEASE_ENTER_PASSWORD) + strlen(user));
206             if (prompt == NULL) {
207                 D(("out of memory!?"));
208                 return PAM_BUF_ERR;
209             } else {
210                 sprintf(prompt, PLEASE_ENTER_PASSWORD, user);
211                 msg[i].msg = prompt;
212             }
213         } else {
214             msg[i].msg = GUEST_LOGIN_PROMPT;
215         }
216
217         msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
218         mesg[i] = &msg[i];
219
220         retval = converse(pamh, ++i, mesg, &resp);
221         if (prompt) {
222             _pam_overwrite(prompt);
223             _pam_drop(prompt);
224         }
225
226         if (retval != PAM_SUCCESS) {
227             if (resp != NULL)
228                 _pam_drop_reply(resp,i);
229             return ((retval == PAM_CONV_AGAIN)
230                     ? PAM_INCOMPLETE:PAM_AUTHINFO_UNAVAIL);
231         }
232
233         if (anon) {
234             /* XXX: Some effort should be made to verify this email address! */
235
236             if (!(ctrl & PAM_IGNORE_EMAIL)) {
237                 token = strtok(resp->resp, "@");
238                 retval = pam_set_item(pamh, PAM_RUSER, token);
239
240                 if ((token) && (retval == PAM_SUCCESS)) {
241                     token = strtok(NULL, "@");
242                     retval = pam_set_item(pamh, PAM_RHOST, token);
243                 }
244             }
245
246             /* we are happy to grant annonymous access to the user */
247             retval = PAM_SUCCESS;
248
249         } else {
250             /*
251              * we have a password so set AUTHTOK
252              */
253
254             (void) pam_set_item(pamh, PAM_AUTHTOK, resp->resp);
255
256             /*
257              * this module failed, but the next one might succeed with
258              * this password.
259              */
260
261             retval = PAM_AUTH_ERR;
262         }
263
264         if (resp) {                                      /* clean up */
265             _pam_drop_reply(resp, i);
266         }
267
268         /* success or failure */
269
270         return retval;
271     }
272 }
273
274 PAM_EXTERN
275 int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc
276                    ,const char **argv)
277 {
278      return PAM_IGNORE;
279 }
280
281
282 #ifdef PAM_STATIC
283
284 /* static module data */
285
286 struct pam_module _pam_ftp_modstruct = {
287      "pam_ftp",
288      pam_sm_authenticate,
289      pam_sm_setcred,
290      NULL,
291      NULL,
292      NULL,
293      NULL,
294 };
295
296 #endif
297
298 /* end of module definition */