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