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