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