]> arthur.barton.de Git - netatalk.git/blob - etc/uams/uams_pam.c
Fix several warnings, remove const
[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                      struct pam_message **msg,
58                      struct pam_response **resp,
59                      void *appdata_ptr _U_) 
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, size_t ibuflen _U_,
130                      char *rbuf _U_, size_t *rbuflen _U_)
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(obj, username, ulen)) == NULL ) {
145         return AFPERR_NOTAUTH;
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_NEW_AUTHTOK_REQD) /* Password change required */
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       else
177         goto login_err;
178     }
179
180 #ifndef PAM_CRED_ESTABLISH
181 #define PAM_CRED_ESTABLISH PAM_ESTABLISH_CRED
182 #endif /* PAM_CRED_ESTABLISH */
183     PAM_error = pam_setcred(pamh, PAM_CRED_ESTABLISH);
184     if (PAM_error != PAM_SUCCESS)
185       goto login_err;
186
187     PAM_error = pam_open_session(pamh, 0);
188     if (PAM_error != PAM_SUCCESS)
189       goto login_err;
190
191     *uam_pwd = pwd;
192
193     if (err == AFPERR_PWDEXPR)
194         return err;
195
196     return AFP_OK;
197
198 login_err:
199     pam_end(pamh, PAM_error);
200     pamh = NULL;
201     return err;
202 }
203
204 /* --------------------------
205    cleartxt login 
206 */
207 static int pam_login(void *obj, struct passwd **uam_pwd,
208                      char *ibuf, size_t ibuflen,
209                      char *rbuf, size_t *rbuflen)
210 {
211     char *username; 
212     size_t  len, ulen;
213
214     *rbuflen = 0;
215
216     if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, (void *) &username, &ulen) < 0) {
217         return AFPERR_MISC;
218     }
219
220     len = (unsigned char) *ibuf++;
221     if ( len > ulen ) {
222         return( AFPERR_PARAM );
223     }
224
225     memcpy(username, ibuf, len );
226     ibuf += len;
227
228     username[ len ] = '\0';
229
230     if ((unsigned long) ibuf & 1)  /* pad character */
231       ++ibuf;
232     return (login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
233 }
234
235 /* ----------------------------- */
236 static int pam_login_ext(void *obj, char *uname, struct passwd **uam_pwd,
237                      char *ibuf, size_t ibuflen,
238                      char *rbuf, size_t *rbuflen)
239 {
240     char *username; 
241     size_t  len, ulen;
242     uint16_t  temp16;
243
244     *rbuflen = 0;
245
246     if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, (void *) &username, &ulen) < 0)
247       return AFPERR_MISC;
248
249     if (*uname != 3)
250         return AFPERR_PARAM;
251     uname++;
252     memcpy(&temp16, uname, sizeof(temp16));
253     len = ntohs(temp16);
254
255     if (!len || len > ulen ) {
256         return( AFPERR_PARAM );
257     }
258     memcpy(username, uname +2, len );
259     username[ len ] = '\0';
260     
261     return (login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
262 }
263
264 /* logout */
265 static void pam_logout(void) {
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 _U_, char *username,
273                         struct passwd *pwd _U_, char *ibuf, size_t ibuflen _U_,
274                         char *rbuf _U_, size_t *rbuflen _U_)
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 static int pam_printer(char *start, char *stop, char *username, struct papfile *out)
333 {
334     int PAM_error;
335     char        *data, *p, *q;
336     char        password[PASSWDLEN + 1] = "\0";
337     static const char *loginok = "0\r";
338     struct passwd *pwd;
339
340     data = (char *)malloc(stop - start + 1);
341     if (!data) {
342         LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: malloc");
343         return(-1);
344     }
345
346     strlcpy(data, start, stop - start + 1);
347
348     /* We are looking for the following format in data:
349      * (username) (password)
350      *
351      * Let's hope username doesn't contain ") ("!
352      */
353
354     /* Parse input for username in () */
355     if ((p = strchr(data, '(' )) == NULL) {
356         LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: username not found in string");
357         free(data);
358         return(-1);
359     }
360     p++;
361     if ((q = strstr(p, ") (" )) == NULL) {
362         LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: username not found in string");
363         free(data);
364         return(-1);
365     }
366     memcpy(username, p, MIN(UAM_USERNAMELEN, q - p) );
367
368     /* Parse input for password in next () */
369     p = q + 3;
370     if ((q = strrchr(p, ')' )) == NULL) {
371         LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: password not found in string");
372         free(data);
373         return(-1);
374     }
375     memcpy(password, p, MIN(PASSWDLEN, (q - p)) );
376
377     /* Done copying username and password, clean up */
378     free(data);
379
380     if (( pwd = uam_getname(NULL, username, strlen(username))) == NULL ) {
381         LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: ( %s ) not found ",
382             username);
383         return(-1);
384     }
385
386     if (uam_checkuser(pwd) < 0) {
387         /* syslog of error happens in uam_checkuser */
388         return(-1);
389     }
390
391     PAM_username = username;
392     PAM_password = password;
393
394     PAM_error = pam_start("netatalk", username, &PAM_conversation,
395                           &pamh);
396     if (PAM_error != PAM_SUCCESS) {
397         LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: %s: %s", 
398                         username, pam_strerror(pamh, PAM_error));
399         pam_end(pamh, PAM_error);
400         pamh = NULL;
401         return(-1);
402     }
403
404     pam_set_item(pamh, PAM_TTY, "papd");
405     pam_set_item(pamh, PAM_RHOST, hostname);
406     PAM_error = pam_authenticate(pamh,0);
407     if (PAM_error != PAM_SUCCESS) {
408         LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: %s: %s", 
409                         username, pam_strerror(pamh, PAM_error));
410         pam_end(pamh, PAM_error);
411         pamh = NULL;
412         return(-1);
413     }      
414
415     PAM_error = pam_acct_mgmt(pamh, 0);
416     if (PAM_error != PAM_SUCCESS) {
417         LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: %s: %s", 
418                         username, pam_strerror(pamh, PAM_error));
419         pam_end(pamh, PAM_error);
420         pamh = NULL;
421         return(-1);
422     }
423
424     PAM_error = pam_open_session(pamh, 0);
425     if (PAM_error != PAM_SUCCESS) {
426         LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: %s: %s", 
427                         username, pam_strerror(pamh, PAM_error));
428         pam_end(pamh, PAM_error);
429         pamh = NULL;
430         return(-1);
431     }
432
433     /* Login successful, but no need to hang onto it,
434        so logout immediately */
435     append(out, loginok, strlen(loginok));
436     LOG(log_info, logtype_uams, "Login ClearTxtUAM: %s", username);
437     pam_close_session(pamh, 0);
438     pam_end(pamh, 0);
439     pamh = NULL;
440
441     return(0);
442 }
443
444
445 static int uam_setup(const char *path)
446 {
447   if (uam_register(UAM_SERVER_LOGIN_EXT, path, "Cleartxt Passwrd", 
448                    pam_login, NULL, pam_logout, pam_login_ext) < 0)
449         return -1;
450
451   if (uam_register(UAM_SERVER_CHANGEPW, path, "Cleartxt Passwrd",
452                    pam_changepw) < 0) {
453         uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
454         return -1;
455   }
456
457   if (uam_register(UAM_SERVER_PRINTAUTH, path, "ClearTxtUAM",
458                    pam_printer) < 0) {
459         return -1;
460   }
461
462   return 0;
463 }
464
465 static void uam_cleanup(void)
466 {
467   uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
468   uam_unregister(UAM_SERVER_CHANGEPW, "Cleartxt Passwrd");
469   uam_unregister(UAM_SERVER_PRINTAUTH, "ClearTxtUAM");
470 }
471
472 UAM_MODULE_EXPORT struct uam_export uams_clrtxt = {
473   UAM_MODULE_SERVER,
474   UAM_MODULE_VERSION,
475   uam_setup, uam_cleanup
476 };
477
478 UAM_MODULE_EXPORT struct uam_export uams_pam = {
479   UAM_MODULE_SERVER,
480   UAM_MODULE_VERSION,
481   uam_setup, uam_cleanup
482 };