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 $
8 * Written by Andrew Morgan <morgan@linux.kernel.org> 1996/3/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."
16 /* the following is a password that "can't be correct" */
17 #define BLOCK_PASSWORD "\177BAD PASSWPRD\177"
19 #include <security/_pam_aconf.h>
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.
37 #include <security/pam_modules.h>
38 #include <security/_pam_macros.h>
42 static void _pam_log(int err, const char *format, ...)
46 va_start(args, format);
47 openlog("PAM-ftp", LOG_CONS|LOG_PID, LOG_AUTH);
48 vsyslog(err, format, args);
53 static int converse(pam_handle_t *pamh, int nargs
54 , struct pam_message **message
55 , struct pam_response **response)
58 struct pam_conv *conv;
60 D(("begin to converse\n"));
62 retval = pam_get_item( pamh, PAM_CONV, (const void **) &conv ) ;
63 if ( retval == PAM_SUCCESS ) {
65 retval = conv->conv(nargs, ( const struct pam_message ** ) message
66 , response, conv->appdata_ptr);
68 D(("returned from application's conversation function\n"));
70 if ((retval != PAM_SUCCESS) && (retval != PAM_CONV_AGAIN)) {
71 _pam_log(LOG_DEBUG, "conversation failure [%s]"
72 , pam_strerror(pamh, retval));
76 _pam_log(LOG_ERR, "couldn't obtain coversation function [%s]"
77 , pam_strerror(pamh, retval));
80 D(("ready to return from module conversation\n"));
82 return retval; /* propagate error status */
85 /* argument parsing */
87 #define PAM_DEBUG_ARG 01
88 #define PAM_IGNORE_EMAIL 02
89 #define PAM_NO_ANON 04
91 static int _pam_parse(int argc, const char **argv, char **users)
95 /* step through arguments */
96 for (ctrl=0; argc-- > 0; ++argv) {
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) {
106 _pam_log(LOG_CRIT, "failed to duplicate user list - anon off");
108 } else if (!strcmp(*argv,"ignore")) {
109 ctrl |= PAM_IGNORE_EMAIL;
111 _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv);
119 * check if name is in list or default list. place users name in *_user
120 * return 1 if listed 0 if not.
123 static int lookup(const char *name, char *list, const char **_user)
127 *_user = name; /* this is the default */
133 while ((l = strtok(x, ","))) {
135 if (!strcmp(name, l)) {
142 static const char *l[MAX_L] = { "ftp", "anonymous" };
145 for (i=0; i<MAX_L; ++i) {
146 if (!strcmp(l[i], name)) {
157 /* --- authentication management functions (only) --- */
160 int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc
163 int retval, anon=0, ctrl;
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.
173 ctrl = _pam_parse(argc, argv, &users);
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;
181 if (!(ctrl & PAM_NO_ANON)) {
182 anon = lookup(user, users, &user);
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;
194 * OK. we require an email address for user or the user's password.
195 * - build conversation and get their input.
199 struct pam_message msg[1], *mesg[1];
200 struct pam_response *resp=NULL;
206 prompt = malloc(strlen(PLEASE_ENTER_PASSWORD) + strlen(user));
207 if (prompt == NULL) {
208 D(("out of memory!?"));
211 sprintf(prompt, PLEASE_ENTER_PASSWORD, user);
215 msg[i].msg = GUEST_LOGIN_PROMPT;
218 msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
221 retval = converse(pamh, ++i, mesg, &resp);
223 _pam_overwrite(prompt);
227 if (retval != PAM_SUCCESS) {
229 _pam_drop_reply(resp,i);
230 return ((retval == PAM_CONV_AGAIN)
231 ? PAM_INCOMPLETE:PAM_AUTHINFO_UNAVAIL);
235 /* XXX: Some effort should be made to verify this email address! */
237 if (!(ctrl & PAM_IGNORE_EMAIL)) {
238 token = strtok(resp->resp, "@");
239 retval = pam_set_item(pamh, PAM_RUSER, token);
241 if ((token) && (retval == PAM_SUCCESS)) {
242 token = strtok(NULL, "@");
243 retval = pam_set_item(pamh, PAM_RHOST, token);
247 /* we are happy to grant annonymous access to the user */
248 retval = PAM_SUCCESS;
252 * we have a password so set AUTHTOK
255 (void) pam_set_item(pamh, PAM_AUTHTOK, resp->resp);
258 * this module failed, but the next one might succeed with
262 retval = PAM_AUTH_ERR;
265 if (resp) { /* clean up */
266 _pam_drop_reply(resp, i);
269 /* success or failure */
276 int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc
285 /* static module data */
287 struct pam_module _pam_ftp_modstruct = {
299 /* end of module definition */