2 * $Id: uams_pam.c,v 1.10 2001-11-13 15:01:38 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 */
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_CLIENTNAME,
144 (void *) &hostname, NULL) < 0)
146 syslog(LOG_INFO, "uams_pam.c :PAM: unable to retrieve client hostname");
151 len = (unsigned char) *ibuf++;
153 return( AFPERR_PARAM );
156 memcpy(username, ibuf, len );
158 username[ len ] = '\0';
159 if ((unsigned long) ibuf & 1) /* pad character */
161 ibuf[ PASSWDLEN ] = '\0';
163 if (( pwd = uam_getname(username, ulen)) == NULL ) {
167 syslog(LOG_INFO, "cleartext login: %s", username);
168 PAM_username = username;
169 PAM_password = ibuf; /* Set these things up for the conv function */
171 err = AFPERR_NOTAUTH;
172 PAM_error = pam_start("netatalk", username, &PAM_conversation,
174 if (PAM_error != PAM_SUCCESS)
177 pam_set_item(pamh, PAM_TTY, "afpd");
178 pam_set_item(pamh, PAM_RHOST, hostname);
179 /* use PAM_DISALLOW_NULL_AUTHTOK if passwdminlen > 0 */
180 PAM_error = pam_authenticate(pamh,0);
181 if (PAM_error != PAM_SUCCESS) {
182 if (PAM_error == PAM_MAXTRIES)
183 err = AFPERR_PWDEXPR;
187 PAM_error = pam_acct_mgmt(pamh, 0);
188 if (PAM_error != PAM_SUCCESS) {
189 if (PAM_error == PAM_ACCT_EXPIRED)
190 err = AFPERR_PWDEXPR;
191 #ifdef PAM_AUTHTOKEN_REQD
192 else if (PAM_error == PAM_AUTHTOKEN_REQD)
193 err = AFPERR_PWDCHNG;
194 #endif /* PAM_AUTHTOKEN_REQD */
198 #ifndef PAM_CRED_ESTABLISH
199 #define PAM_CRED_ESTABLISH PAM_ESTABLISH_CRED
200 #endif /* PAM_CRED_ESTABLISH */
201 PAM_error = pam_setcred(pamh, PAM_CRED_ESTABLISH);
202 if (PAM_error != PAM_SUCCESS)
205 PAM_error = pam_open_session(pamh, 0);
206 if (PAM_error != PAM_SUCCESS)
213 pam_end(pamh, PAM_error);
219 static void pam_logout() {
220 pam_close_session(pamh, 0);
226 static int pam_changepw(void *obj, char *username,
227 struct passwd *pwd, char *ibuf, int ibuflen,
228 char *rbuf, int *rbuflen)
230 char pw[PASSWDLEN + 1];
236 memcpy(pw, ibuf, PASSWDLEN);
237 memset(ibuf, 0, PASSWDLEN);
238 pw[PASSWDLEN] = '\0';
240 /* let's do a quick check for the same password */
241 if (memcmp(pw, ibuf + PASSWDLEN, PASSWDLEN) == 0)
242 return AFPERR_PWDSAME;
244 /* Set these things up for the conv function */
245 PAM_username = username;
248 PAM_error = pam_start("netatalk", username, &PAM_conversation,
250 if (PAM_error != PAM_SUCCESS)
252 pam_set_item(lpamh, PAM_TTY, "afpd");
253 pam_set_item(lpamh, PAM_RHOST, hostname);
255 /* we might need to do this as root */
258 PAM_error = pam_authenticate(lpamh,0);
259 if (PAM_error != PAM_SUCCESS) {
261 pam_end(lpamh, PAM_error);
262 return AFPERR_NOTAUTH;
268 ibuf[PASSWDLEN] = '\0';
270 /* this really does need to be done as root */
271 PAM_error = pam_chauthtok(lpamh, 0);
272 seteuid(uid); /* un-root ourselves. */
273 memset(pw, 0, PASSWDLEN);
274 memset(ibuf, 0, PASSWDLEN);
275 if (PAM_error != PAM_SUCCESS) {
276 pam_end(lpamh, PAM_error);
277 return AFPERR_ACCESS;
285 /* Printer ClearTxtUAM login */
286 int pam_printer(start, stop, username, out)
287 char *start, *stop, *username;
292 char password[PASSWDLEN + 1] = "\0";
293 static const char *loginok = "0\r";
295 data = (char *)malloc(stop - start + 1);
296 strncpy(data, start, stop - start + 1);
298 /* We are looking for the following format in data:
299 * (username) (password)
301 * Let's hope username doesn't contain ") ("!
304 /* Parse input for username in () */
305 if ((p = strchr(data, '(' )) == NULL) {
306 syslog(LOG_INFO,"Bad Login ClearTxtUAM: username not found in string");
311 if ((q = strstr(data, ") (" )) == NULL) {
312 syslog(LOG_INFO,"Bad Login ClearTxtUAM: username not found in string");
316 strncpy(username, p, q - p);
318 /* Parse input for password in next () */
320 if ((q = strrchr(data, ')' )) == NULL) {
321 syslog(LOG_INFO,"Bad Login ClearTxtUAM: password not found in string");
325 strncpy(password, p, q - p);
327 /* Done copying username and password, clean up */
330 PAM_username = username;
331 PAM_password = password;
333 PAM_error = pam_start("netatalk", username, &PAM_conversation,
335 if (PAM_error != PAM_SUCCESS) {
336 syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s",
337 username, pam_strerror(pamh, PAM_error));
338 pam_end(pamh, PAM_error);
343 pam_set_item(pamh, PAM_TTY, "papd");
344 pam_set_item(pamh, PAM_RHOST, hostname);
345 PAM_error = pam_authenticate(pamh,0);
346 if (PAM_error != PAM_SUCCESS) {
347 syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s",
348 username, pam_strerror(pamh, PAM_error));
349 pam_end(pamh, PAM_error);
354 PAM_error = pam_acct_mgmt(pamh, 0);
355 if (PAM_error != PAM_SUCCESS) {
356 syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s",
357 username, pam_strerror(pamh, PAM_error));
358 pam_end(pamh, PAM_error);
363 PAM_error = pam_open_session(pamh, 0);
364 if (PAM_error != PAM_SUCCESS) {
365 syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s",
366 username, pam_strerror(pamh, PAM_error));
367 pam_end(pamh, PAM_error);
372 /* Login successful, but no need to hang onto it,
373 so logout immediately */
374 append(out, loginok, strlen(loginok));
375 syslog(LOG_INFO, "Login ClearTxtUAM: %s", username);
376 pam_close_session(pamh, 0);
384 static int uam_setup(const char *path)
386 if (uam_register(UAM_SERVER_LOGIN, path, "Cleartxt Passwrd",
387 pam_login, NULL, pam_logout) < 0)
390 if (uam_register(UAM_SERVER_CHANGEPW, path, "Cleartxt Passwrd",
392 uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
396 if (uam_register(UAM_SERVER_PRINTAUTH, path, "ClearTxtUAM",
404 static void uam_cleanup(void)
406 uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
407 uam_unregister(UAM_SERVER_CHANGEPW, "Cleartxt Passwrd");
408 uam_unregister(UAM_SERVER_PRINTAUTH, "ClearTxtUAM");
411 UAM_MODULE_EXPORT struct uam_export uams_clrtxt = {
414 uam_setup, uam_cleanup
417 UAM_MODULE_EXPORT struct uam_export uams_pam = {
420 uam_setup, uam_cleanup