2 * $Id: uams_pam.c,v 1.8 2001-09-06 20:00:59 rufustfirefly 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 */
19 #endif /* HAVE_UNISTD_H */
24 #else /* STDC_HEADERS */
28 #endif /* HAVE_STRCHR */
29 char *strchr (), *strrchr ();
31 #define memcpy(d,s,n) bcopy ((s), (d), (n))
32 #define memmove(d,s,n) bcopy ((s), (d), (n))
33 #endif /* ! HAVE_MEMCPY */
34 #endif /* STDC_HEADERS */
38 #include <security/pam_appl.h>
40 #include <atalk/afp.h>
41 #include <atalk/uam.h>
45 /* Static variables used to communicate between the conversation function
46 * and the server_login function
48 static pam_handle_t *pamh = NULL;
49 static char *hostname;
50 static char *PAM_username;
51 static char *PAM_password;
53 /* PAM conversation function
54 * Here we assume (for now, at least) that echo on means login name, and
55 * echo off means password.
57 static int PAM_conv (int num_msg,
58 const struct pam_message **msg,
59 struct pam_response **resp,
62 struct pam_response *reply;
65 #define COPY_STRING(s) (s) ? strdup(s) : NULL
70 reply = (struct pam_response *)
71 calloc(num_msg, sizeof(struct pam_response));
76 for (count = 0; count < num_msg; count++) {
79 switch (msg[count]->msg_style) {
80 case PAM_PROMPT_ECHO_ON:
81 if (!(string = COPY_STRING(PAM_username)))
84 case PAM_PROMPT_ECHO_OFF:
85 if (!(string = COPY_STRING(PAM_password)))
89 #ifdef PAM_BINARY_PROMPT
90 case PAM_BINARY_PROMPT:
91 #endif /* PAM_BINARY_PROMPT */
100 reply[count].resp_retcode = 0;
101 reply[count].resp = string;
110 for (count = 0; count < num_msg; count++) {
111 if (!reply[count].resp)
113 switch (msg[count]->msg_style) {
114 case PAM_PROMPT_ECHO_OFF:
115 case PAM_PROMPT_ECHO_ON:
116 free(reply[count].resp);
124 static struct pam_conv PAM_conversation = {
131 static int pam_login(void *obj, struct passwd **uam_pwd,
132 char *ibuf, int ibuflen,
133 char *rbuf, int *rbuflen)
137 int err, len, ulen, PAM_error;
141 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME,
142 (void *) &username, &ulen) < 0)
145 if (uam_afpserver_option(obj, UAM_OPTION_HOSTNAME,
146 (void *) &hostname, NULL) < 0)
149 len = (unsigned char) *ibuf++;
151 return( AFPERR_PARAM );
154 memcpy(username, ibuf, len );
156 username[ len ] = '\0';
157 if ((unsigned long) ibuf & 1) /* pad character */
159 ibuf[ PASSWDLEN ] = '\0';
161 if (( pwd = uam_getname(username, ulen)) == NULL ) {
165 syslog(LOG_INFO, "cleartext login: %s", username);
166 PAM_username = username;
167 PAM_password = ibuf; /* Set these things up for the conv function */
169 err = AFPERR_NOTAUTH;
170 PAM_error = pam_start("netatalk", username, &PAM_conversation,
172 if (PAM_error != PAM_SUCCESS)
175 pam_set_item(pamh, PAM_TTY, "afpd");
176 pam_set_item(pamh, PAM_RHOST, hostname);
177 /* use PAM_DISALLOW_NULL_AUTHTOK if passwdminlen > 0 */
178 PAM_error = pam_authenticate(pamh,0);
179 if (PAM_error != PAM_SUCCESS) {
180 if (PAM_error == PAM_MAXTRIES)
181 err = AFPERR_PWDEXPR;
185 PAM_error = pam_acct_mgmt(pamh, 0);
186 if (PAM_error != PAM_SUCCESS) {
187 if (PAM_error == PAM_ACCT_EXPIRED)
188 err = AFPERR_PWDEXPR;
189 #ifdef PAM_AUTHTOKEN_REQD
190 else if (PAM_error == PAM_AUTHTOKEN_REQD)
191 err = AFPERR_PWDCHNG;
192 #endif /* PAM_AUTHTOKEN_REQD */
196 #ifndef PAM_CRED_ESTABLISH
197 #define PAM_CRED_ESTABLISH PAM_ESTABLISH_CRED
198 #endif /* PAM_CRED_ESTABLISH */
199 PAM_error = pam_setcred(pamh, PAM_CRED_ESTABLISH);
200 if (PAM_error != PAM_SUCCESS)
203 PAM_error = pam_open_session(pamh, 0);
204 if (PAM_error != PAM_SUCCESS)
211 pam_end(pamh, PAM_error);
217 static void pam_logout() {
218 pam_close_session(pamh, 0);
224 static int pam_changepw(void *obj, char *username,
225 struct passwd *pwd, char *ibuf, int ibuflen,
226 char *rbuf, int *rbuflen)
228 char pw[PASSWDLEN + 1];
234 memcpy(pw, ibuf, PASSWDLEN);
235 memset(ibuf, 0, PASSWDLEN);
236 pw[PASSWDLEN] = '\0';
238 /* let's do a quick check for the same password */
239 if (memcmp(pw, ibuf + PASSWDLEN, PASSWDLEN) == 0)
240 return AFPERR_PWDSAME;
242 /* Set these things up for the conv function */
243 PAM_username = username;
246 PAM_error = pam_start("netatalk", username, &PAM_conversation,
248 if (PAM_error != PAM_SUCCESS)
250 pam_set_item(lpamh, PAM_TTY, "afpd");
251 pam_set_item(lpamh, PAM_RHOST, hostname);
253 /* we might need to do this as root */
256 PAM_error = pam_authenticate(lpamh,0);
257 if (PAM_error != PAM_SUCCESS) {
259 pam_end(lpamh, PAM_error);
260 return AFPERR_NOTAUTH;
266 ibuf[PASSWDLEN] = '\0';
268 /* this really does need to be done as root */
269 PAM_error = pam_chauthtok(lpamh, 0);
270 seteuid(uid); /* un-root ourselves. */
271 memset(pw, 0, PASSWDLEN);
272 memset(ibuf, 0, PASSWDLEN);
273 if (PAM_error != PAM_SUCCESS) {
274 pam_end(lpamh, PAM_error);
275 return AFPERR_ACCESS;
283 /* Printer ClearTxtUAM login */
284 int pam_printer(start, stop, username, out)
285 char *start, *stop, *username;
290 char password[PASSWDLEN + 1] = "\0";
291 static const char *loginok = "0\r";
293 data = (char *)malloc(stop - start + 1);
294 strncpy(data, start, stop - start + 1);
296 /* We are looking for the following format in data:
297 * (username) (password)
299 * Let's hope username doesn't contain ") ("!
302 /* Parse input for username in () */
303 if ((p = strchr(data, '(' )) == NULL) {
304 syslog(LOG_INFO,"Bad Login ClearTxtUAM: username not found in string");
309 if ((q = strstr(data, ") (" )) == NULL) {
310 syslog(LOG_INFO,"Bad Login ClearTxtUAM: username not found in string");
314 strncpy(username, p, q - p);
316 /* Parse input for password in next () */
318 if ((q = strrchr(data, ')' )) == NULL) {
319 syslog(LOG_INFO,"Bad Login ClearTxtUAM: password not found in string");
323 strncpy(password, p, q - p);
325 /* Done copying username and password, clean up */
328 PAM_username = username;
329 PAM_password = password;
331 PAM_error = pam_start("netatalk", username, &PAM_conversation,
333 if (PAM_error != PAM_SUCCESS) {
334 syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s",
335 username, pam_strerror(pamh, PAM_error));
336 pam_end(pamh, PAM_error);
341 pam_set_item(pamh, PAM_TTY, "papd");
342 pam_set_item(pamh, PAM_RHOST, hostname);
343 PAM_error = pam_authenticate(pamh,0);
344 if (PAM_error != PAM_SUCCESS) {
345 syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s",
346 username, pam_strerror(pamh, PAM_error));
347 pam_end(pamh, PAM_error);
352 PAM_error = pam_acct_mgmt(pamh, 0);
353 if (PAM_error != PAM_SUCCESS) {
354 syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s",
355 username, pam_strerror(pamh, PAM_error));
356 pam_end(pamh, PAM_error);
361 PAM_error = pam_open_session(pamh, 0);
362 if (PAM_error != PAM_SUCCESS) {
363 syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s",
364 username, pam_strerror(pamh, PAM_error));
365 pam_end(pamh, PAM_error);
370 /* Login successful, but no need to hang onto it,
371 so logout immediately */
372 append(out, loginok, strlen(loginok));
373 syslog(LOG_INFO, "Login ClearTxtUAM: %s", username);
374 pam_close_session(pamh, 0);
382 static int uam_setup(const char *path)
384 if (uam_register(UAM_SERVER_LOGIN, path, "Cleartxt Passwrd",
385 pam_login, NULL, pam_logout) < 0)
388 if (uam_register(UAM_SERVER_CHANGEPW, path, "Cleartxt Passwrd",
390 uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
394 if (uam_register(UAM_SERVER_PRINTAUTH, path, "ClearTxtUAM",
402 static void uam_cleanup(void)
404 uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
405 uam_unregister(UAM_SERVER_CHANGEPW, "Cleartxt Passwrd");
406 uam_unregister(UAM_SERVER_PRINTAUTH, "ClearTxtUAM");
409 UAM_MODULE_EXPORT struct uam_export uams_clrtxt = {
412 uam_setup, uam_cleanup