2 * $Id: uams_pam.c,v 1.15.2.1.2.4 2003-11-01 02:38:09 bfernhomberg Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu)
6 * All Rights Reserved. See COPYRIGHT.
11 #endif /* HAVE_CONFIG_H */
18 #endif /* HAVE_UNISTD_H */
23 #else /* STDC_HEADERS */
27 #endif /* HAVE_STRCHR */
28 char *strchr (), *strrchr ();
30 #define memcpy(d,s,n) bcopy ((s), (d), (n))
31 #define memmove(d,s,n) bcopy ((s), (d), (n))
32 #endif /* ! HAVE_MEMCPY */
33 #endif /* STDC_HEADERS */
35 #include <atalk/logger.h>
37 #ifdef HAVE_SECURITY_PAM_APPL_H
38 #include <security/pam_appl.h>
40 #ifdef HAVE_PAM_PAM_APPL_H
41 #include <pam/pam_appl.h>
44 #include <atalk/afp.h>
45 #include <atalk/uam.h>
50 #define MIN(a,b) ((a) < (b) ? (a) : (b))
54 /* Static variables used to communicate between the conversation function
55 * and the server_login function
57 static pam_handle_t *pamh = NULL;
58 static char *hostname;
59 static char *PAM_username;
60 static char *PAM_password;
62 extern void append(void *, const char *, int);
64 /* PAM conversation function
65 * Here we assume (for now, at least) that echo on means login name, and
66 * echo off means password.
68 static int PAM_conv (int num_msg,
69 const struct pam_message **msg,
70 struct pam_response **resp,
73 struct pam_response *reply;
76 #define COPY_STRING(s) (s) ? strdup(s) : NULL
81 reply = (struct pam_response *)
82 calloc(num_msg, sizeof(struct pam_response));
87 for (count = 0; count < num_msg; count++) {
90 switch (msg[count]->msg_style) {
91 case PAM_PROMPT_ECHO_ON:
92 if (!(string = COPY_STRING(PAM_username)))
95 case PAM_PROMPT_ECHO_OFF:
96 if (!(string = COPY_STRING(PAM_password)))
100 #ifdef PAM_BINARY_PROMPT
101 case PAM_BINARY_PROMPT:
102 #endif /* PAM_BINARY_PROMPT */
111 reply[count].resp_retcode = 0;
112 reply[count].resp = string;
121 for (count = 0; count < num_msg; count++) {
122 if (!reply[count].resp)
124 switch (msg[count]->msg_style) {
125 case PAM_PROMPT_ECHO_OFF:
126 case PAM_PROMPT_ECHO_ON:
127 free(reply[count].resp);
135 static struct pam_conv PAM_conversation = {
140 static int login(void *obj, char *username, int ulen, struct passwd **uam_pwd,
141 char *ibuf, int ibuflen,
142 char *rbuf, int *rbuflen)
147 if (uam_afpserver_option(obj, UAM_OPTION_CLIENTNAME,
148 (void *) &hostname, NULL) < 0)
150 LOG(log_info, logtype_uams, "uams_pam.c :PAM: unable to retrieve client hostname");
154 ibuf[ PASSWDLEN ] = '\0';
156 if (( pwd = uam_getname(obj, username, ulen)) == NULL ) {
160 LOG(log_info, logtype_uams, "cleartext login: %s", username);
161 PAM_username = username;
162 PAM_password = ibuf; /* Set these things up for the conv function */
164 err = AFPERR_NOTAUTH;
165 PAM_error = pam_start("netatalk", username, &PAM_conversation,
167 if (PAM_error != PAM_SUCCESS)
170 pam_set_item(pamh, PAM_TTY, "afpd");
171 pam_set_item(pamh, PAM_RHOST, hostname);
172 /* use PAM_DISALLOW_NULL_AUTHTOK if passwdminlen > 0 */
173 PAM_error = pam_authenticate(pamh,0);
174 if (PAM_error != PAM_SUCCESS) {
175 if (PAM_error == PAM_MAXTRIES)
176 err = AFPERR_PWDEXPR;
180 PAM_error = pam_acct_mgmt(pamh, 0);
181 if (PAM_error != PAM_SUCCESS) {
182 if (PAM_error == PAM_NEW_AUTHTOK_REQD) /* Password change required */
183 err = AFPERR_PWDEXPR;
184 #ifdef PAM_AUTHTOKEN_REQD
185 else if (PAM_error == PAM_AUTHTOKEN_REQD)
186 err = AFPERR_PWDCHNG;
187 #endif /* PAM_AUTHTOKEN_REQD */
192 #ifndef PAM_CRED_ESTABLISH
193 #define PAM_CRED_ESTABLISH PAM_ESTABLISH_CRED
194 #endif /* PAM_CRED_ESTABLISH */
195 PAM_error = pam_setcred(pamh, PAM_CRED_ESTABLISH);
196 if (PAM_error != PAM_SUCCESS)
199 PAM_error = pam_open_session(pamh, 0);
200 if (PAM_error != PAM_SUCCESS)
205 if (err == AFPERR_PWDEXPR)
211 pam_end(pamh, PAM_error);
216 /* --------------------------
219 static int pam_login(void *obj, struct passwd **uam_pwd,
220 char *ibuf, int ibuflen,
221 char *rbuf, int *rbuflen)
228 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, (void *) &username, &ulen) < 0) {
232 len = (unsigned char) *ibuf++;
234 return( AFPERR_PARAM );
237 memcpy(username, ibuf, len );
240 username[ len ] = '\0';
242 if ((unsigned long) ibuf & 1) /* pad character */
244 return (login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
247 /* ----------------------------- */
248 static int pam_login_ext(void *obj, char *uname, struct passwd **uam_pwd,
249 char *ibuf, int ibuflen,
250 char *rbuf, int *rbuflen)
258 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, (void *) &username, &ulen) < 0)
264 memcpy(&temp16, uname, sizeof(temp16));
267 if (!len || len > ulen ) {
268 return( AFPERR_PARAM );
270 memcpy(username, uname +2, len );
271 username[ len ] = '\0';
273 return (login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
277 static void pam_logout() {
278 pam_close_session(pamh, 0);
284 static int pam_changepw(void *obj, char *username,
285 struct passwd *pwd, char *ibuf, int ibuflen,
286 char *rbuf, int *rbuflen)
288 char pw[PASSWDLEN + 1];
294 memcpy(pw, ibuf, PASSWDLEN);
295 memset(ibuf, 0, PASSWDLEN);
296 pw[PASSWDLEN] = '\0';
298 /* let's do a quick check for the same password */
299 if (memcmp(pw, ibuf + PASSWDLEN, PASSWDLEN) == 0)
300 return AFPERR_PWDSAME;
302 /* Set these things up for the conv function */
303 PAM_username = username;
306 PAM_error = pam_start("netatalk", username, &PAM_conversation,
308 if (PAM_error != PAM_SUCCESS)
310 pam_set_item(lpamh, PAM_TTY, "afpd");
311 pam_set_item(lpamh, PAM_RHOST, hostname);
313 /* we might need to do this as root */
316 PAM_error = pam_authenticate(lpamh,0);
317 if (PAM_error != PAM_SUCCESS) {
319 pam_end(lpamh, PAM_error);
320 return AFPERR_NOTAUTH;
326 ibuf[PASSWDLEN] = '\0';
328 /* this really does need to be done as root */
329 PAM_error = pam_chauthtok(lpamh, 0);
330 seteuid(uid); /* un-root ourselves. */
331 memset(pw, 0, PASSWDLEN);
332 memset(ibuf, 0, PASSWDLEN);
333 if (PAM_error != PAM_SUCCESS) {
334 pam_end(lpamh, PAM_error);
335 return AFPERR_ACCESS;
343 /* Printer ClearTxtUAM login */
344 int pam_printer(start, stop, username, out)
345 char *start, *stop, *username;
350 char password[PASSWDLEN + 1] = "\0";
351 static const char *loginok = "0\r";
354 data = (char *)malloc(stop - start + 2);
356 LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: malloc");
360 strncpy(data, start, stop - start + 1);
361 data[stop - start + 2] = 0;
363 /* We are looking for the following format in data:
364 * (username) (password)
366 * Let's hope username doesn't contain ") ("!
369 /* Parse input for username in () */
370 if ((p = strchr(data, '(' )) == NULL) {
371 LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: username not found in string");
376 if ((q = strstr(p, ") (" )) == NULL) {
377 LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: username not found in string");
381 strncpy(username, p, MIN(UAM_USERNAMELEN, q - p) );
382 username[ UAM_USERNAMELEN +1] = '\0';
384 /* Parse input for password in next () */
386 if ((q = strrchr(p, ')' )) == NULL) {
387 LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: password not found in string");
391 strncpy(password, p, MIN(PASSWDLEN, (q - p)) );
392 password[ PASSWDLEN + 1] = '\0';
394 /* Done copying username and password, clean up */
397 if (( pwd = uam_getname(NULL, username, strlen(username))) == NULL ) {
398 LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: ( %s ) not found ",
403 if (uam_checkuser(pwd) < 0) {
404 /* syslog of error happens in uam_checkuser */
408 PAM_username = username;
409 PAM_password = password;
411 PAM_error = pam_start("netatalk", username, &PAM_conversation,
413 if (PAM_error != PAM_SUCCESS) {
414 LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: %s: %s",
415 username, pam_strerror(pamh, PAM_error));
416 pam_end(pamh, PAM_error);
421 pam_set_item(pamh, PAM_TTY, "papd");
422 pam_set_item(pamh, PAM_RHOST, hostname);
423 PAM_error = pam_authenticate(pamh,0);
424 if (PAM_error != PAM_SUCCESS) {
425 LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: %s: %s",
426 username, pam_strerror(pamh, PAM_error));
427 pam_end(pamh, PAM_error);
432 PAM_error = pam_acct_mgmt(pamh, 0);
433 if (PAM_error != PAM_SUCCESS) {
434 LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: %s: %s",
435 username, pam_strerror(pamh, PAM_error));
436 pam_end(pamh, PAM_error);
441 PAM_error = pam_open_session(pamh, 0);
442 if (PAM_error != PAM_SUCCESS) {
443 LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: %s: %s",
444 username, pam_strerror(pamh, PAM_error));
445 pam_end(pamh, PAM_error);
450 /* Login successful, but no need to hang onto it,
451 so logout immediately */
452 append(out, loginok, strlen(loginok));
453 LOG(log_info, logtype_uams, "Login ClearTxtUAM: %s", username);
454 pam_close_session(pamh, 0);
462 static int uam_setup(const char *path)
464 if (uam_register(UAM_SERVER_LOGIN_EXT, path, "Cleartxt Passwrd",
465 pam_login, NULL, pam_logout, pam_login_ext) < 0)
468 if (uam_register(UAM_SERVER_CHANGEPW, path, "Cleartxt Passwrd",
470 uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
474 if (uam_register(UAM_SERVER_PRINTAUTH, path, "ClearTxtUAM",
482 static void uam_cleanup(void)
484 uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
485 uam_unregister(UAM_SERVER_CHANGEPW, "Cleartxt Passwrd");
486 uam_unregister(UAM_SERVER_PRINTAUTH, "ClearTxtUAM");
489 UAM_MODULE_EXPORT struct uam_export uams_clrtxt = {
492 uam_setup, uam_cleanup
495 UAM_MODULE_EXPORT struct uam_export uams_pam = {
498 uam_setup, uam_cleanup