]> arthur.barton.de Git - netatalk.git/blob - etc/uams/uams_pam.c
Identify modules as uams_pam as well as uams_clrtxt.
[netatalk.git] / etc / uams / uams_pam.c
1 /*
2  * $Id: uams_pam.c,v 1.9 2001-11-10 18:30:21 srittau Exp $
3  *
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.
7  */
8
9 #ifdef HAVE_CONFIG_H
10 #include "config.h"
11 #endif /* HAVE_CONFIG_H */
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #ifdef HAVE_UNISTD_H
16 #include <unistd.h>
17 #endif /* HAVE_UNISTD_H */
18
19 /* STDC check */
20 #if STDC_HEADERS
21 #include <string.h>
22 #else /* STDC_HEADERS */
23 #ifndef HAVE_STRCHR
24 #define strchr index
25 #define strrchr index
26 #endif /* HAVE_STRCHR */
27 char *strchr (), *strrchr ();
28 #ifndef HAVE_MEMCPY
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 */
33
34 #include <syslog.h>
35
36 #include <security/pam_appl.h>
37
38 #include <atalk/afp.h>
39 #include <atalk/uam.h>
40
41 #define PASSWDLEN 8
42
43 /* Static variables used to communicate between the conversation function
44  * and the server_login function
45  */
46 static pam_handle_t *pamh = NULL; 
47 static char *hostname;
48 static char *PAM_username;
49 static char *PAM_password;
50
51 /* PAM conversation function
52  * Here we assume (for now, at least) that echo on means login name, and
53  * echo off means password.
54  */
55 static int PAM_conv (int num_msg,
56                      const struct pam_message **msg,
57                      struct pam_response **resp,
58                      void *appdata_ptr) 
59 {
60   struct pam_response *reply;
61   int count;
62   
63 #define COPY_STRING(s) (s) ? strdup(s) : NULL
64   
65   if (num_msg < 1)
66     return PAM_CONV_ERR;
67
68   reply = (struct pam_response *) 
69     calloc(num_msg, sizeof(struct pam_response));
70
71   if (!reply)
72     return PAM_CONV_ERR;
73
74   for (count = 0; count < num_msg; count++) {
75     char *string = NULL;
76
77     switch (msg[count]->msg_style) {
78     case PAM_PROMPT_ECHO_ON:
79       if (!(string = COPY_STRING(PAM_username)))
80         goto pam_fail_conv;
81       break;
82     case PAM_PROMPT_ECHO_OFF:
83       if (!(string = COPY_STRING(PAM_password)))
84         goto pam_fail_conv;
85       break;
86     case PAM_TEXT_INFO:
87 #ifdef PAM_BINARY_PROMPT
88     case PAM_BINARY_PROMPT:
89 #endif /* PAM_BINARY_PROMPT */
90       /* ignore it... */
91       break;
92     case PAM_ERROR_MSG:
93     default:
94       goto pam_fail_conv;
95     }
96
97     if (string) {  
98       reply[count].resp_retcode = 0;
99       reply[count].resp = string;
100       string = NULL;
101     }
102   }
103
104   *resp = reply;
105   return PAM_SUCCESS;
106
107 pam_fail_conv:
108   for (count = 0; count < num_msg; count++) {
109     if (!reply[count].resp)
110       continue;
111     switch (msg[count]->msg_style) {
112     case PAM_PROMPT_ECHO_OFF:
113     case PAM_PROMPT_ECHO_ON:
114       free(reply[count].resp);
115       break;      
116     }
117   }
118   free(reply);
119   return PAM_CONV_ERR;
120 }
121
122 static struct pam_conv PAM_conversation = {
123   &PAM_conv,
124   NULL
125 };
126
127
128 /* cleartxt login */
129 static int pam_login(void *obj, struct passwd **uam_pwd,
130                      char *ibuf, int ibuflen,
131                      char *rbuf, int *rbuflen)
132 {
133     struct passwd *pwd;
134     char *username; 
135     int err, len, ulen, PAM_error;
136
137     *rbuflen = 0;
138
139     if (uam_afpserver_option(obj, UAM_OPTION_USERNAME,
140                              (void *) &username, &ulen) < 0)
141       return AFPERR_MISC;
142
143     if (uam_afpserver_option(obj, UAM_OPTION_HOSTNAME,
144                              (void *) &hostname, NULL) < 0)
145       return AFPERR_MISC;
146
147     len = (unsigned char) *ibuf++;
148     if ( len > ulen ) {
149         return( AFPERR_PARAM );
150     }
151
152     memcpy(username, ibuf, len );
153     ibuf += len;
154     username[ len ] = '\0';
155     if ((unsigned long) ibuf & 1)  /* pad character */
156       ++ibuf;
157     ibuf[ PASSWDLEN ] = '\0';
158
159     if (( pwd = uam_getname(username, ulen)) == NULL ) {
160         return AFPERR_PARAM;
161     }
162
163     syslog(LOG_INFO, "cleartext login: %s", username);
164     PAM_username = username;
165     PAM_password = ibuf; /* Set these things up for the conv function */
166
167     err = AFPERR_NOTAUTH;
168     PAM_error = pam_start("netatalk", username, &PAM_conversation,
169                           &pamh);
170     if (PAM_error != PAM_SUCCESS)
171       goto login_err;
172
173     pam_set_item(pamh, PAM_TTY, "afpd");
174     pam_set_item(pamh, PAM_RHOST, hostname);
175     /* use PAM_DISALLOW_NULL_AUTHTOK if passwdminlen > 0 */
176     PAM_error = pam_authenticate(pamh,0);
177     if (PAM_error != PAM_SUCCESS) {
178       if (PAM_error == PAM_MAXTRIES) 
179         err = AFPERR_PWDEXPR;
180       goto login_err;
181     }      
182
183     PAM_error = pam_acct_mgmt(pamh, 0);
184     if (PAM_error != PAM_SUCCESS) {
185       if (PAM_error == PAM_ACCT_EXPIRED)
186         err = AFPERR_PWDEXPR;
187 #ifdef PAM_AUTHTOKEN_REQD
188       else if (PAM_error == PAM_AUTHTOKEN_REQD) 
189         err = AFPERR_PWDCHNG;
190 #endif /* PAM_AUTHTOKEN_REQD */
191       goto login_err;
192     }
193
194 #ifndef PAM_CRED_ESTABLISH
195 #define PAM_CRED_ESTABLISH PAM_ESTABLISH_CRED
196 #endif /* PAM_CRED_ESTABLISH */
197     PAM_error = pam_setcred(pamh, PAM_CRED_ESTABLISH);
198     if (PAM_error != PAM_SUCCESS)
199       goto login_err;
200
201     PAM_error = pam_open_session(pamh, 0);
202     if (PAM_error != PAM_SUCCESS)
203       goto login_err;
204
205     *uam_pwd = pwd;
206     return AFP_OK;
207
208 login_err:
209     pam_end(pamh, PAM_error);
210     pamh = NULL;
211     return err;
212 }
213
214 /* logout */
215 static void pam_logout() {
216     pam_close_session(pamh, 0);
217     pam_end(pamh, 0);
218     pamh = NULL;
219 }
220
221 /* change passwd */
222 static int pam_changepw(void *obj, char *username,
223                         struct passwd *pwd, char *ibuf, int ibuflen,
224                         char *rbuf, int *rbuflen)
225 {
226     char pw[PASSWDLEN + 1];
227     pam_handle_t *lpamh;
228     uid_t uid;
229     int PAM_error;
230
231     /* old password */
232     memcpy(pw, ibuf, PASSWDLEN);
233     memset(ibuf, 0, PASSWDLEN);
234     pw[PASSWDLEN] = '\0';
235
236     /* let's do a quick check for the same password */
237     if (memcmp(pw, ibuf + PASSWDLEN, PASSWDLEN) == 0)
238       return AFPERR_PWDSAME;
239
240     /* Set these things up for the conv function */
241     PAM_username = username;
242     PAM_password = pw; 
243
244     PAM_error = pam_start("netatalk", username, &PAM_conversation,
245                           &lpamh);
246     if (PAM_error != PAM_SUCCESS) 
247       return AFPERR_PARAM;
248     pam_set_item(lpamh, PAM_TTY, "afpd");
249     pam_set_item(lpamh, PAM_RHOST, hostname);
250
251     /* we might need to do this as root */
252     uid = geteuid();
253     seteuid(0);
254     PAM_error = pam_authenticate(lpamh,0);
255     if (PAM_error != PAM_SUCCESS) {
256       seteuid(uid);
257       pam_end(lpamh, PAM_error);
258       return AFPERR_NOTAUTH;
259     }
260
261     /* new password */
262     ibuf += PASSWDLEN;
263     PAM_password = ibuf;
264     ibuf[PASSWDLEN] = '\0';
265     
266     /* this really does need to be done as root */
267     PAM_error = pam_chauthtok(lpamh, 0);
268     seteuid(uid); /* un-root ourselves. */
269     memset(pw, 0, PASSWDLEN);
270     memset(ibuf, 0, PASSWDLEN);
271     if (PAM_error != PAM_SUCCESS) {
272       pam_end(lpamh, PAM_error);
273       return AFPERR_ACCESS;
274     }
275
276     pam_end(lpamh, 0);
277     return AFP_OK;
278 }
279
280
281 /* Printer ClearTxtUAM login */
282 int pam_printer(start, stop, username, out)
283         char    *start, *stop, *username;
284         struct papfile  *out;
285 {
286     int PAM_error;
287     char        *data, *p, *q;
288     char        password[PASSWDLEN + 1] = "\0";
289     static const char *loginok = "0\r";
290
291     data = (char *)malloc(stop - start + 1);
292     strncpy(data, start, stop - start + 1);
293
294     /* We are looking for the following format in data:
295      * (username) (password)
296      *
297      * Let's hope username doesn't contain ") ("!
298      */
299
300     /* Parse input for username in () */
301     if ((p = strchr(data, '(' )) == NULL) {
302         syslog(LOG_INFO,"Bad Login ClearTxtUAM: username not found in string");
303         free(data);
304         return(-1);
305     }
306     p++;
307     if ((q = strstr(data, ") (" )) == NULL) {
308         syslog(LOG_INFO,"Bad Login ClearTxtUAM: username not found in string");
309         free(data);
310         return(-1);
311     }
312     strncpy(username, p, q - p);
313
314     /* Parse input for password in next () */
315     p = q + 3;
316     if ((q = strrchr(data, ')' )) == NULL) {
317         syslog(LOG_INFO,"Bad Login ClearTxtUAM: password not found in string");
318         free(data);
319         return(-1);
320     }
321     strncpy(password, p, q - p);
322
323     /* Done copying username and password, clean up */
324     free(data);
325
326     PAM_username = username;
327     PAM_password = password;
328
329     PAM_error = pam_start("netatalk", username, &PAM_conversation,
330                           &pamh);
331     if (PAM_error != PAM_SUCCESS) {
332         syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s", 
333                         username, pam_strerror(pamh, PAM_error));
334         pam_end(pamh, PAM_error);
335         pamh = NULL;
336         return(-1);
337     }
338
339     pam_set_item(pamh, PAM_TTY, "papd");
340     pam_set_item(pamh, PAM_RHOST, hostname);
341     PAM_error = pam_authenticate(pamh,0);
342     if (PAM_error != PAM_SUCCESS) {
343         syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s", 
344                         username, pam_strerror(pamh, PAM_error));
345         pam_end(pamh, PAM_error);
346         pamh = NULL;
347         return(-1);
348     }      
349
350     PAM_error = pam_acct_mgmt(pamh, 0);
351     if (PAM_error != PAM_SUCCESS) {
352         syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s", 
353                         username, pam_strerror(pamh, PAM_error));
354         pam_end(pamh, PAM_error);
355         pamh = NULL;
356         return(-1);
357     }
358
359     PAM_error = pam_open_session(pamh, 0);
360     if (PAM_error != PAM_SUCCESS) {
361         syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s", 
362                         username, pam_strerror(pamh, PAM_error));
363         pam_end(pamh, PAM_error);
364         pamh = NULL;
365         return(-1);
366     }
367
368     /* Login successful, but no need to hang onto it,
369        so logout immediately */
370     append(out, loginok, strlen(loginok));
371     syslog(LOG_INFO, "Login ClearTxtUAM: %s", username);
372     pam_close_session(pamh, 0);
373     pam_end(pamh, 0);
374     pamh = NULL;
375
376     return(0);
377 }
378
379
380 static int uam_setup(const char *path)
381 {
382   if (uam_register(UAM_SERVER_LOGIN, path, "Cleartxt Passwrd", 
383                    pam_login, NULL, pam_logout) < 0)
384         return -1;
385
386   if (uam_register(UAM_SERVER_CHANGEPW, path, "Cleartxt Passwrd",
387                    pam_changepw) < 0) {
388         uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
389         return -1;
390   }
391
392   if (uam_register(UAM_SERVER_PRINTAUTH, path, "ClearTxtUAM",
393                    pam_printer) < 0) {
394         return -1;
395   }
396
397   return 0;
398 }
399
400 static void uam_cleanup(void)
401 {
402   uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
403   uam_unregister(UAM_SERVER_CHANGEPW, "Cleartxt Passwrd");
404   uam_unregister(UAM_SERVER_PRINTAUTH, "ClearTxtUAM");
405 }
406
407 UAM_MODULE_EXPORT struct uam_export uams_clrtxt = {
408   UAM_MODULE_SERVER,
409   UAM_MODULE_VERSION,
410   uam_setup, uam_cleanup
411 };
412
413 UAM_MODULE_EXPORT struct uam_export uams_pam = {
414   UAM_MODULE_SERVER,
415   UAM_MODULE_VERSION,
416   uam_setup, uam_cleanup
417 };