2 * $Id: uams_pam.c,v 1.9 2001-11-10 18:30:21 srittau 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 */
36 #include <security/pam_appl.h>
38 #include <atalk/afp.h>
39 #include <atalk/uam.h>
43 /* Static variables used to communicate between the conversation function
44 * and the server_login function
46 static pam_handle_t *pamh = NULL;
47 static char *hostname;
48 static char *PAM_username;
49 static char *PAM_password;
51 /* PAM conversation function
52 * Here we assume (for now, at least) that echo on means login name, and
53 * echo off means password.
55 static int PAM_conv (int num_msg,
56 const struct pam_message **msg,
57 struct pam_response **resp,
60 struct pam_response *reply;
63 #define COPY_STRING(s) (s) ? strdup(s) : NULL
68 reply = (struct pam_response *)
69 calloc(num_msg, sizeof(struct pam_response));
74 for (count = 0; count < num_msg; count++) {
77 switch (msg[count]->msg_style) {
78 case PAM_PROMPT_ECHO_ON:
79 if (!(string = COPY_STRING(PAM_username)))
82 case PAM_PROMPT_ECHO_OFF:
83 if (!(string = COPY_STRING(PAM_password)))
87 #ifdef PAM_BINARY_PROMPT
88 case PAM_BINARY_PROMPT:
89 #endif /* PAM_BINARY_PROMPT */
98 reply[count].resp_retcode = 0;
99 reply[count].resp = string;
108 for (count = 0; count < num_msg; count++) {
109 if (!reply[count].resp)
111 switch (msg[count]->msg_style) {
112 case PAM_PROMPT_ECHO_OFF:
113 case PAM_PROMPT_ECHO_ON:
114 free(reply[count].resp);
122 static struct pam_conv PAM_conversation = {
129 static int pam_login(void *obj, struct passwd **uam_pwd,
130 char *ibuf, int ibuflen,
131 char *rbuf, int *rbuflen)
135 int err, len, ulen, PAM_error;
139 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME,
140 (void *) &username, &ulen) < 0)
143 if (uam_afpserver_option(obj, UAM_OPTION_HOSTNAME,
144 (void *) &hostname, NULL) < 0)
147 len = (unsigned char) *ibuf++;
149 return( AFPERR_PARAM );
152 memcpy(username, ibuf, len );
154 username[ len ] = '\0';
155 if ((unsigned long) ibuf & 1) /* pad character */
157 ibuf[ PASSWDLEN ] = '\0';
159 if (( pwd = uam_getname(username, ulen)) == NULL ) {
163 syslog(LOG_INFO, "cleartext login: %s", username);
164 PAM_username = username;
165 PAM_password = ibuf; /* Set these things up for the conv function */
167 err = AFPERR_NOTAUTH;
168 PAM_error = pam_start("netatalk", username, &PAM_conversation,
170 if (PAM_error != PAM_SUCCESS)
173 pam_set_item(pamh, PAM_TTY, "afpd");
174 pam_set_item(pamh, PAM_RHOST, hostname);
175 /* use PAM_DISALLOW_NULL_AUTHTOK if passwdminlen > 0 */
176 PAM_error = pam_authenticate(pamh,0);
177 if (PAM_error != PAM_SUCCESS) {
178 if (PAM_error == PAM_MAXTRIES)
179 err = AFPERR_PWDEXPR;
183 PAM_error = pam_acct_mgmt(pamh, 0);
184 if (PAM_error != PAM_SUCCESS) {
185 if (PAM_error == PAM_ACCT_EXPIRED)
186 err = AFPERR_PWDEXPR;
187 #ifdef PAM_AUTHTOKEN_REQD
188 else if (PAM_error == PAM_AUTHTOKEN_REQD)
189 err = AFPERR_PWDCHNG;
190 #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)
209 pam_end(pamh, PAM_error);
215 static void pam_logout() {
216 pam_close_session(pamh, 0);
222 static int pam_changepw(void *obj, char *username,
223 struct passwd *pwd, char *ibuf, int ibuflen,
224 char *rbuf, int *rbuflen)
226 char pw[PASSWDLEN + 1];
232 memcpy(pw, ibuf, PASSWDLEN);
233 memset(ibuf, 0, PASSWDLEN);
234 pw[PASSWDLEN] = '\0';
236 /* let's do a quick check for the same password */
237 if (memcmp(pw, ibuf + PASSWDLEN, PASSWDLEN) == 0)
238 return AFPERR_PWDSAME;
240 /* Set these things up for the conv function */
241 PAM_username = username;
244 PAM_error = pam_start("netatalk", username, &PAM_conversation,
246 if (PAM_error != PAM_SUCCESS)
248 pam_set_item(lpamh, PAM_TTY, "afpd");
249 pam_set_item(lpamh, PAM_RHOST, hostname);
251 /* we might need to do this as root */
254 PAM_error = pam_authenticate(lpamh,0);
255 if (PAM_error != PAM_SUCCESS) {
257 pam_end(lpamh, PAM_error);
258 return AFPERR_NOTAUTH;
264 ibuf[PASSWDLEN] = '\0';
266 /* this really does need to be done as root */
267 PAM_error = pam_chauthtok(lpamh, 0);
268 seteuid(uid); /* un-root ourselves. */
269 memset(pw, 0, PASSWDLEN);
270 memset(ibuf, 0, PASSWDLEN);
271 if (PAM_error != PAM_SUCCESS) {
272 pam_end(lpamh, PAM_error);
273 return AFPERR_ACCESS;
281 /* Printer ClearTxtUAM login */
282 int pam_printer(start, stop, username, out)
283 char *start, *stop, *username;
288 char password[PASSWDLEN + 1] = "\0";
289 static const char *loginok = "0\r";
291 data = (char *)malloc(stop - start + 1);
292 strncpy(data, start, stop - start + 1);
294 /* We are looking for the following format in data:
295 * (username) (password)
297 * Let's hope username doesn't contain ") ("!
300 /* Parse input for username in () */
301 if ((p = strchr(data, '(' )) == NULL) {
302 syslog(LOG_INFO,"Bad Login ClearTxtUAM: username not found in string");
307 if ((q = strstr(data, ") (" )) == NULL) {
308 syslog(LOG_INFO,"Bad Login ClearTxtUAM: username not found in string");
312 strncpy(username, p, q - p);
314 /* Parse input for password in next () */
316 if ((q = strrchr(data, ')' )) == NULL) {
317 syslog(LOG_INFO,"Bad Login ClearTxtUAM: password not found in string");
321 strncpy(password, p, q - p);
323 /* Done copying username and password, clean up */
326 PAM_username = username;
327 PAM_password = password;
329 PAM_error = pam_start("netatalk", username, &PAM_conversation,
331 if (PAM_error != PAM_SUCCESS) {
332 syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s",
333 username, pam_strerror(pamh, PAM_error));
334 pam_end(pamh, PAM_error);
339 pam_set_item(pamh, PAM_TTY, "papd");
340 pam_set_item(pamh, PAM_RHOST, hostname);
341 PAM_error = pam_authenticate(pamh,0);
342 if (PAM_error != PAM_SUCCESS) {
343 syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s",
344 username, pam_strerror(pamh, PAM_error));
345 pam_end(pamh, PAM_error);
350 PAM_error = pam_acct_mgmt(pamh, 0);
351 if (PAM_error != PAM_SUCCESS) {
352 syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s",
353 username, pam_strerror(pamh, PAM_error));
354 pam_end(pamh, PAM_error);
359 PAM_error = pam_open_session(pamh, 0);
360 if (PAM_error != PAM_SUCCESS) {
361 syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s",
362 username, pam_strerror(pamh, PAM_error));
363 pam_end(pamh, PAM_error);
368 /* Login successful, but no need to hang onto it,
369 so logout immediately */
370 append(out, loginok, strlen(loginok));
371 syslog(LOG_INFO, "Login ClearTxtUAM: %s", username);
372 pam_close_session(pamh, 0);
380 static int uam_setup(const char *path)
382 if (uam_register(UAM_SERVER_LOGIN, path, "Cleartxt Passwrd",
383 pam_login, NULL, pam_logout) < 0)
386 if (uam_register(UAM_SERVER_CHANGEPW, path, "Cleartxt Passwrd",
388 uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
392 if (uam_register(UAM_SERVER_PRINTAUTH, path, "ClearTxtUAM",
400 static void uam_cleanup(void)
402 uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
403 uam_unregister(UAM_SERVER_CHANGEPW, "Cleartxt Passwrd");
404 uam_unregister(UAM_SERVER_PRINTAUTH, "ClearTxtUAM");
407 UAM_MODULE_EXPORT struct uam_export uams_clrtxt = {
410 uam_setup, uam_cleanup
413 UAM_MODULE_EXPORT struct uam_export uams_pam = {
416 uam_setup, uam_cleanup