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