2 * $Id: uams_pam.c,v 1.6 2001-02-27 17:07:43 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.
20 #include <security/pam_appl.h>
22 #include <atalk/afp.h>
23 #include <atalk/uam.h>
27 /* Static variables used to communicate between the conversation function
28 * and the server_login function
30 static pam_handle_t *pamh = NULL;
31 static char *hostname;
32 static char *PAM_username;
33 static char *PAM_password;
35 /* PAM conversation function
36 * Here we assume (for now, at least) that echo on means login name, and
37 * echo off means password.
39 static int PAM_conv (int num_msg,
40 const struct pam_message **msg,
41 struct pam_response **resp,
44 struct pam_response *reply;
47 #define COPY_STRING(s) (s) ? strdup(s) : NULL
52 reply = (struct pam_response *)
53 calloc(num_msg, sizeof(struct pam_response));
58 for (count = 0; count < num_msg; count++) {
61 switch (msg[count]->msg_style) {
62 case PAM_PROMPT_ECHO_ON:
63 if (!(string = COPY_STRING(PAM_username)))
66 case PAM_PROMPT_ECHO_OFF:
67 if (!(string = COPY_STRING(PAM_password)))
71 #ifdef PAM_BINARY_PROMPT
72 case PAM_BINARY_PROMPT:
82 reply[count].resp_retcode = 0;
83 reply[count].resp = string;
92 for (count = 0; count < num_msg; count++) {
93 if (!reply[count].resp)
95 switch (msg[count]->msg_style) {
96 case PAM_PROMPT_ECHO_OFF:
97 case PAM_PROMPT_ECHO_ON:
98 free(reply[count].resp);
106 static struct pam_conv PAM_conversation = {
113 static int pam_login(void *obj, struct passwd **uam_pwd,
114 char *ibuf, int ibuflen,
115 char *rbuf, int *rbuflen)
119 int err, len, ulen, PAM_error;
123 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME,
124 (void *) &username, &ulen) < 0)
127 if (uam_afpserver_option(obj, UAM_OPTION_HOSTNAME,
128 (void *) &hostname, NULL) < 0)
131 len = (unsigned char) *ibuf++;
133 return( AFPERR_PARAM );
136 memcpy(username, ibuf, len );
138 username[ len ] = '\0';
139 if ((unsigned long) ibuf & 1) /* pad character */
141 ibuf[ PASSWDLEN ] = '\0';
143 if (( pwd = uam_getname(username, ulen)) == NULL ) {
147 syslog(LOG_INFO, "cleartext login: %s", username);
148 PAM_username = username;
149 PAM_password = ibuf; /* Set these things up for the conv function */
151 err = AFPERR_NOTAUTH;
152 PAM_error = pam_start("netatalk", username, &PAM_conversation,
154 if (PAM_error != PAM_SUCCESS)
157 pam_set_item(pamh, PAM_TTY, "afpd");
158 pam_set_item(pamh, PAM_RHOST, hostname);
159 /* use PAM_DISALLOW_NULL_AUTHTOK if passwdminlen > 0 */
160 PAM_error = pam_authenticate(pamh,0);
161 if (PAM_error != PAM_SUCCESS) {
162 if (PAM_error == PAM_MAXTRIES)
163 err = AFPERR_PWDEXPR;
167 PAM_error = pam_acct_mgmt(pamh, 0);
168 if (PAM_error != PAM_SUCCESS) {
169 if (PAM_error == PAM_ACCT_EXPIRED)
170 err = AFPERR_PWDEXPR;
171 #ifdef PAM_AUTHTOKEN_REQD
172 else if (PAM_error == PAM_AUTHTOKEN_REQD)
173 err = AFPERR_PWDCHNG;
178 #ifndef PAM_CRED_ESTABLISH
179 #define PAM_CRED_ESTABLISH PAM_ESTABLISH_CRED
181 PAM_error = pam_setcred(pamh, PAM_CRED_ESTABLISH);
182 if (PAM_error != PAM_SUCCESS)
185 PAM_error = pam_open_session(pamh, 0);
186 if (PAM_error != PAM_SUCCESS)
193 pam_end(pamh, PAM_error);
199 static void pam_logout() {
200 pam_close_session(pamh, 0);
206 static int pam_changepw(void *obj, char *username,
207 struct passwd *pwd, char *ibuf, int ibuflen,
208 char *rbuf, int *rbuflen)
210 char pw[PASSWDLEN + 1];
216 memcpy(pw, ibuf, PASSWDLEN);
217 memset(ibuf, 0, PASSWDLEN);
218 pw[PASSWDLEN] = '\0';
220 /* let's do a quick check for the same password */
221 if (memcmp(pw, ibuf + PASSWDLEN, PASSWDLEN) == 0)
222 return AFPERR_PWDSAME;
224 /* Set these things up for the conv function */
225 PAM_username = username;
228 PAM_error = pam_start("netatalk", username, &PAM_conversation,
230 if (PAM_error != PAM_SUCCESS)
232 pam_set_item(lpamh, PAM_TTY, "afpd");
233 pam_set_item(lpamh, PAM_RHOST, hostname);
235 /* we might need to do this as root */
238 PAM_error = pam_authenticate(lpamh,0);
239 if (PAM_error != PAM_SUCCESS) {
241 pam_end(lpamh, PAM_error);
242 return AFPERR_NOTAUTH;
248 ibuf[PASSWDLEN] = '\0';
250 /* this really does need to be done as root */
251 PAM_error = pam_chauthtok(lpamh, 0);
252 seteuid(uid); /* un-root ourselves. */
253 memset(pw, 0, PASSWDLEN);
254 memset(ibuf, 0, PASSWDLEN);
255 if (PAM_error != PAM_SUCCESS) {
256 pam_end(lpamh, PAM_error);
257 return AFPERR_ACCESS;
265 /* Printer ClearTxtUAM login */
266 int pam_printer(start, stop, username, out)
267 char *start, *stop, *username;
272 char password[PASSWDLEN + 1] = "\0";
273 static const char *loginok = "0\r";
275 data = (char *)malloc(stop - start + 1);
276 strncpy(data, start, stop - start + 1);
278 /* We are looking for the following format in data:
279 * (username) (password)
281 * Let's hope username doesn't contain ") ("!
284 /* Parse input for username in () */
285 if ((p = strchr(data, '(' )) == NULL) {
286 syslog(LOG_INFO,"Bad Login ClearTxtUAM: username not found in string");
291 if ((q = strstr(data, ") (" )) == NULL) {
292 syslog(LOG_INFO,"Bad Login ClearTxtUAM: username not found in string");
296 strncpy(username, p, q - p);
298 /* Parse input for password in next () */
300 if ((q = strrchr(data, ')' )) == NULL) {
301 syslog(LOG_INFO,"Bad Login ClearTxtUAM: password not found in string");
305 strncpy(password, p, q - p);
307 /* Done copying username and password, clean up */
310 PAM_username = username;
311 PAM_password = password;
313 PAM_error = pam_start("netatalk", username, &PAM_conversation,
315 if (PAM_error != PAM_SUCCESS) {
316 syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s",
317 username, pam_strerror(pamh, PAM_error));
318 pam_end(pamh, PAM_error);
323 pam_set_item(pamh, PAM_TTY, "papd");
324 pam_set_item(pamh, PAM_RHOST, hostname);
325 PAM_error = pam_authenticate(pamh,0);
326 if (PAM_error != PAM_SUCCESS) {
327 syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s",
328 username, pam_strerror(pamh, PAM_error));
329 pam_end(pamh, PAM_error);
334 PAM_error = pam_acct_mgmt(pamh, 0);
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_error = pam_open_session(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 /* Login successful, but no need to hang onto it,
353 so logout immediately */
354 append(out, loginok, strlen(loginok));
355 syslog(LOG_INFO, "Login ClearTxtUAM: %s", username);
356 pam_close_session(pamh, 0);
364 static int uam_setup(const char *path)
366 if (uam_register(UAM_SERVER_LOGIN, path, "Cleartxt Passwrd",
367 pam_login, NULL, pam_logout) < 0)
370 if (uam_register(UAM_SERVER_CHANGEPW, path, "Cleartxt Passwrd",
372 uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
376 if (uam_register(UAM_SERVER_PRINTAUTH, path, "ClearTxtUAM",
384 static void uam_cleanup(void)
386 uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
387 uam_unregister(UAM_SERVER_CHANGEPW, "Cleartxt Passwrd");
388 uam_unregister(UAM_SERVER_PRINTAUTH, "ClearTxtUAM");
391 UAM_MODULE_EXPORT struct uam_export uams_clrtxt = {
394 uam_setup, uam_cleanup