2 * $Id: uams_pam.c,v 1.24 2010-03-30 10:25:49 franklahm 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 */
17 #endif /* HAVE_UNISTD_H */
22 #else /* STDC_HEADERS */
26 #endif /* HAVE_STRCHR */
27 char *strchr (), *strrchr ();
29 #define memcpy(d,s,n) bcopy ((s), (d), (n))
30 #define memmove(d,s,n) bcopy ((s), (d), (n))
31 #endif /* ! HAVE_MEMCPY */
32 #endif /* STDC_HEADERS */
34 #include <atalk/logger.h>
36 #ifdef HAVE_SECURITY_PAM_APPL_H
37 #include <security/pam_appl.h>
39 #ifdef HAVE_PAM_PAM_APPL_H
40 #include <pam/pam_appl.h>
43 #include <atalk/afp.h>
44 #include <atalk/uam.h>
45 #include <atalk/util.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 const char *hostname;
59 static char *PAM_username;
60 static char *PAM_password;
62 /*XXX in etc/papd/file.h */
64 extern UAM_MODULE_EXPORT void append(struct papfile *, const char *, int);
66 /* PAM conversation function
67 * Here we assume (for now, at least) that echo on means login name, and
68 * echo off means password.
70 static int PAM_conv (int num_msg,
71 const struct pam_message **msg,
72 struct pam_response **resp,
73 void *appdata_ptr _U_)
75 struct pam_response *reply;
78 #define COPY_STRING(s) (s) ? strdup(s) : NULL
83 reply = (struct pam_response *)
84 calloc(num_msg, sizeof(struct pam_response));
89 for (count = 0; count < num_msg; count++) {
92 switch (msg[count]->msg_style) {
93 case PAM_PROMPT_ECHO_ON:
94 if (!(string = COPY_STRING(PAM_username)))
97 case PAM_PROMPT_ECHO_OFF:
98 if (!(string = COPY_STRING(PAM_password)))
102 #ifdef PAM_BINARY_PROMPT
103 case PAM_BINARY_PROMPT:
104 #endif /* PAM_BINARY_PROMPT */
113 reply[count].resp_retcode = 0;
114 reply[count].resp = string;
123 for (count = 0; count < num_msg; count++) {
124 if (!reply[count].resp)
126 switch (msg[count]->msg_style) {
127 case PAM_PROMPT_ECHO_OFF:
128 case PAM_PROMPT_ECHO_ON:
129 free(reply[count].resp);
137 static struct pam_conv PAM_conversation = {
142 static int login(void *obj, char *username, int ulen, struct passwd **uam_pwd,
143 char *ibuf, size_t ibuflen _U_,
144 char *rbuf _U_, size_t *rbuflen _U_)
149 if (uam_afpserver_option(obj, UAM_OPTION_CLIENTNAME,
150 (void *) &hostname, NULL) < 0)
152 LOG(log_info, logtype_uams, "uams_pam.c :PAM: unable to retrieve client hostname");
156 ibuf[ PASSWDLEN ] = '\0';
158 if (( pwd = uam_getname(obj, username, ulen)) == NULL ) {
159 return AFPERR_NOTAUTH;
162 LOG(log_info, logtype_uams, "cleartext login: %s", username);
163 PAM_username = username;
164 PAM_password = ibuf; /* Set these things up for the conv function */
166 err = AFPERR_NOTAUTH;
167 PAM_error = pam_start("netatalk", username, &PAM_conversation,
169 if (PAM_error != PAM_SUCCESS)
172 pam_set_item(pamh, PAM_TTY, "afpd");
173 pam_set_item(pamh, PAM_RHOST, hostname);
174 /* use PAM_DISALLOW_NULL_AUTHTOK if passwdminlen > 0 */
175 PAM_error = pam_authenticate(pamh,0);
176 if (PAM_error != PAM_SUCCESS) {
177 if (PAM_error == PAM_MAXTRIES)
178 err = AFPERR_PWDEXPR;
182 PAM_error = pam_acct_mgmt(pamh, 0);
183 if (PAM_error != PAM_SUCCESS) {
184 if (PAM_error == PAM_NEW_AUTHTOK_REQD) /* Password change required */
185 err = AFPERR_PWDEXPR;
186 #ifdef PAM_AUTHTOKEN_REQD
187 else if (PAM_error == PAM_AUTHTOKEN_REQD)
188 err = AFPERR_PWDCHNG;
189 #endif /* PAM_AUTHTOKEN_REQD */
194 #ifndef PAM_CRED_ESTABLISH
195 #define PAM_CRED_ESTABLISH PAM_ESTABLISH_CRED
196 #endif /* PAM_CRED_ESTABLISH */
197 PAM_error = pam_setcred(pamh, PAM_CRED_ESTABLISH);
198 if (PAM_error != PAM_SUCCESS)
201 PAM_error = pam_open_session(pamh, 0);
202 if (PAM_error != PAM_SUCCESS)
207 if (err == AFPERR_PWDEXPR)
213 pam_end(pamh, PAM_error);
218 /* --------------------------
221 static int pam_login(void *obj, struct passwd **uam_pwd,
222 char *ibuf, size_t ibuflen,
223 char *rbuf, size_t *rbuflen)
230 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, (void *) &username, &ulen) < 0) {
234 len = (unsigned char) *ibuf++;
236 return( AFPERR_PARAM );
239 memcpy(username, ibuf, len );
242 username[ len ] = '\0';
244 if ((unsigned long) ibuf & 1) /* pad character */
246 return (login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
249 /* ----------------------------- */
250 static int pam_login_ext(void *obj, char *uname, struct passwd **uam_pwd,
251 char *ibuf, size_t ibuflen,
252 char *rbuf, size_t *rbuflen)
260 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, (void *) &username, &ulen) < 0)
266 memcpy(&temp16, uname, sizeof(temp16));
269 if (!len || len > ulen ) {
270 return( AFPERR_PARAM );
272 memcpy(username, uname +2, len );
273 username[ len ] = '\0';
275 return (login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
279 static void pam_logout(void) {
280 pam_close_session(pamh, 0);
286 static int pam_changepw(void *obj _U_, char *username,
287 struct passwd *pwd _U_, char *ibuf, size_t ibuflen _U_,
288 char *rbuf _U_, size_t *rbuflen _U_)
290 char pw[PASSWDLEN + 1];
296 memcpy(pw, ibuf, PASSWDLEN);
297 memset(ibuf, 0, PASSWDLEN);
298 pw[PASSWDLEN] = '\0';
300 /* let's do a quick check for the same password */
301 if (memcmp(pw, ibuf + PASSWDLEN, PASSWDLEN) == 0)
302 return AFPERR_PWDSAME;
304 /* Set these things up for the conv function */
305 PAM_username = username;
308 PAM_error = pam_start("netatalk", username, &PAM_conversation,
310 if (PAM_error != PAM_SUCCESS)
312 pam_set_item(lpamh, PAM_TTY, "afpd");
313 pam_set_item(lpamh, PAM_RHOST, hostname);
315 /* we might need to do this as root */
318 PAM_error = pam_authenticate(lpamh,0);
319 if (PAM_error != PAM_SUCCESS) {
321 pam_end(lpamh, PAM_error);
322 return AFPERR_NOTAUTH;
328 ibuf[PASSWDLEN] = '\0';
330 /* this really does need to be done as root */
331 PAM_error = pam_chauthtok(lpamh, 0);
332 seteuid(uid); /* un-root ourselves. */
333 memset(pw, 0, PASSWDLEN);
334 memset(ibuf, 0, PASSWDLEN);
335 if (PAM_error != PAM_SUCCESS) {
336 pam_end(lpamh, PAM_error);
337 return AFPERR_ACCESS;
345 /* Printer ClearTxtUAM login */
346 static int pam_printer(char *start, char *stop, char *username, struct papfile *out)
350 char password[PASSWDLEN + 1] = "\0";
351 static const char *loginok = "0\r";
354 data = (char *)malloc(stop - start + 1);
356 LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: malloc");
360 strlcpy(data, start, stop - start + 1);
362 /* We are looking for the following format in data:
363 * (username) (password)
365 * Let's hope username doesn't contain ") ("!
368 /* Parse input for username in () */
369 if ((p = strchr(data, '(' )) == NULL) {
370 LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: username not found in string");
375 if ((q = strstr(p, ") (" )) == NULL) {
376 LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: username not found in string");
380 memcpy(username, p, MIN(UAM_USERNAMELEN, q - p) );
382 /* Parse input for password in next () */
384 if ((q = strrchr(p, ')' )) == NULL) {
385 LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: password not found in string");
389 memcpy(password, p, MIN(PASSWDLEN, (q - p)) );
391 /* Done copying username and password, clean up */
394 if (( pwd = uam_getname(NULL, username, strlen(username))) == NULL ) {
395 LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: ( %s ) not found ",
400 if (uam_checkuser(pwd) < 0) {
401 /* syslog of error happens in uam_checkuser */
405 PAM_username = username;
406 PAM_password = password;
408 PAM_error = pam_start("netatalk", username, &PAM_conversation,
410 if (PAM_error != PAM_SUCCESS) {
411 LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: %s: %s",
412 username, pam_strerror(pamh, PAM_error));
413 pam_end(pamh, PAM_error);
418 pam_set_item(pamh, PAM_TTY, "papd");
419 pam_set_item(pamh, PAM_RHOST, hostname);
420 PAM_error = pam_authenticate(pamh,0);
421 if (PAM_error != PAM_SUCCESS) {
422 LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: %s: %s",
423 username, pam_strerror(pamh, PAM_error));
424 pam_end(pamh, PAM_error);
429 PAM_error = pam_acct_mgmt(pamh, 0);
430 if (PAM_error != PAM_SUCCESS) {
431 LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: %s: %s",
432 username, pam_strerror(pamh, PAM_error));
433 pam_end(pamh, PAM_error);
438 PAM_error = pam_open_session(pamh, 0);
439 if (PAM_error != PAM_SUCCESS) {
440 LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: %s: %s",
441 username, pam_strerror(pamh, PAM_error));
442 pam_end(pamh, PAM_error);
447 /* Login successful, but no need to hang onto it,
448 so logout immediately */
449 append(out, loginok, strlen(loginok));
450 LOG(log_info, logtype_uams, "Login ClearTxtUAM: %s", username);
451 pam_close_session(pamh, 0);
459 static int uam_setup(const char *path)
461 if (uam_register(UAM_SERVER_LOGIN_EXT, path, "Cleartxt Passwrd",
462 pam_login, NULL, pam_logout, pam_login_ext) < 0)
465 if (uam_register(UAM_SERVER_CHANGEPW, path, "Cleartxt Passwrd",
467 uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
471 if (uam_register(UAM_SERVER_PRINTAUTH, path, "ClearTxtUAM",
479 static void uam_cleanup(void)
481 uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
482 uam_unregister(UAM_SERVER_CHANGEPW, "Cleartxt Passwrd");
483 uam_unregister(UAM_SERVER_PRINTAUTH, "ClearTxtUAM");
486 UAM_MODULE_EXPORT struct uam_export uams_clrtxt = {
489 uam_setup, uam_cleanup
492 UAM_MODULE_EXPORT struct uam_export uams_pam = {
495 uam_setup, uam_cleanup