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