2 * Copyright (c) 1990,1993 Regents of The University of Michigan.
3 * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu)
4 * All Rights Reserved. See COPYRIGHT.
18 #include <security/pam_appl.h>
20 #include <atalk/afp.h>
21 #include <atalk/uam.h>
25 /* Static variables used to communicate between the conversation function
26 * and the server_login function
28 static pam_handle_t *pamh = NULL;
29 static char *hostname;
30 static char *PAM_username;
31 static char *PAM_password;
33 /* PAM conversation function
34 * Here we assume (for now, at least) that echo on means login name, and
35 * echo off means password.
37 static int PAM_conv (int num_msg,
38 const struct pam_message **msg,
39 struct pam_response **resp,
42 struct pam_response *reply;
45 #define COPY_STRING(s) (s) ? strdup(s) : NULL
50 reply = (struct pam_response *)
51 calloc(num_msg, sizeof(struct pam_response));
56 for (count = 0; count < num_msg; count++) {
59 switch (msg[count]->msg_style) {
60 case PAM_PROMPT_ECHO_ON:
61 if (!(string = COPY_STRING(PAM_username)))
64 case PAM_PROMPT_ECHO_OFF:
65 if (!(string = COPY_STRING(PAM_password)))
69 #ifdef PAM_BINARY_PROMPT
70 case PAM_BINARY_PROMPT:
80 reply[count].resp_retcode = 0;
81 reply[count].resp = string;
90 for (count = 0; count < num_msg; count++) {
91 if (!reply[count].resp)
93 switch (msg[count]->msg_style) {
94 case PAM_PROMPT_ECHO_OFF:
95 case PAM_PROMPT_ECHO_ON:
96 free(reply[count].resp);
104 static struct pam_conv PAM_conversation = {
111 static int pam_login(void *obj, struct passwd **uam_pwd,
112 char *ibuf, int ibuflen,
113 char *rbuf, int *rbuflen)
117 int err, len, ulen, PAM_error;
121 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME,
122 (void *) &username, &ulen) < 0)
125 if (uam_afpserver_option(obj, UAM_OPTION_HOSTNAME,
126 (void *) &hostname, NULL) < 0)
129 len = (unsigned char) *ibuf++;
131 return( AFPERR_PARAM );
134 memcpy(username, ibuf, len );
136 username[ len ] = '\0';
137 if ((unsigned long) ibuf & 1) /* pad character */
139 ibuf[ PASSWDLEN ] = '\0';
141 if (( pwd = uam_getname(username, ulen)) == NULL ) {
145 syslog(LOG_INFO, "cleartext login: %s", username);
146 PAM_username = username;
147 PAM_password = ibuf; /* Set these things up for the conv function */
149 err = AFPERR_NOTAUTH;
150 PAM_error = pam_start("netatalk", username, &PAM_conversation,
152 if (PAM_error != PAM_SUCCESS)
155 pam_set_item(pamh, PAM_TTY, "afpd");
156 pam_set_item(pamh, PAM_RHOST, hostname);
157 /* use PAM_DISALLOW_NULL_AUTHTOK if passwdminlen > 0 */
158 PAM_error = pam_authenticate(pamh,0);
159 if (PAM_error != PAM_SUCCESS) {
160 if (PAM_error == PAM_MAXTRIES)
161 err = AFPERR_PWDEXPR;
165 PAM_error = pam_acct_mgmt(pamh, 0);
166 if (PAM_error != PAM_SUCCESS) {
167 if (PAM_error == PAM_ACCT_EXPIRED)
168 err = AFPERR_PWDEXPR;
169 #ifdef PAM_AUTHTOKEN_REQD
170 else if (PAM_error == PAM_AUTHTOKEN_REQD)
171 err = AFPERR_PWDCHNG;
176 #ifndef PAM_CRED_ESTABLISH
177 #define PAM_CRED_ESTABLISH PAM_ESTABLISH_CRED
179 PAM_error = pam_setcred(pamh, PAM_CRED_ESTABLISH);
180 if (PAM_error != PAM_SUCCESS)
183 PAM_error = pam_open_session(pamh, 0);
184 if (PAM_error != PAM_SUCCESS)
191 pam_end(pamh, PAM_error);
197 static void pam_logout() {
198 pam_close_session(pamh, 0);
204 static int pam_changepw(void *obj, char *username,
205 struct passwd *pwd, char *ibuf, int ibuflen,
206 char *rbuf, int *rbuflen)
208 char pw[PASSWDLEN + 1];
214 memcpy(pw, ibuf, PASSWDLEN);
215 memset(ibuf, 0, PASSWDLEN);
216 pw[PASSWDLEN] = '\0';
218 /* let's do a quick check for the same password */
219 if (memcmp(pw, ibuf + PASSWDLEN, PASSWDLEN) == 0)
220 return AFPERR_PWDSAME;
222 /* Set these things up for the conv function */
223 PAM_username = username;
226 PAM_error = pam_start("netatalk", username, &PAM_conversation,
228 if (PAM_error != PAM_SUCCESS)
230 pam_set_item(lpamh, PAM_TTY, "afpd");
231 pam_set_item(lpamh, PAM_RHOST, hostname);
233 /* we might need to do this as root */
236 PAM_error = pam_authenticate(lpamh,0);
237 if (PAM_error != PAM_SUCCESS) {
239 pam_end(lpamh, PAM_error);
240 return AFPERR_NOTAUTH;
246 ibuf[PASSWDLEN] = '\0';
248 /* this really does need to be done as root */
249 PAM_error = pam_chauthtok(lpamh, 0);
250 seteuid(uid); /* un-root ourselves. */
251 memset(pw, 0, PASSWDLEN);
252 memset(ibuf, 0, PASSWDLEN);
253 if (PAM_error != PAM_SUCCESS) {
254 pam_end(lpamh, PAM_error);
255 return AFPERR_ACCESS;
263 /* Printer ClearTxtUAM login */
264 int pam_printer(start, stop, username, out)
265 char *start, *stop, *username;
270 char password[PASSWDLEN + 1] = "\0";
271 static const char *loginok = "0\r";
273 data = (char *)malloc(stop - start + 1);
274 strncpy(data, start, stop - start + 1);
276 /* We are looking for the following format in data:
277 * (username) (password)
279 * Let's hope username doesn't contain ") ("!
282 /* Parse input for username in () */
283 if ((p = strchr(data, '(' )) == NULL) {
284 syslog(LOG_INFO,"Bad Login ClearTxtUAM: username not found in string");
289 if ((q = strstr(data, ") (" )) == NULL) {
290 syslog(LOG_INFO,"Bad Login ClearTxtUAM: username not found in string");
294 strncpy(username, p, q - p);
296 /* Parse input for password in next () */
298 if ((q = strrchr(data, ')' )) == NULL) {
299 syslog(LOG_INFO,"Bad Login ClearTxtUAM: password not found in string");
303 strncpy(password, p, q - p);
305 /* Done copying username and password, clean up */
308 PAM_username = username;
309 PAM_password = password;
311 PAM_error = pam_start("netatalk", username, &PAM_conversation,
313 if (PAM_error != PAM_SUCCESS) {
314 syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s",
315 username, pam_strerror(pamh, PAM_error));
316 pam_end(pamh, PAM_error);
321 pam_set_item(pamh, PAM_TTY, "papd");
322 pam_set_item(pamh, PAM_RHOST, hostname);
323 PAM_error = pam_authenticate(pamh,0);
324 if (PAM_error != PAM_SUCCESS) {
325 syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s",
326 username, pam_strerror(pamh, PAM_error));
327 pam_end(pamh, PAM_error);
332 PAM_error = pam_acct_mgmt(pamh, 0);
333 if (PAM_error != PAM_SUCCESS) {
334 syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s",
335 username, pam_strerror(pamh, PAM_error));
336 pam_end(pamh, PAM_error);
341 PAM_error = pam_open_session(pamh, 0);
342 if (PAM_error != PAM_SUCCESS) {
343 syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s",
344 username, pam_strerror(pamh, PAM_error));
345 pam_end(pamh, PAM_error);
350 /* Login successful, but no need to hang onto it,
351 so logout immediately */
352 append(out, loginok, strlen(loginok));
353 syslog(LOG_INFO, "Login ClearTxtUAM: %s", username);
354 pam_close_session(pamh, 0);
362 static int uam_setup(const char *path)
364 if (uam_register(UAM_SERVER_LOGIN, path, "Cleartxt Passwrd",
365 pam_login, NULL, pam_logout) < 0)
368 if (uam_register(UAM_SERVER_CHANGEPW, path, "Cleartxt Passwrd",
370 uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
374 if (uam_register(UAM_SERVER_PRINTAUTH, path, "ClearTxtUAM",
382 static void uam_cleanup(void)
384 uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
385 uam_unregister(UAM_SERVER_CHANGEPW, "Cleartxt Passwrd");
386 uam_unregister(UAM_SERVER_PRINTAUTH, "ClearTxtUAM");
389 UAM_MODULE_EXPORT struct uam_export uams_pam = {
392 uam_setup, uam_cleanup