2 * $Id: uams_pam.c,v 1.7 2001-06-25 20:13:45 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 */
23 #include <security/pam_appl.h>
25 #include <atalk/afp.h>
26 #include <atalk/uam.h>
30 /* Static variables used to communicate between the conversation function
31 * and the server_login function
33 static pam_handle_t *pamh = NULL;
34 static char *hostname;
35 static char *PAM_username;
36 static char *PAM_password;
38 /* PAM conversation function
39 * Here we assume (for now, at least) that echo on means login name, and
40 * echo off means password.
42 static int PAM_conv (int num_msg,
43 const struct pam_message **msg,
44 struct pam_response **resp,
47 struct pam_response *reply;
50 #define COPY_STRING(s) (s) ? strdup(s) : NULL
55 reply = (struct pam_response *)
56 calloc(num_msg, sizeof(struct pam_response));
61 for (count = 0; count < num_msg; count++) {
64 switch (msg[count]->msg_style) {
65 case PAM_PROMPT_ECHO_ON:
66 if (!(string = COPY_STRING(PAM_username)))
69 case PAM_PROMPT_ECHO_OFF:
70 if (!(string = COPY_STRING(PAM_password)))
74 #ifdef PAM_BINARY_PROMPT
75 case PAM_BINARY_PROMPT:
76 #endif /* PAM_BINARY_PROMPT */
85 reply[count].resp_retcode = 0;
86 reply[count].resp = string;
95 for (count = 0; count < num_msg; count++) {
96 if (!reply[count].resp)
98 switch (msg[count]->msg_style) {
99 case PAM_PROMPT_ECHO_OFF:
100 case PAM_PROMPT_ECHO_ON:
101 free(reply[count].resp);
109 static struct pam_conv PAM_conversation = {
116 static int pam_login(void *obj, struct passwd **uam_pwd,
117 char *ibuf, int ibuflen,
118 char *rbuf, int *rbuflen)
122 int err, len, ulen, PAM_error;
126 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME,
127 (void *) &username, &ulen) < 0)
130 if (uam_afpserver_option(obj, UAM_OPTION_HOSTNAME,
131 (void *) &hostname, NULL) < 0)
134 len = (unsigned char) *ibuf++;
136 return( AFPERR_PARAM );
139 memcpy(username, ibuf, len );
141 username[ len ] = '\0';
142 if ((unsigned long) ibuf & 1) /* pad character */
144 ibuf[ PASSWDLEN ] = '\0';
146 if (( pwd = uam_getname(username, ulen)) == NULL ) {
150 syslog(LOG_INFO, "cleartext login: %s", username);
151 PAM_username = username;
152 PAM_password = ibuf; /* Set these things up for the conv function */
154 err = AFPERR_NOTAUTH;
155 PAM_error = pam_start("netatalk", username, &PAM_conversation,
157 if (PAM_error != PAM_SUCCESS)
160 pam_set_item(pamh, PAM_TTY, "afpd");
161 pam_set_item(pamh, PAM_RHOST, hostname);
162 /* use PAM_DISALLOW_NULL_AUTHTOK if passwdminlen > 0 */
163 PAM_error = pam_authenticate(pamh,0);
164 if (PAM_error != PAM_SUCCESS) {
165 if (PAM_error == PAM_MAXTRIES)
166 err = AFPERR_PWDEXPR;
170 PAM_error = pam_acct_mgmt(pamh, 0);
171 if (PAM_error != PAM_SUCCESS) {
172 if (PAM_error == PAM_ACCT_EXPIRED)
173 err = AFPERR_PWDEXPR;
174 #ifdef PAM_AUTHTOKEN_REQD
175 else if (PAM_error == PAM_AUTHTOKEN_REQD)
176 err = AFPERR_PWDCHNG;
177 #endif /* PAM_AUTHTOKEN_REQD */
181 #ifndef PAM_CRED_ESTABLISH
182 #define PAM_CRED_ESTABLISH PAM_ESTABLISH_CRED
183 #endif /* PAM_CRED_ESTABLISH */
184 PAM_error = pam_setcred(pamh, PAM_CRED_ESTABLISH);
185 if (PAM_error != PAM_SUCCESS)
188 PAM_error = pam_open_session(pamh, 0);
189 if (PAM_error != PAM_SUCCESS)
196 pam_end(pamh, PAM_error);
202 static void pam_logout() {
203 pam_close_session(pamh, 0);
209 static int pam_changepw(void *obj, char *username,
210 struct passwd *pwd, char *ibuf, int ibuflen,
211 char *rbuf, int *rbuflen)
213 char pw[PASSWDLEN + 1];
219 memcpy(pw, ibuf, PASSWDLEN);
220 memset(ibuf, 0, PASSWDLEN);
221 pw[PASSWDLEN] = '\0';
223 /* let's do a quick check for the same password */
224 if (memcmp(pw, ibuf + PASSWDLEN, PASSWDLEN) == 0)
225 return AFPERR_PWDSAME;
227 /* Set these things up for the conv function */
228 PAM_username = username;
231 PAM_error = pam_start("netatalk", username, &PAM_conversation,
233 if (PAM_error != PAM_SUCCESS)
235 pam_set_item(lpamh, PAM_TTY, "afpd");
236 pam_set_item(lpamh, PAM_RHOST, hostname);
238 /* we might need to do this as root */
241 PAM_error = pam_authenticate(lpamh,0);
242 if (PAM_error != PAM_SUCCESS) {
244 pam_end(lpamh, PAM_error);
245 return AFPERR_NOTAUTH;
251 ibuf[PASSWDLEN] = '\0';
253 /* this really does need to be done as root */
254 PAM_error = pam_chauthtok(lpamh, 0);
255 seteuid(uid); /* un-root ourselves. */
256 memset(pw, 0, PASSWDLEN);
257 memset(ibuf, 0, PASSWDLEN);
258 if (PAM_error != PAM_SUCCESS) {
259 pam_end(lpamh, PAM_error);
260 return AFPERR_ACCESS;
268 /* Printer ClearTxtUAM login */
269 int pam_printer(start, stop, username, out)
270 char *start, *stop, *username;
275 char password[PASSWDLEN + 1] = "\0";
276 static const char *loginok = "0\r";
278 data = (char *)malloc(stop - start + 1);
279 strncpy(data, start, stop - start + 1);
281 /* We are looking for the following format in data:
282 * (username) (password)
284 * Let's hope username doesn't contain ") ("!
287 /* Parse input for username in () */
288 if ((p = strchr(data, '(' )) == NULL) {
289 syslog(LOG_INFO,"Bad Login ClearTxtUAM: username not found in string");
294 if ((q = strstr(data, ") (" )) == NULL) {
295 syslog(LOG_INFO,"Bad Login ClearTxtUAM: username not found in string");
299 strncpy(username, p, q - p);
301 /* Parse input for password in next () */
303 if ((q = strrchr(data, ')' )) == NULL) {
304 syslog(LOG_INFO,"Bad Login ClearTxtUAM: password not found in string");
308 strncpy(password, p, q - p);
310 /* Done copying username and password, clean up */
313 PAM_username = username;
314 PAM_password = password;
316 PAM_error = pam_start("netatalk", username, &PAM_conversation,
318 if (PAM_error != PAM_SUCCESS) {
319 syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s",
320 username, pam_strerror(pamh, PAM_error));
321 pam_end(pamh, PAM_error);
326 pam_set_item(pamh, PAM_TTY, "papd");
327 pam_set_item(pamh, PAM_RHOST, hostname);
328 PAM_error = pam_authenticate(pamh,0);
329 if (PAM_error != PAM_SUCCESS) {
330 syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s",
331 username, pam_strerror(pamh, PAM_error));
332 pam_end(pamh, PAM_error);
337 PAM_error = pam_acct_mgmt(pamh, 0);
338 if (PAM_error != PAM_SUCCESS) {
339 syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s",
340 username, pam_strerror(pamh, PAM_error));
341 pam_end(pamh, PAM_error);
346 PAM_error = pam_open_session(pamh, 0);
347 if (PAM_error != PAM_SUCCESS) {
348 syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s",
349 username, pam_strerror(pamh, PAM_error));
350 pam_end(pamh, PAM_error);
355 /* Login successful, but no need to hang onto it,
356 so logout immediately */
357 append(out, loginok, strlen(loginok));
358 syslog(LOG_INFO, "Login ClearTxtUAM: %s", username);
359 pam_close_session(pamh, 0);
367 static int uam_setup(const char *path)
369 if (uam_register(UAM_SERVER_LOGIN, path, "Cleartxt Passwrd",
370 pam_login, NULL, pam_logout) < 0)
373 if (uam_register(UAM_SERVER_CHANGEPW, path, "Cleartxt Passwrd",
375 uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
379 if (uam_register(UAM_SERVER_PRINTAUTH, path, "ClearTxtUAM",
387 static void uam_cleanup(void)
389 uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
390 uam_unregister(UAM_SERVER_CHANGEPW, "Cleartxt Passwrd");
391 uam_unregister(UAM_SERVER_PRINTAUTH, "ClearTxtUAM");
394 UAM_MODULE_EXPORT struct uam_export uams_clrtxt = {
397 uam_setup, uam_cleanup