1 /*
2 * pam_ftp module
3 *
4 * Written by Andrew Morgan <morgan@linux.kernel.org> 1996/3/11
5 */
6
7 #define PLEASE_ENTER_PASSWORD "Password required for %s."
8 #define GUEST_LOGIN_PROMPT "Guest login ok, " \
9 "send your complete e-mail address as password."
10
11 /* the following is a password that "can't be correct" */
12 #define BLOCK_PASSWORD "\177BAD PASSWPRD\177"
13
14 #include "config.h"
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <syslog.h>
20 #include <stdarg.h>
21 #include <string.h>
22
23 #include <security/pam_modules.h>
24 #include <security/_pam_macros.h>
25 #include <security/pam_ext.h>
26 #include "pam_inline.h"
27
28 /* argument parsing */
29
30 #define PAM_DEBUG_ARG 01
31 #define PAM_IGNORE_EMAIL 02
32 #define PAM_NO_ANON 04
33
34 static int
35 _pam_parse(pam_handle_t *pamh, int argc, const char **argv, const char **users)
36 {
37 int ctrl=0;
38
39 /* step through arguments */
40 for (ctrl=0; argc-- > 0; ++argv) {
41 const char *str;
42
43 /* generic options */
44
45 if (!strcmp(*argv,"debug"))
46 ctrl |= PAM_DEBUG_ARG;
47 else if (!strcmp(*argv,"ignore"))
48 ctrl |= PAM_IGNORE_EMAIL;
49 else if ((str = pam_str_skip_prefix(*argv, "users=")) != NULL)
50 *users = str;
51 else
52 pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv);
53 }
54
55 return ctrl;
56 }
57
58 /*
59 * check if name is in list or default list. place users name in *_user
60 * return 1 if listed 0 if not.
61 */
62
63 static int lookup(const char *name, const char *list, char **_user)
64 {
65 int anon = 0;
66
67 if (list && *list) {
68 const char *l;
69 char *list_copy, *x;
70 char *sptr = NULL;
71
72 list_copy = strdup(list);
73 x = list_copy;
74 while (list_copy && (l = strtok_r(x, ",", &sptr))) {
75 x = NULL;
76 if (!strcmp(name, l)) {
77 *_user = list_copy;
78 anon = 1;
79 break;
80 }
81 }
82 if (*_user != list_copy) {
83 free(list_copy);
84 }
85 } else {
86 #define MAX_L 2
87 static const char *l[MAX_L] = { "ftp", "anonymous" };
88 int i;
89
90 for (i=0; i<MAX_L; ++i) {
91 if (!strcmp(l[i], name)) {
92 *_user = strdup(l[0]);
93 anon = 1;
94 break;
95 }
96 }
97 }
98
99 return anon;
100 }
101
102 /* --- authentication management functions (only) --- */
103
104 int
105 pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED,
106 int argc, const char **argv)
107 {
108 int retval, anon=0, ctrl;
109 const char *user;
110 char *anon_user = NULL;
111 const char *users = NULL;
112
113 /*
114 * this module checks if the user name is ftp or anonymous. If
115 * this is the case, it can set the PAM_RUSER to the entered email
116 * address and SUCCEEDS, otherwise it FAILS.
117 */
118
119 ctrl = _pam_parse(pamh, argc, argv, &users);
120
121 retval = pam_get_user(pamh, &user, NULL);
122 if (retval != PAM_SUCCESS) {
123 pam_syslog(pamh, LOG_NOTICE, "cannot determine user name: %s",
124 pam_strerror(pamh, retval));
125 return PAM_USER_UNKNOWN;
126 }
127
128 if (!(ctrl & PAM_NO_ANON)) {
129 anon = lookup(user, users, &anon_user);
130 }
131
132 if (anon) {
133 retval = pam_set_item(pamh, PAM_USER, (const void *)anon_user);
134 if (retval != PAM_SUCCESS || anon_user == NULL) {
135 pam_syslog(pamh, LOG_ERR, "user resetting failed");
136 free(anon_user);
137
138 return PAM_USER_UNKNOWN;
139 }
140 free(anon_user);
141 }
142
143 /*
144 * OK. we require an email address for user or the user's password.
145 * - build conversation and get their input.
146 */
147
148 {
149 char *resp = NULL;
150 const char *token;
151
152 if (!anon)
153 retval = pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp,
154 PLEASE_ENTER_PASSWORD, user);
155 else
156 retval = pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp,
157 GUEST_LOGIN_PROMPT);
158
159 if (retval != PAM_SUCCESS) {
160 pam_overwrite_string (resp);
161 _pam_drop (resp);
162 return ((retval == PAM_CONV_AGAIN)
163 ? PAM_INCOMPLETE:PAM_AUTHINFO_UNAVAIL);
164 }
165
166 if (anon) {
167 /* XXX: Some effort should be made to verify this email address! */
168
169 if (!(ctrl & PAM_IGNORE_EMAIL)) {
170 char *sptr = NULL;
171 token = strtok_r(resp, "@", &sptr);
172 retval = pam_set_item(pamh, PAM_RUSER, token);
173
174 if ((token) && (retval == PAM_SUCCESS)) {
175 token = strtok_r(NULL, "@", &sptr);
176 retval = pam_set_item(pamh, PAM_RHOST, token);
177 }
178 }
179
180 /* we are happy to grant anonymous access to the user */
181 retval = PAM_SUCCESS;
182
183 } else {
184 /*
185 * we have a password so set AUTHTOK
186 */
187
188 pam_set_item(pamh, PAM_AUTHTOK, resp);
189
190 /*
191 * this module failed, but the next one might succeed with
192 * this password.
193 */
194
195 retval = PAM_AUTH_ERR;
196 }
197
198 /* clean up */
199 pam_overwrite_string(resp);
200 _pam_drop(resp);
201
202 /* success or failure */
203
204 return retval;
205 }
206 }
207
208 int
209 pam_sm_setcred (pam_handle_t *pamh UNUSED, int flags UNUSED,
210 int argc UNUSED, const char **argv UNUSED)
211 {
212 return PAM_IGNORE;
213 }
214
215 /* end of module definition */