2 * Copyright (c) 1990,1993 Regents of The University of Michigan.
3 * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu)
4 * All Rights Reserved. See COPYRIGHT.
13 #include <security/pam_appl.h>
15 #include <atalk/afp.h>
16 #include <atalk/uam.h>
20 /* Static variables used to communicate between the conversation function
21 * and the server_login function
23 static pam_handle_t *pamh = NULL;
24 static char *hostname;
25 static char *PAM_username;
26 static char *PAM_password;
28 /* PAM conversation function
29 * Here we assume (for now, at least) that echo on means login name, and
30 * echo off means password.
32 static int PAM_conv (int num_msg,
33 const struct pam_message **msg,
34 struct pam_response **resp,
37 struct pam_response *reply;
40 #define COPY_STRING(s) (s) ? strdup(s) : NULL
45 reply = (struct pam_response *)
46 calloc(num_msg, sizeof(struct pam_response));
51 for (count = 0; count < num_msg; count++) {
54 switch (msg[count]->msg_style) {
55 case PAM_PROMPT_ECHO_ON:
56 if (!(string = COPY_STRING(PAM_username)))
59 case PAM_PROMPT_ECHO_OFF:
60 if (!(string = COPY_STRING(PAM_password)))
64 #ifdef PAM_BINARY_PROMPT
65 case PAM_BINARY_PROMPT:
75 reply[count].resp_retcode = 0;
76 reply[count].resp = string;
85 for (count = 0; count < num_msg; count++) {
86 if (!reply[count].resp)
88 switch (msg[count]->msg_style) {
89 case PAM_PROMPT_ECHO_OFF:
90 case PAM_PROMPT_ECHO_ON:
91 free(reply[count].resp);
99 static struct pam_conv PAM_conversation = {
106 static int pam_login(void *obj, struct passwd **uam_pwd,
107 char *ibuf, int ibuflen,
108 char *rbuf, int *rbuflen)
112 int err, len, ulen, PAM_error;
116 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME,
117 (void *) &username, &ulen) < 0)
120 if (uam_afpserver_option(obj, UAM_OPTION_HOSTNAME,
121 (void *) &hostname, NULL) < 0)
124 len = (unsigned char) *ibuf++;
126 return( AFPERR_PARAM );
129 memcpy(username, ibuf, len );
131 username[ len ] = '\0';
132 if ((unsigned long) ibuf & 1) /* pad character */
134 ibuf[ PASSWDLEN ] = '\0';
136 if (( pwd = uam_getname(username, ulen)) == NULL ) {
140 syslog(LOG_INFO, "cleartext login: %s", username);
141 PAM_username = username;
142 PAM_password = ibuf; /* Set these things up for the conv function */
144 err = AFPERR_NOTAUTH;
145 PAM_error = pam_start("netatalk", username, &PAM_conversation,
147 if (PAM_error != PAM_SUCCESS)
150 pam_set_item(pamh, PAM_TTY, "afpd");
151 pam_set_item(pamh, PAM_RHOST, hostname);
152 /* use PAM_DISALLOW_NULL_AUTHTOK if passwdminlen > 0 */
153 PAM_error = pam_authenticate(pamh,0);
154 if (PAM_error != PAM_SUCCESS) {
155 if (PAM_error == PAM_MAXTRIES)
156 err = AFPERR_PWDEXPR;
160 PAM_error = pam_acct_mgmt(pamh, 0);
161 if (PAM_error != PAM_SUCCESS) {
162 if (PAM_error == PAM_ACCT_EXPIRED)
163 err = AFPERR_PWDEXPR;
164 #ifdef PAM_AUTHTOKEN_REQD
165 else if (PAM_error == PAM_AUTHTOKEN_REQD)
166 err = AFPERR_PWDCHNG;
171 #ifndef PAM_CRED_ESTABLISH
172 #define PAM_CRED_ESTABLISH PAM_ESTABLISH_CRED
174 PAM_error = pam_setcred(pamh, PAM_CRED_ESTABLISH);
175 if (PAM_error != PAM_SUCCESS)
178 PAM_error = pam_open_session(pamh, 0);
179 if (PAM_error != PAM_SUCCESS)
186 pam_end(pamh, PAM_error);
192 static void pam_logout() {
193 pam_close_session(pamh, 0);
199 static int pam_changepw(void *obj, char *username,
200 struct passwd *pwd, char *ibuf, int ibuflen,
201 char *rbuf, int *rbuflen)
203 char pw[PASSWDLEN + 1];
209 memcpy(pw, ibuf, PASSWDLEN);
210 memset(ibuf, 0, PASSWDLEN);
211 pw[PASSWDLEN] = '\0';
213 /* let's do a quick check for the same password */
214 if (memcmp(pw, ibuf + PASSWDLEN, PASSWDLEN) == 0)
215 return AFPERR_PWDSAME;
217 /* Set these things up for the conv function */
218 PAM_username = username;
221 PAM_error = pam_start("netatalk", username, &PAM_conversation,
223 if (PAM_error != PAM_SUCCESS)
225 pam_set_item(lpamh, PAM_TTY, "afpd");
226 pam_set_item(lpamh, PAM_RHOST, hostname);
228 /* we might need to do this as root */
231 PAM_error = pam_authenticate(lpamh,0);
232 if (PAM_error != PAM_SUCCESS) {
234 pam_end(lpamh, PAM_error);
235 return AFPERR_NOTAUTH;
241 ibuf[PASSWDLEN] = '\0';
243 /* this really does need to be done as root */
244 PAM_error = pam_chauthtok(lpamh, 0);
245 seteuid(uid); /* un-root ourselves. */
246 memset(pw, 0, PASSWDLEN);
247 memset(ibuf, 0, PASSWDLEN);
248 if (PAM_error != PAM_SUCCESS) {
249 pam_end(lpamh, PAM_error);
250 return AFPERR_ACCESS;
258 /* Printer ClearTxtUAM login */
259 int pam_printer(start, stop, username, out)
260 char *start, *stop, *username;
265 char password[PASSWDLEN + 1] = "\0";
266 static const char *loginok = "0\r";
268 data = (char *)malloc(stop - start + 1);
269 strncpy(data, start, stop - start + 1);
271 /* We are looking for the following format in data:
272 * (username) (password)
274 * Let's hope username doesn't contain ") ("!
277 /* Parse input for username in () */
278 if ((p = strchr(data, '(' )) == NULL) {
279 syslog(LOG_INFO,"Bad Login ClearTxtUAM: username not found in string");
284 if ((q = strstr(data, ") (" )) == NULL) {
285 syslog(LOG_INFO,"Bad Login ClearTxtUAM: username not found in string");
289 strncpy(username, p, q - p);
291 /* Parse input for password in next () */
293 if ((q = strrchr(data, ')' )) == NULL) {
294 syslog(LOG_INFO,"Bad Login ClearTxtUAM: password not found in string");
298 strncpy(password, p, q - p);
300 /* Done copying username and password, clean up */
303 PAM_username = username;
304 PAM_password = password;
306 PAM_error = pam_start("netatalk", username, &PAM_conversation,
308 if (PAM_error != PAM_SUCCESS) {
309 syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s",
310 username, pam_strerror(pamh, PAM_error));
311 pam_end(pamh, PAM_error);
316 pam_set_item(pamh, PAM_TTY, "papd");
317 pam_set_item(pamh, PAM_RHOST, hostname);
318 PAM_error = pam_authenticate(pamh,0);
319 if (PAM_error != PAM_SUCCESS) {
320 syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s",
321 username, pam_strerror(pamh, PAM_error));
322 pam_end(pamh, PAM_error);
327 PAM_error = pam_acct_mgmt(pamh, 0);
328 if (PAM_error != PAM_SUCCESS) {
329 syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s",
330 username, pam_strerror(pamh, PAM_error));
331 pam_end(pamh, PAM_error);
336 PAM_error = pam_open_session(pamh, 0);
337 if (PAM_error != PAM_SUCCESS) {
338 syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s",
339 username, pam_strerror(pamh, PAM_error));
340 pam_end(pamh, PAM_error);
345 /* Login successful, but no need to hang onto it,
346 so logout immediately */
347 append(out, loginok, strlen(loginok));
348 syslog(LOG_INFO, "Login ClearTxtUAM: %s", username);
349 pam_close_session(pamh, 0);
357 static int uam_setup(const char *path)
359 if (uam_register(UAM_SERVER_LOGIN, path, "Cleartxt Passwrd",
360 pam_login, NULL, pam_logout) < 0)
363 if (uam_register(UAM_SERVER_CHANGEPW, path, "Cleartxt Passwrd",
365 uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
369 if (uam_register(UAM_SERVER_PRINTAUTH, path, "ClearTxtUAM",
377 static void uam_cleanup(void)
379 uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
380 uam_unregister(UAM_SERVER_CHANGEPW, "Cleartxt Passwrd");
381 uam_unregister(UAM_SERVER_PRINTAUTH, "ClearTxtUAM");
384 UAM_MODULE_EXPORT struct uam_export uams_clrtxt = {
387 uam_setup, uam_cleanup