]> arthur.barton.de Git - netatalk.git/blob - etc/uams/uams_pam.c
AFP 3 fixes ofr cleartxt login and 31 char filename size limit
[netatalk.git] / etc / uams / uams_pam.c
1 /*
2  * $Id: uams_pam.c,v 1.14 2002-10-17 18:01:54 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 static int login(void *obj, char *username, int ulen,  struct passwd **uam_pwd,
129                      char *ibuf, int ibuflen,
130                      char *rbuf, int *rbuflen)
131 {
132     struct passwd *pwd;
133     int err, PAM_error;
134
135     if (uam_afpserver_option(obj, UAM_OPTION_CLIENTNAME,
136                              (void *) &hostname, NULL) < 0)
137     {
138         LOG(log_info, logtype_uams, "uams_pam.c :PAM: unable to retrieve client hostname");
139         hostname = NULL;
140     }
141     
142     ibuf[ PASSWDLEN ] = '\0';
143
144     if (( pwd = uam_getname(username, ulen)) == NULL ) {
145         return AFPERR_PARAM;
146     }
147
148     LOG(log_info, logtype_uams, "cleartext login: %s", username);
149     PAM_username = username;
150     PAM_password = ibuf; /* Set these things up for the conv function */
151
152     err = AFPERR_NOTAUTH;
153     PAM_error = pam_start("netatalk", username, &PAM_conversation,
154                           &pamh);
155     if (PAM_error != PAM_SUCCESS)
156       goto login_err;
157
158     pam_set_item(pamh, PAM_TTY, "afpd");
159     pam_set_item(pamh, PAM_RHOST, hostname);
160     /* use PAM_DISALLOW_NULL_AUTHTOK if passwdminlen > 0 */
161     PAM_error = pam_authenticate(pamh,0);
162     if (PAM_error != PAM_SUCCESS) {
163       if (PAM_error == PAM_MAXTRIES) 
164         err = AFPERR_PWDEXPR;
165       goto login_err;
166     }      
167
168     PAM_error = pam_acct_mgmt(pamh, 0);
169     if (PAM_error != PAM_SUCCESS) {
170       if (PAM_error == PAM_ACCT_EXPIRED)
171         err = AFPERR_PWDEXPR;
172 #ifdef PAM_AUTHTOKEN_REQD
173       else if (PAM_error == PAM_AUTHTOKEN_REQD) 
174         err = AFPERR_PWDCHNG;
175 #endif /* PAM_AUTHTOKEN_REQD */
176       goto login_err;
177     }
178
179 #ifndef PAM_CRED_ESTABLISH
180 #define PAM_CRED_ESTABLISH PAM_ESTABLISH_CRED
181 #endif /* PAM_CRED_ESTABLISH */
182     PAM_error = pam_setcred(pamh, PAM_CRED_ESTABLISH);
183     if (PAM_error != PAM_SUCCESS)
184       goto login_err;
185
186     PAM_error = pam_open_session(pamh, 0);
187     if (PAM_error != PAM_SUCCESS)
188       goto login_err;
189
190     *uam_pwd = pwd;
191     return AFP_OK;
192
193 login_err:
194     pam_end(pamh, PAM_error);
195     pamh = NULL;
196     return err;
197
198 }
199
200 /* --------------------------
201    cleartxt login 
202 */
203 static int pam_login(void *obj, struct passwd **uam_pwd,
204                      char *ibuf, int ibuflen,
205                      char *rbuf, int *rbuflen)
206 {
207     char *username; 
208     int  len, ulen;
209
210     *rbuflen = 0;
211
212     if (uam_afpserver_option(obj, UAM_OPTION_USERNAME,
213                              (void *) &username, &ulen) < 0)
214       return AFPERR_MISC;
215
216
217     len = (unsigned char) *ibuf++;
218     if ( len > ulen ) {
219         return( AFPERR_PARAM );
220     }
221
222     memcpy(username, ibuf, len );
223     ibuf += len;
224
225     username[ len ] = '\0';
226     if ((unsigned long) ibuf & 1)  /* pad character */
227       ++ibuf;
228     return (login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
229 }
230
231 static int pam_login_ext(void *obj, char *uname, struct passwd **uam_pwd,
232                      char *ibuf, int ibuflen,
233                      char *rbuf, int *rbuflen)
234 {
235     char *username; 
236     int  len, ulen;
237     u_int16_t  temp16;
238
239     *rbuflen = 0;
240
241     if (uam_afpserver_option(obj, UAM_OPTION_USERNAME,
242                              (void *) &username, &ulen) < 0)
243       return AFPERR_MISC;
244
245     if (*uname != 3)
246         return AFPERR_PARAM;
247     uname++;
248     memcpy(&temp16, uname, sizeof(temp16));
249     len = ntohs(temp16);
250
251     if (!len || len > ulen ) {
252         return( AFPERR_PARAM );
253     }
254     memcpy(username, uname +2, len );
255     username[ len ] = '\0';
256 #if 0
257     if ((unsigned long) ibuf & 1) {  /* pad character */
258       ++ibuf;
259     }
260 #endif    
261     return (login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
262 }
263
264 /* logout */
265 static void pam_logout() {
266     pam_close_session(pamh, 0);
267     pam_end(pamh, 0);
268     pamh = NULL;
269 }
270
271 /* change passwd */
272 static int pam_changepw(void *obj, char *username,
273                         struct passwd *pwd, char *ibuf, int ibuflen,
274                         char *rbuf, int *rbuflen)
275 {
276     char pw[PASSWDLEN + 1];
277     pam_handle_t *lpamh;
278     uid_t uid;
279     int PAM_error;
280
281     /* old password */
282     memcpy(pw, ibuf, PASSWDLEN);
283     memset(ibuf, 0, PASSWDLEN);
284     pw[PASSWDLEN] = '\0';
285
286     /* let's do a quick check for the same password */
287     if (memcmp(pw, ibuf + PASSWDLEN, PASSWDLEN) == 0)
288       return AFPERR_PWDSAME;
289
290     /* Set these things up for the conv function */
291     PAM_username = username;
292     PAM_password = pw; 
293
294     PAM_error = pam_start("netatalk", username, &PAM_conversation,
295                           &lpamh);
296     if (PAM_error != PAM_SUCCESS) 
297       return AFPERR_PARAM;
298     pam_set_item(lpamh, PAM_TTY, "afpd");
299     pam_set_item(lpamh, PAM_RHOST, hostname);
300
301     /* we might need to do this as root */
302     uid = geteuid();
303     seteuid(0);
304     PAM_error = pam_authenticate(lpamh,0);
305     if (PAM_error != PAM_SUCCESS) {
306       seteuid(uid);
307       pam_end(lpamh, PAM_error);
308       return AFPERR_NOTAUTH;
309     }
310
311     /* new password */
312     ibuf += PASSWDLEN;
313     PAM_password = ibuf;
314     ibuf[PASSWDLEN] = '\0';
315     
316     /* this really does need to be done as root */
317     PAM_error = pam_chauthtok(lpamh, 0);
318     seteuid(uid); /* un-root ourselves. */
319     memset(pw, 0, PASSWDLEN);
320     memset(ibuf, 0, PASSWDLEN);
321     if (PAM_error != PAM_SUCCESS) {
322       pam_end(lpamh, PAM_error);
323       return AFPERR_ACCESS;
324     }
325
326     pam_end(lpamh, 0);
327     return AFP_OK;
328 }
329
330
331 /* Printer ClearTxtUAM login */
332 int pam_printer(start, stop, username, out)
333         char    *start, *stop, *username;
334         struct papfile  *out;
335 {
336     int PAM_error;
337     char        *data, *p, *q;
338     char        password[PASSWDLEN + 1] = "\0";
339     static const char *loginok = "0\r";
340
341     data = (char *)malloc(stop - start + 1);
342     strncpy(data, start, stop - start + 1);
343
344     /* We are looking for the following format in data:
345      * (username) (password)
346      *
347      * Let's hope username doesn't contain ") ("!
348      */
349
350     /* Parse input for username in () */
351     if ((p = strchr(data, '(' )) == NULL) {
352         LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: username not found in string");
353         free(data);
354         return(-1);
355     }
356     p++;
357     if ((q = strstr(data, ") (" )) == NULL) {
358         LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: username not found in string");
359         free(data);
360         return(-1);
361     }
362     strncpy(username, p, q - p);
363
364     /* Parse input for password in next () */
365     p = q + 3;
366     if ((q = strrchr(data, ')' )) == NULL) {
367         LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: password not found in string");
368         free(data);
369         return(-1);
370     }
371     strncpy(password, p, q - p);
372
373     /* Done copying username and password, clean up */
374     free(data);
375
376     PAM_username = username;
377     PAM_password = password;
378
379     PAM_error = pam_start("netatalk", username, &PAM_conversation,
380                           &pamh);
381     if (PAM_error != PAM_SUCCESS) {
382         LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: %s: %s", 
383                         username, pam_strerror(pamh, PAM_error));
384         pam_end(pamh, PAM_error);
385         pamh = NULL;
386         return(-1);
387     }
388
389     pam_set_item(pamh, PAM_TTY, "papd");
390     pam_set_item(pamh, PAM_RHOST, hostname);
391     PAM_error = pam_authenticate(pamh,0);
392     if (PAM_error != PAM_SUCCESS) {
393         LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: %s: %s", 
394                         username, pam_strerror(pamh, PAM_error));
395         pam_end(pamh, PAM_error);
396         pamh = NULL;
397         return(-1);
398     }      
399
400     PAM_error = pam_acct_mgmt(pamh, 0);
401     if (PAM_error != PAM_SUCCESS) {
402         LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: %s: %s", 
403                         username, pam_strerror(pamh, PAM_error));
404         pam_end(pamh, PAM_error);
405         pamh = NULL;
406         return(-1);
407     }
408
409     PAM_error = pam_open_session(pamh, 0);
410     if (PAM_error != PAM_SUCCESS) {
411         LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: %s: %s", 
412                         username, pam_strerror(pamh, PAM_error));
413         pam_end(pamh, PAM_error);
414         pamh = NULL;
415         return(-1);
416     }
417
418     /* Login successful, but no need to hang onto it,
419        so logout immediately */
420     append(out, loginok, strlen(loginok));
421     LOG(log_info, logtype_uams, "Login ClearTxtUAM: %s", username);
422     pam_close_session(pamh, 0);
423     pam_end(pamh, 0);
424     pamh = NULL;
425
426     return(0);
427 }
428
429
430 static int uam_setup(const char *path)
431 {
432   if (uam_register(UAM_SERVER_LOGIN_EXT, path, "Cleartxt Passwrd", 
433                    pam_login, NULL, pam_logout, pam_login_ext) < 0)
434         return -1;
435
436   if (uam_register(UAM_SERVER_CHANGEPW, path, "Cleartxt Passwrd",
437                    pam_changepw) < 0) {
438         uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
439         return -1;
440   }
441
442   if (uam_register(UAM_SERVER_PRINTAUTH, path, "ClearTxtUAM",
443                    pam_printer) < 0) {
444         return -1;
445   }
446
447   return 0;
448 }
449
450 static void uam_cleanup(void)
451 {
452   uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
453   uam_unregister(UAM_SERVER_CHANGEPW, "Cleartxt Passwrd");
454   uam_unregister(UAM_SERVER_PRINTAUTH, "ClearTxtUAM");
455 }
456
457 UAM_MODULE_EXPORT struct uam_export uams_clrtxt = {
458   UAM_MODULE_SERVER,
459   UAM_MODULE_VERSION,
460   uam_setup, uam_cleanup
461 };
462
463 UAM_MODULE_EXPORT struct uam_export uams_pam = {
464   UAM_MODULE_SERVER,
465   UAM_MODULE_VERSION,
466   uam_setup, uam_cleanup
467 };
468 #endif