Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / contrib / libpam / modules / pam_ftp / pam_ftp.c
CommitLineData
984263bc
MD
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 $
1de703da 6 * $DragonFly: src/contrib/libpam/modules/pam_ftp/Attic/pam_ftp.c,v 1.2 2003/06/17 04:24:03 dillon Exp $
984263bc
MD
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
42static 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
53static 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
91static 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
123static 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
159PAM_EXTERN
160int 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
275PAM_EXTERN
276int 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
287struct 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 */