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 */
19 #ifdef HAVE_SECURITY_PAM_APPL_H
20 #include <security/pam_appl.h>
22 #ifdef HAVE_PAM_PAM_APPL_H
23 #include <pam/pam_appl.h>
25 #include <arpa/inet.h>
27 #include <atalk/afp.h>
28 #include <atalk/uam.h>
29 #include <atalk/util.h>
30 #include <atalk/logger.h>
31 #include <atalk/compat.h>
36 #define MIN(a,b) ((a) < (b) ? (a) : (b))
40 /* Static variables used to communicate between the conversation function
41 * and the server_login function
43 static pam_handle_t *pamh = NULL;
44 static const char *hostname;
45 static char *PAM_username;
46 static char *PAM_password;
48 /*XXX in etc/papd/file.h */
50 extern UAM_MODULE_EXPORT void append(struct papfile *, const char *, int);
52 /* PAM conversation function
53 * Here we assume (for now, at least) that echo on means login name, and
54 * echo off means password.
56 static int PAM_conv (int num_msg,
58 const struct pam_message **msg,
60 struct pam_message **msg,
62 struct pam_response **resp,
63 void *appdata_ptr _U_)
65 struct pam_response *reply;
68 #define COPY_STRING(s) (s) ? strdup(s) : NULL
73 reply = (struct pam_response *)
74 calloc(num_msg, sizeof(struct pam_response));
79 for (count = 0; count < num_msg; count++) {
82 switch (msg[count]->msg_style) {
83 case PAM_PROMPT_ECHO_ON:
84 if (!(string = COPY_STRING(PAM_username)))
87 case PAM_PROMPT_ECHO_OFF:
88 if (!(string = COPY_STRING(PAM_password)))
92 #ifdef PAM_BINARY_PROMPT
93 case PAM_BINARY_PROMPT:
94 #endif /* PAM_BINARY_PROMPT */
103 reply[count].resp_retcode = 0;
104 reply[count].resp = string;
113 for (count = 0; count < num_msg; count++) {
114 if (!reply[count].resp)
116 switch (msg[count]->msg_style) {
117 case PAM_PROMPT_ECHO_OFF:
118 case PAM_PROMPT_ECHO_ON:
119 free(reply[count].resp);
127 static struct pam_conv PAM_conversation = {
132 static int login(void *obj, char *username, int ulen, struct passwd **uam_pwd,
133 char *ibuf, size_t ibuflen _U_,
134 char *rbuf _U_, size_t *rbuflen _U_)
139 if (uam_afpserver_option(obj, UAM_OPTION_CLIENTNAME,
140 (void *) &hostname, NULL) < 0)
142 LOG(log_info, logtype_uams, "uams_pam.c :PAM: unable to retrieve client hostname");
146 ibuf[ PASSWDLEN ] = '\0';
148 if (( pwd = uam_getname(obj, username, ulen)) == NULL ) {
149 return AFPERR_NOTAUTH;
152 LOG(log_info, logtype_uams, "cleartext login: %s", username);
153 PAM_username = username;
154 PAM_password = ibuf; /* Set these things up for the conv function */
156 err = AFPERR_NOTAUTH;
157 PAM_error = pam_start("netatalk", username, &PAM_conversation,
159 if (PAM_error != PAM_SUCCESS)
162 pam_set_item(pamh, PAM_TTY, "afpd");
163 pam_set_item(pamh, PAM_RHOST, hostname);
164 /* use PAM_DISALLOW_NULL_AUTHTOK if passwdminlen > 0 */
165 PAM_error = pam_authenticate(pamh,0);
166 if (PAM_error != PAM_SUCCESS) {
167 if (PAM_error == PAM_MAXTRIES)
168 err = AFPERR_PWDEXPR;
172 PAM_error = pam_acct_mgmt(pamh, 0);
173 if (PAM_error != PAM_SUCCESS) {
174 if (PAM_error == PAM_NEW_AUTHTOK_REQD) /* Password change required */
175 err = AFPERR_PWDEXPR;
176 #ifdef PAM_AUTHTOKEN_REQD
177 else if (PAM_error == PAM_AUTHTOKEN_REQD)
178 err = AFPERR_PWDCHNG;
179 #endif /* PAM_AUTHTOKEN_REQD */
184 #ifndef PAM_CRED_ESTABLISH
185 #define PAM_CRED_ESTABLISH PAM_ESTABLISH_CRED
186 #endif /* PAM_CRED_ESTABLISH */
187 PAM_error = pam_setcred(pamh, PAM_CRED_ESTABLISH);
188 if (PAM_error != PAM_SUCCESS)
191 PAM_error = pam_open_session(pamh, 0);
192 if (PAM_error != PAM_SUCCESS)
197 if (err == AFPERR_PWDEXPR)
203 pam_end(pamh, PAM_error);
208 /* --------------------------
211 static int pam_login(void *obj, struct passwd **uam_pwd,
212 char *ibuf, size_t ibuflen,
213 char *rbuf, size_t *rbuflen)
220 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, (void *) &username, &ulen) < 0) {
224 len = (unsigned char) *ibuf++;
226 return( AFPERR_PARAM );
229 memcpy(username, ibuf, len );
232 username[ len ] = '\0';
234 if ((unsigned long) ibuf & 1) /* pad character */
236 return (login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
239 /* ----------------------------- */
240 static int pam_login_ext(void *obj, char *uname, struct passwd **uam_pwd,
241 char *ibuf, size_t ibuflen,
242 char *rbuf, size_t *rbuflen)
250 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, (void *) &username, &ulen) < 0)
256 memcpy(&temp16, uname, sizeof(temp16));
259 if (!len || len > ulen ) {
260 return( AFPERR_PARAM );
262 memcpy(username, uname +2, len );
263 username[ len ] = '\0';
265 return (login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
269 static void pam_logout(void) {
270 pam_close_session(pamh, 0);
276 static int pam_changepw(void *obj _U_, char *username,
277 struct passwd *pwd _U_, char *ibuf, size_t ibuflen _U_,
278 char *rbuf _U_, size_t *rbuflen _U_)
280 char pw[PASSWDLEN + 1];
286 memcpy(pw, ibuf, PASSWDLEN);
287 memset(ibuf, 0, PASSWDLEN);
288 pw[PASSWDLEN] = '\0';
290 /* let's do a quick check for the same password */
291 if (memcmp(pw, ibuf + PASSWDLEN, PASSWDLEN) == 0)
292 return AFPERR_PWDSAME;
294 /* Set these things up for the conv function */
295 PAM_username = username;
298 PAM_error = pam_start("netatalk", username, &PAM_conversation,
300 if (PAM_error != PAM_SUCCESS)
302 pam_set_item(lpamh, PAM_TTY, "afpd");
303 pam_set_item(lpamh, PAM_RHOST, hostname);
305 /* we might need to do this as root */
308 PAM_error = pam_authenticate(lpamh,0);
309 if (PAM_error != PAM_SUCCESS) {
311 pam_end(lpamh, PAM_error);
312 return AFPERR_NOTAUTH;
318 ibuf[PASSWDLEN] = '\0';
320 /* this really does need to be done as root */
321 PAM_error = pam_chauthtok(lpamh, 0);
322 seteuid(uid); /* un-root ourselves. */
323 memset(pw, 0, PASSWDLEN);
324 memset(ibuf, 0, PASSWDLEN);
325 if (PAM_error != PAM_SUCCESS) {
326 pam_end(lpamh, PAM_error);
327 return AFPERR_ACCESS;
335 /* Printer ClearTxtUAM login */
336 static int pam_printer(char *start, char *stop, char *username, struct papfile *out)
340 char password[PASSWDLEN + 1] = "\0";
341 static const char *loginok = "0\r";
344 data = (char *)malloc(stop - start + 1);
346 LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: malloc");
350 strlcpy(data, start, stop - start + 1);
352 /* We are looking for the following format in data:
353 * (username) (password)
355 * Let's hope username doesn't contain ") ("!
358 /* Parse input for username in () */
359 if ((p = strchr(data, '(' )) == NULL) {
360 LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: username not found in string");
365 if ((q = strstr(p, ") (" )) == NULL) {
366 LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: username not found in string");
370 memcpy(username, p, MIN(UAM_USERNAMELEN, q - p) );
372 /* Parse input for password in next () */
374 if ((q = strrchr(p, ')' )) == NULL) {
375 LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: password not found in string");
379 memcpy(password, p, MIN(PASSWDLEN, (q - p)) );
381 /* Done copying username and password, clean up */
384 if (( pwd = uam_getname(NULL, username, strlen(username))) == NULL ) {
385 LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: ( %s ) not found ",
390 if (uam_checkuser(pwd) < 0) {
391 /* syslog of error happens in uam_checkuser */
395 PAM_username = username;
396 PAM_password = password;
398 PAM_error = pam_start("netatalk", username, &PAM_conversation,
400 if (PAM_error != PAM_SUCCESS) {
401 LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: %s: %s",
402 username, pam_strerror(pamh, PAM_error));
403 pam_end(pamh, PAM_error);
408 pam_set_item(pamh, PAM_TTY, "papd");
409 pam_set_item(pamh, PAM_RHOST, hostname);
410 PAM_error = pam_authenticate(pamh,0);
411 if (PAM_error != PAM_SUCCESS) {
412 LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: %s: %s",
413 username, pam_strerror(pamh, PAM_error));
414 pam_end(pamh, PAM_error);
419 PAM_error = pam_acct_mgmt(pamh, 0);
420 if (PAM_error != PAM_SUCCESS) {
421 LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: %s: %s",
422 username, pam_strerror(pamh, PAM_error));
423 pam_end(pamh, PAM_error);
428 PAM_error = pam_open_session(pamh, 0);
429 if (PAM_error != PAM_SUCCESS) {
430 LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: %s: %s",
431 username, pam_strerror(pamh, PAM_error));
432 pam_end(pamh, PAM_error);
437 /* Login successful, but no need to hang onto it,
438 so logout immediately */
439 append(out, loginok, strlen(loginok));
440 LOG(log_info, logtype_uams, "Login ClearTxtUAM: %s", username);
441 pam_close_session(pamh, 0);
449 static int uam_setup(const char *path)
451 if (uam_register(UAM_SERVER_LOGIN_EXT, path, "Cleartxt Passwrd",
452 pam_login, NULL, pam_logout, pam_login_ext) < 0)
455 if (uam_register(UAM_SERVER_CHANGEPW, path, "Cleartxt Passwrd",
457 uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
461 if (uam_register(UAM_SERVER_PRINTAUTH, path, "ClearTxtUAM",
469 static void uam_cleanup(void)
471 uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
472 uam_unregister(UAM_SERVER_CHANGEPW, "Cleartxt Passwrd");
473 uam_unregister(UAM_SERVER_PRINTAUTH, "ClearTxtUAM");
476 UAM_MODULE_EXPORT struct uam_export uams_clrtxt = {
479 uam_setup, uam_cleanup
482 UAM_MODULE_EXPORT struct uam_export uams_pam = {
485 uam_setup, uam_cleanup