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