2 * $Id: uams_pam.c,v 1.15.2.1.2.1 2003-09-09 16:42:20 didg 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 #include <security/pam_appl.h>
38 #include <atalk/unicode.h>
40 #include <atalk/afp.h>
41 #include <atalk/uam.h>
46 #define MIN(a,b) ((a) < (b) ? (a) : (b))
50 /* Static variables used to communicate between the conversation function
51 * and the server_login function
53 static pam_handle_t *pamh = NULL;
54 static char *hostname;
55 static char *PAM_username;
56 static char *PAM_password;
58 extern void append(void *, const char *, int);
60 /* PAM conversation function
61 * Here we assume (for now, at least) that echo on means login name, and
62 * echo off means password.
64 static int PAM_conv (int num_msg,
65 const struct pam_message **msg,
66 struct pam_response **resp,
69 struct pam_response *reply;
72 #define COPY_STRING(s) (s) ? strdup(s) : NULL
77 reply = (struct pam_response *)
78 calloc(num_msg, sizeof(struct pam_response));
83 for (count = 0; count < num_msg; count++) {
86 switch (msg[count]->msg_style) {
87 case PAM_PROMPT_ECHO_ON:
88 if (!(string = COPY_STRING(PAM_username)))
91 case PAM_PROMPT_ECHO_OFF:
92 if (!(string = COPY_STRING(PAM_password)))
96 #ifdef PAM_BINARY_PROMPT
97 case PAM_BINARY_PROMPT:
98 #endif /* PAM_BINARY_PROMPT */
107 reply[count].resp_retcode = 0;
108 reply[count].resp = string;
117 for (count = 0; count < num_msg; count++) {
118 if (!reply[count].resp)
120 switch (msg[count]->msg_style) {
121 case PAM_PROMPT_ECHO_OFF:
122 case PAM_PROMPT_ECHO_ON:
123 free(reply[count].resp);
131 static struct pam_conv PAM_conversation = {
136 static int login(void *obj, char *username, int ulen, struct passwd **uam_pwd,
137 char *ibuf, int ibuflen,
138 char *rbuf, int *rbuflen)
143 if (uam_afpserver_option(obj, UAM_OPTION_CLIENTNAME,
144 (void *) &hostname, NULL) < 0)
146 LOG(log_info, logtype_uams, "uams_pam.c :PAM: unable to retrieve client hostname");
150 ibuf[ PASSWDLEN ] = '\0';
152 if (( pwd = uam_getname(username, ulen)) == NULL ) {
156 LOG(log_info, logtype_uams, "cleartext login: %s", username);
157 PAM_username = username;
158 PAM_password = ibuf; /* Set these things up for the conv function */
160 err = AFPERR_NOTAUTH;
161 PAM_error = pam_start("netatalk", username, &PAM_conversation,
163 if (PAM_error != PAM_SUCCESS)
166 pam_set_item(pamh, PAM_TTY, "afpd");
167 pam_set_item(pamh, PAM_RHOST, hostname);
168 /* use PAM_DISALLOW_NULL_AUTHTOK if passwdminlen > 0 */
169 PAM_error = pam_authenticate(pamh,0);
170 if (PAM_error != PAM_SUCCESS) {
171 if (PAM_error == PAM_MAXTRIES)
172 err = AFPERR_PWDEXPR;
176 PAM_error = pam_acct_mgmt(pamh, 0);
177 if (PAM_error != PAM_SUCCESS) {
178 if (PAM_error == PAM_ACCT_EXPIRED)
179 err = AFPERR_PWDEXPR;
180 #ifdef PAM_AUTHTOKEN_REQD
181 else if (PAM_error == PAM_AUTHTOKEN_REQD)
182 err = AFPERR_PWDCHNG;
183 #endif /* PAM_AUTHTOKEN_REQD */
187 #ifndef PAM_CRED_ESTABLISH
188 #define PAM_CRED_ESTABLISH PAM_ESTABLISH_CRED
189 #endif /* PAM_CRED_ESTABLISH */
190 PAM_error = pam_setcred(pamh, PAM_CRED_ESTABLISH);
191 if (PAM_error != PAM_SUCCESS)
194 PAM_error = pam_open_session(pamh, 0);
195 if (PAM_error != PAM_SUCCESS)
202 pam_end(pamh, PAM_error);
207 /* --------------------------
210 static int pam_login(void *obj, struct passwd **uam_pwd,
211 char *ibuf, int ibuflen,
212 char *rbuf, int *rbuflen)
219 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, (void *) &username, &ulen) < 0) {
223 len = (unsigned char) *ibuf++;
225 return( AFPERR_PARAM );
228 memcpy(username, ibuf, len );
231 username[ len ] = '\0';
233 len = convert_charset(CH_MAC, CH_UNIX, username, len, username, ulen, 0);
236 if ((unsigned long) ibuf & 1) /* pad character */
238 return (login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
241 /* ----------------------------- */
242 static int pam_login_ext(void *obj, char *uname, struct passwd **uam_pwd,
243 char *ibuf, int ibuflen,
244 char *rbuf, int *rbuflen)
252 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, (void *) &username, &ulen) < 0)
258 memcpy(&temp16, uname, sizeof(temp16));
261 if (!len || len > ulen ) {
262 return( AFPERR_PARAM );
264 memcpy(username, uname +2, len );
265 username[ len ] = '\0';
267 len = convert_charset(CH_UTF8_MAC, CH_UNIX, username, len, username, ulen, 0);
269 return (login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
273 static void pam_logout() {
274 pam_close_session(pamh, 0);
280 static int pam_changepw(void *obj, char *username,
281 struct passwd *pwd, char *ibuf, int ibuflen,
282 char *rbuf, int *rbuflen)
284 char pw[PASSWDLEN + 1];
290 memcpy(pw, ibuf, PASSWDLEN);
291 memset(ibuf, 0, PASSWDLEN);
292 pw[PASSWDLEN] = '\0';
294 /* let's do a quick check for the same password */
295 if (memcmp(pw, ibuf + PASSWDLEN, PASSWDLEN) == 0)
296 return AFPERR_PWDSAME;
298 /* Set these things up for the conv function */
299 PAM_username = username;
302 PAM_error = pam_start("netatalk", username, &PAM_conversation,
304 if (PAM_error != PAM_SUCCESS)
306 pam_set_item(lpamh, PAM_TTY, "afpd");
307 pam_set_item(lpamh, PAM_RHOST, hostname);
309 /* we might need to do this as root */
312 PAM_error = pam_authenticate(lpamh,0);
313 if (PAM_error != PAM_SUCCESS) {
315 pam_end(lpamh, PAM_error);
316 return AFPERR_NOTAUTH;
322 ibuf[PASSWDLEN] = '\0';
324 /* this really does need to be done as root */
325 PAM_error = pam_chauthtok(lpamh, 0);
326 seteuid(uid); /* un-root ourselves. */
327 memset(pw, 0, PASSWDLEN);
328 memset(ibuf, 0, PASSWDLEN);
329 if (PAM_error != PAM_SUCCESS) {
330 pam_end(lpamh, PAM_error);
331 return AFPERR_ACCESS;
339 /* Printer ClearTxtUAM login */
340 int pam_printer(start, stop, username, out)
341 char *start, *stop, *username;
346 char password[PASSWDLEN + 1] = "\0";
347 static const char *loginok = "0\r";
350 data = (char *)malloc(stop - start + 2);
352 LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: malloc");
356 strncpy(data, start, stop - start + 1);
357 data[stop - start + 2] = 0;
359 /* We are looking for the following format in data:
360 * (username) (password)
362 * Let's hope username doesn't contain ") ("!
365 /* Parse input for username in () */
366 if ((p = strchr(data, '(' )) == NULL) {
367 LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: username not found in string");
372 if ((q = strstr(p, ") (" )) == NULL) {
373 LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: username not found in string");
377 strncpy(username, p, MIN(UAM_USERNAMELEN, q - p) );
378 username[ UAM_USERNAMELEN +1] = '\0';
380 /* Parse input for password in next () */
382 if ((q = strrchr(p, ')' )) == NULL) {
383 LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: password not found in string");
387 strncpy(password, p, MIN(PASSWDLEN, (q - p)) );
388 password[ PASSWDLEN + 1] = '\0';
390 /* Done copying username and password, clean up */
393 if (( pwd = uam_getname(username, strlen(username))) == NULL ) {
394 LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: ( %s ) not found ",
399 if (uam_checkuser(pwd) < 0) {
400 /* syslog of error happens in uam_checkuser */
404 PAM_username = username;
405 PAM_password = password;
407 PAM_error = pam_start("netatalk", username, &PAM_conversation,
409 if (PAM_error != PAM_SUCCESS) {
410 LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: %s: %s",
411 username, pam_strerror(pamh, PAM_error));
412 pam_end(pamh, PAM_error);
417 pam_set_item(pamh, PAM_TTY, "papd");
418 pam_set_item(pamh, PAM_RHOST, hostname);
419 PAM_error = pam_authenticate(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_acct_mgmt(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 PAM_error = pam_open_session(pamh, 0);
438 if (PAM_error != PAM_SUCCESS) {
439 LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: %s: %s",
440 username, pam_strerror(pamh, PAM_error));
441 pam_end(pamh, PAM_error);
446 /* Login successful, but no need to hang onto it,
447 so logout immediately */
448 append(out, loginok, strlen(loginok));
449 LOG(log_info, logtype_uams, "Login ClearTxtUAM: %s", username);
450 pam_close_session(pamh, 0);
458 static int uam_setup(const char *path)
460 if (uam_register(UAM_SERVER_LOGIN_EXT, path, "Cleartxt Passwrd",
461 pam_login, NULL, pam_logout, pam_login_ext) < 0)
464 if (uam_register(UAM_SERVER_CHANGEPW, path, "Cleartxt Passwrd",
466 uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
470 if (uam_register(UAM_SERVER_PRINTAUTH, path, "ClearTxtUAM",
478 static void uam_cleanup(void)
480 uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
481 uam_unregister(UAM_SERVER_CHANGEPW, "Cleartxt Passwrd");
482 uam_unregister(UAM_SERVER_PRINTAUTH, "ClearTxtUAM");
485 UAM_MODULE_EXPORT struct uam_export uams_clrtxt = {
488 uam_setup, uam_cleanup
491 UAM_MODULE_EXPORT struct uam_export uams_pam = {
494 uam_setup, uam_cleanup