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