2 * $Id: uams_pam.c,v 1.13 2002-10-13 06:18:14 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>
39 #include <atalk/afp.h>
40 #include <atalk/uam.h>
44 /* Static variables used to communicate between the conversation function
45 * and the server_login function
47 static pam_handle_t *pamh = NULL;
48 static char *hostname;
49 static char *PAM_username;
50 static char *PAM_password;
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,
57 const struct pam_message **msg,
58 struct pam_response **resp,
61 struct pam_response *reply;
64 #define COPY_STRING(s) (s) ? strdup(s) : NULL
69 reply = (struct pam_response *)
70 calloc(num_msg, sizeof(struct pam_response));
75 for (count = 0; count < num_msg; count++) {
78 switch (msg[count]->msg_style) {
79 case PAM_PROMPT_ECHO_ON:
80 if (!(string = COPY_STRING(PAM_username)))
83 case PAM_PROMPT_ECHO_OFF:
84 if (!(string = COPY_STRING(PAM_password)))
88 #ifdef PAM_BINARY_PROMPT
89 case PAM_BINARY_PROMPT:
90 #endif /* PAM_BINARY_PROMPT */
99 reply[count].resp_retcode = 0;
100 reply[count].resp = string;
109 for (count = 0; count < num_msg; count++) {
110 if (!reply[count].resp)
112 switch (msg[count]->msg_style) {
113 case PAM_PROMPT_ECHO_OFF:
114 case PAM_PROMPT_ECHO_ON:
115 free(reply[count].resp);
123 static struct pam_conv PAM_conversation = {
130 static int pam_login(void *obj, struct passwd **uam_pwd,
131 char *ibuf, int ibuflen,
132 char *rbuf, int *rbuflen)
136 int err, len, ulen, PAM_error;
140 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME,
141 (void *) &username, &ulen) < 0)
144 if (uam_afpserver_option(obj, UAM_OPTION_CLIENTNAME,
145 (void *) &hostname, NULL) < 0)
147 LOG(log_info, logtype_uams, "uams_pam.c :PAM: unable to retrieve client hostname");
152 len = (unsigned char) *ibuf++;
154 return( AFPERR_PARAM );
157 memcpy(username, ibuf, len );
159 username[ len ] = '\0';
160 if ((unsigned long) ibuf & 1) /* pad character */
162 ibuf[ PASSWDLEN ] = '\0';
164 if (( pwd = uam_getname(username, ulen)) == NULL ) {
168 LOG(log_info, logtype_uams, "cleartext login: %s", username);
169 PAM_username = username;
170 PAM_password = ibuf; /* Set these things up for the conv function */
172 err = AFPERR_NOTAUTH;
173 PAM_error = pam_start("netatalk", username, &PAM_conversation,
175 if (PAM_error != PAM_SUCCESS)
178 pam_set_item(pamh, PAM_TTY, "afpd");
179 pam_set_item(pamh, PAM_RHOST, hostname);
180 /* use PAM_DISALLOW_NULL_AUTHTOK if passwdminlen > 0 */
181 PAM_error = pam_authenticate(pamh,0);
182 if (PAM_error != PAM_SUCCESS) {
183 if (PAM_error == PAM_MAXTRIES)
184 err = AFPERR_PWDEXPR;
188 PAM_error = pam_acct_mgmt(pamh, 0);
189 if (PAM_error != PAM_SUCCESS) {
190 if (PAM_error == PAM_ACCT_EXPIRED)
191 err = AFPERR_PWDEXPR;
192 #ifdef PAM_AUTHTOKEN_REQD
193 else if (PAM_error == PAM_AUTHTOKEN_REQD)
194 err = AFPERR_PWDCHNG;
195 #endif /* PAM_AUTHTOKEN_REQD */
199 #ifndef PAM_CRED_ESTABLISH
200 #define PAM_CRED_ESTABLISH PAM_ESTABLISH_CRED
201 #endif /* PAM_CRED_ESTABLISH */
202 PAM_error = pam_setcred(pamh, PAM_CRED_ESTABLISH);
203 if (PAM_error != PAM_SUCCESS)
206 PAM_error = pam_open_session(pamh, 0);
207 if (PAM_error != PAM_SUCCESS)
214 pam_end(pamh, PAM_error);
220 static void pam_logout() {
221 pam_close_session(pamh, 0);
227 static int pam_changepw(void *obj, char *username,
228 struct passwd *pwd, char *ibuf, int ibuflen,
229 char *rbuf, int *rbuflen)
231 char pw[PASSWDLEN + 1];
237 memcpy(pw, ibuf, PASSWDLEN);
238 memset(ibuf, 0, PASSWDLEN);
239 pw[PASSWDLEN] = '\0';
241 /* let's do a quick check for the same password */
242 if (memcmp(pw, ibuf + PASSWDLEN, PASSWDLEN) == 0)
243 return AFPERR_PWDSAME;
245 /* Set these things up for the conv function */
246 PAM_username = username;
249 PAM_error = pam_start("netatalk", username, &PAM_conversation,
251 if (PAM_error != PAM_SUCCESS)
253 pam_set_item(lpamh, PAM_TTY, "afpd");
254 pam_set_item(lpamh, PAM_RHOST, hostname);
256 /* we might need to do this as root */
259 PAM_error = pam_authenticate(lpamh,0);
260 if (PAM_error != PAM_SUCCESS) {
262 pam_end(lpamh, PAM_error);
263 return AFPERR_NOTAUTH;
269 ibuf[PASSWDLEN] = '\0';
271 /* this really does need to be done as root */
272 PAM_error = pam_chauthtok(lpamh, 0);
273 seteuid(uid); /* un-root ourselves. */
274 memset(pw, 0, PASSWDLEN);
275 memset(ibuf, 0, PASSWDLEN);
276 if (PAM_error != PAM_SUCCESS) {
277 pam_end(lpamh, PAM_error);
278 return AFPERR_ACCESS;
286 /* Printer ClearTxtUAM login */
287 int pam_printer(start, stop, username, out)
288 char *start, *stop, *username;
293 char password[PASSWDLEN + 1] = "\0";
294 static const char *loginok = "0\r";
296 data = (char *)malloc(stop - start + 1);
297 strncpy(data, start, stop - start + 1);
299 /* We are looking for the following format in data:
300 * (username) (password)
302 * Let's hope username doesn't contain ") ("!
305 /* Parse input for username in () */
306 if ((p = strchr(data, '(' )) == NULL) {
307 LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: username not found in string");
312 if ((q = strstr(data, ") (" )) == NULL) {
313 LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: username not found in string");
317 strncpy(username, p, q - p);
319 /* Parse input for password in next () */
321 if ((q = strrchr(data, ')' )) == NULL) {
322 LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: password not found in string");
326 strncpy(password, p, q - p);
328 /* Done copying username and password, clean up */
331 PAM_username = username;
332 PAM_password = password;
334 PAM_error = pam_start("netatalk", username, &PAM_conversation,
336 if (PAM_error != PAM_SUCCESS) {
337 LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: %s: %s",
338 username, pam_strerror(pamh, PAM_error));
339 pam_end(pamh, PAM_error);
344 pam_set_item(pamh, PAM_TTY, "papd");
345 pam_set_item(pamh, PAM_RHOST, hostname);
346 PAM_error = pam_authenticate(pamh,0);
347 if (PAM_error != PAM_SUCCESS) {
348 LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: %s: %s",
349 username, pam_strerror(pamh, PAM_error));
350 pam_end(pamh, PAM_error);
355 PAM_error = pam_acct_mgmt(pamh, 0);
356 if (PAM_error != PAM_SUCCESS) {
357 LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: %s: %s",
358 username, pam_strerror(pamh, PAM_error));
359 pam_end(pamh, PAM_error);
364 PAM_error = pam_open_session(pamh, 0);
365 if (PAM_error != PAM_SUCCESS) {
366 LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: %s: %s",
367 username, pam_strerror(pamh, PAM_error));
368 pam_end(pamh, PAM_error);
373 /* Login successful, but no need to hang onto it,
374 so logout immediately */
375 append(out, loginok, strlen(loginok));
376 LOG(log_info, logtype_uams, "Login ClearTxtUAM: %s", username);
377 pam_close_session(pamh, 0);
385 static int uam_setup(const char *path)
387 if (uam_register(UAM_SERVER_LOGIN, path, "Cleartxt Passwrd",
388 pam_login, NULL, pam_logout) < 0)
391 if (uam_register(UAM_SERVER_CHANGEPW, path, "Cleartxt Passwrd",
393 uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
397 if (uam_register(UAM_SERVER_PRINTAUTH, path, "ClearTxtUAM",
405 static void uam_cleanup(void)
407 uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
408 uam_unregister(UAM_SERVER_CHANGEPW, "Cleartxt Passwrd");
409 uam_unregister(UAM_SERVER_PRINTAUTH, "ClearTxtUAM");
412 UAM_MODULE_EXPORT struct uam_export uams_clrtxt = {
415 uam_setup, uam_cleanup
418 UAM_MODULE_EXPORT struct uam_export uams_pam = {
421 uam_setup, uam_cleanup