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 $
7 * Written by Andrew Morgan <morgan@linux.kernel.org> 1996/3/11
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."
15 /* the following is a password that "can't be correct" */
16 #define BLOCK_PASSWORD "\177BAD PASSWPRD\177"
18 #include <security/_pam_aconf.h>
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.
36 #include <security/pam_modules.h>
37 #include <security/_pam_macros.h>
41 static void _pam_log(int err, const char *format, ...)
45 va_start(args, format);
46 openlog("PAM-ftp", LOG_CONS|LOG_PID, LOG_AUTH);
47 vsyslog(err, format, args);
52 static int converse(pam_handle_t *pamh, int nargs
53 , struct pam_message **message
54 , struct pam_response **response)
57 struct pam_conv *conv;
59 D(("begin to converse\n"));
61 retval = pam_get_item( pamh, PAM_CONV, (const void **) &conv ) ;
62 if ( retval == PAM_SUCCESS ) {
64 retval = conv->conv(nargs, ( const struct pam_message ** ) message
65 , response, conv->appdata_ptr);
67 D(("returned from application's conversation function\n"));
69 if ((retval != PAM_SUCCESS) && (retval != PAM_CONV_AGAIN)) {
70 _pam_log(LOG_DEBUG, "conversation failure [%s]"
71 , pam_strerror(pamh, retval));
75 _pam_log(LOG_ERR, "couldn't obtain coversation function [%s]"
76 , pam_strerror(pamh, retval));
79 D(("ready to return from module conversation\n"));
81 return retval; /* propagate error status */
84 /* argument parsing */
86 #define PAM_DEBUG_ARG 01
87 #define PAM_IGNORE_EMAIL 02
88 #define PAM_NO_ANON 04
90 static int _pam_parse(int argc, const char **argv, char **users)
94 /* step through arguments */
95 for (ctrl=0; argc-- > 0; ++argv) {
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) {
105 _pam_log(LOG_CRIT, "failed to duplicate user list - anon off");
107 } else if (!strcmp(*argv,"ignore")) {
108 ctrl |= PAM_IGNORE_EMAIL;
110 _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv);
118 * check if name is in list or default list. place users name in *_user
119 * return 1 if listed 0 if not.
122 static int lookup(const char *name, char *list, const char **_user)
126 *_user = name; /* this is the default */
132 while ((l = strtok(x, ","))) {
134 if (!strcmp(name, l)) {
141 static const char *l[MAX_L] = { "ftp", "anonymous" };
144 for (i=0; i<MAX_L; ++i) {
145 if (!strcmp(l[i], name)) {
156 /* --- authentication management functions (only) --- */
159 int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc
162 int retval, anon=0, ctrl;
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.
172 ctrl = _pam_parse(argc, argv, &users);
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;
180 if (!(ctrl & PAM_NO_ANON)) {
181 anon = lookup(user, users, &user);
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;
193 * OK. we require an email address for user or the user's password.
194 * - build conversation and get their input.
198 struct pam_message msg[1], *mesg[1];
199 struct pam_response *resp=NULL;
205 prompt = malloc(strlen(PLEASE_ENTER_PASSWORD) + strlen(user));
206 if (prompt == NULL) {
207 D(("out of memory!?"));
210 sprintf(prompt, PLEASE_ENTER_PASSWORD, user);
214 msg[i].msg = GUEST_LOGIN_PROMPT;
217 msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
220 retval = converse(pamh, ++i, mesg, &resp);
222 _pam_overwrite(prompt);
226 if (retval != PAM_SUCCESS) {
228 _pam_drop_reply(resp,i);
229 return ((retval == PAM_CONV_AGAIN)
230 ? PAM_INCOMPLETE:PAM_AUTHINFO_UNAVAIL);
234 /* XXX: Some effort should be made to verify this email address! */
236 if (!(ctrl & PAM_IGNORE_EMAIL)) {
237 token = strtok(resp->resp, "@");
238 retval = pam_set_item(pamh, PAM_RUSER, token);
240 if ((token) && (retval == PAM_SUCCESS)) {
241 token = strtok(NULL, "@");
242 retval = pam_set_item(pamh, PAM_RHOST, token);
246 /* we are happy to grant annonymous access to the user */
247 retval = PAM_SUCCESS;
251 * we have a password so set AUTHTOK
254 (void) pam_set_item(pamh, PAM_AUTHTOK, resp->resp);
257 * this module failed, but the next one might succeed with
261 retval = PAM_AUTH_ERR;
264 if (resp) { /* clean up */
265 _pam_drop_reply(resp, i);
268 /* success or failure */
275 int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc
284 /* static module data */
286 struct pam_module _pam_ftp_modstruct = {
298 /* end of module definition */