]> arthur.barton.de Git - netatalk.git/blob - etc/uams/uams_pam.c
Initial revision
[netatalk.git] / etc / uams / uams_pam.c
1 /*
2  * Copyright (c) 1990,1993 Regents of The University of Michigan.
3  * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu) 
4  * All Rights Reserved.  See COPYRIGHT.
5  */
6 #ifdef USE_PAM
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <string.h>
11 #include <syslog.h>
12
13 #include <security/pam_appl.h>
14
15 #include <atalk/afp.h>
16 #include <atalk/uam.h>
17
18 #define PASSWDLEN 8
19
20 /* Static variables used to communicate between the conversation function
21  * and the server_login function
22  */
23 static pam_handle_t *pamh = NULL; 
24 static char *hostname;
25 static char *PAM_username;
26 static char *PAM_password;
27
28 /* PAM conversation function
29  * Here we assume (for now, at least) that echo on means login name, and
30  * echo off means password.
31  */
32 static int PAM_conv (int num_msg,
33                      const struct pam_message **msg,
34                      struct pam_response **resp,
35                      void *appdata_ptr) 
36 {
37   struct pam_response *reply;
38   int count;
39   
40 #define COPY_STRING(s) (s) ? strdup(s) : NULL
41   
42   if (num_msg < 1)
43     return PAM_CONV_ERR;
44
45   reply = (struct pam_response *) 
46     calloc(num_msg, sizeof(struct pam_response));
47
48   if (!reply)
49     return PAM_CONV_ERR;
50
51   for (count = 0; count < num_msg; count++) {
52     char *string = NULL;
53
54     switch (msg[count]->msg_style) {
55     case PAM_PROMPT_ECHO_ON:
56       if (!(string = COPY_STRING(PAM_username)))
57         goto pam_fail_conv;
58       break;
59     case PAM_PROMPT_ECHO_OFF:
60       if (!(string = COPY_STRING(PAM_password)))
61         goto pam_fail_conv;
62       break;
63     case PAM_TEXT_INFO:
64 #ifdef PAM_BINARY_PROMPT
65     case PAM_BINARY_PROMPT:
66 #endif
67       /* ignore it... */
68       break;
69     case PAM_ERROR_MSG:
70     default:
71       goto pam_fail_conv;
72     }
73
74     if (string) {  
75       reply[count].resp_retcode = 0;
76       reply[count].resp = string;
77       string = NULL;
78     }
79   }
80
81   *resp = reply;
82   return PAM_SUCCESS;
83
84 pam_fail_conv:
85   for (count = 0; count < num_msg; count++) {
86     if (!reply[count].resp)
87       continue;
88     switch (msg[count]->msg_style) {
89     case PAM_PROMPT_ECHO_OFF:
90     case PAM_PROMPT_ECHO_ON:
91       free(reply[count].resp);
92       break;      
93     }
94   }
95   free(reply);
96   return PAM_CONV_ERR;
97 }
98
99 static struct pam_conv PAM_conversation = {
100   &PAM_conv,
101   NULL
102 };
103
104
105 /* cleartxt login */
106 static int pam_login(void *obj, struct passwd **uam_pwd,
107                      char *ibuf, int ibuflen,
108                      char *rbuf, int *rbuflen)
109 {
110     struct passwd *pwd;
111     char *username; 
112     int err, len, ulen, PAM_error;
113
114     *rbuflen = 0;
115
116     if (uam_afpserver_option(obj, UAM_OPTION_USERNAME,
117                              (void *) &username, &ulen) < 0)
118       return AFPERR_MISC;
119
120     if (uam_afpserver_option(obj, UAM_OPTION_HOSTNAME,
121                              (void *) &hostname, NULL) < 0)
122       return AFPERR_MISC;
123
124     len = (unsigned char) *ibuf++;
125     if ( len > ulen ) {
126         return( AFPERR_PARAM );
127     }
128
129     memcpy(username, ibuf, len );
130     ibuf += len;
131     username[ len ] = '\0';
132     if ((unsigned long) ibuf & 1)  /* pad character */
133       ++ibuf;
134     ibuf[ PASSWDLEN ] = '\0';
135
136     if (( pwd = uam_getname(username, ulen)) == NULL ) {
137         return AFPERR_PARAM;
138     }
139
140     syslog(LOG_INFO, "cleartext login: %s", username);
141     PAM_username = username;
142     PAM_password = ibuf; /* Set these things up for the conv function */
143
144     err = AFPERR_NOTAUTH;
145     PAM_error = pam_start("netatalk", username, &PAM_conversation,
146                           &pamh);
147     if (PAM_error != PAM_SUCCESS)
148       goto login_err;
149
150     pam_set_item(pamh, PAM_TTY, "afpd");
151     pam_set_item(pamh, PAM_RHOST, hostname);
152     /* use PAM_DISALLOW_NULL_AUTHTOK if passwdminlen > 0 */
153     PAM_error = pam_authenticate(pamh,0);
154     if (PAM_error != PAM_SUCCESS) {
155       if (PAM_error == PAM_MAXTRIES) 
156         err = AFPERR_PWDEXPR;
157       goto login_err;
158     }      
159
160     PAM_error = pam_acct_mgmt(pamh, 0);
161     if (PAM_error != PAM_SUCCESS) {
162       if (PAM_error == PAM_ACCT_EXPIRED)
163         err = AFPERR_PWDEXPR;
164 #ifdef PAM_AUTHTOKEN_REQD
165       else if (PAM_error == PAM_AUTHTOKEN_REQD) 
166         err = AFPERR_PWDCHNG;
167 #endif
168       goto login_err;
169     }
170
171 #ifndef PAM_CRED_ESTABLISH
172 #define PAM_CRED_ESTABLISH PAM_ESTABLISH_CRED
173 #endif
174     PAM_error = pam_setcred(pamh, PAM_CRED_ESTABLISH);
175     if (PAM_error != PAM_SUCCESS)
176       goto login_err;
177
178     PAM_error = pam_open_session(pamh, 0);
179     if (PAM_error != PAM_SUCCESS)
180       goto login_err;
181
182     *uam_pwd = pwd;
183     return AFP_OK;
184
185 login_err:
186     pam_end(pamh, PAM_error);
187     pamh = NULL;
188     return err;
189 }
190
191 /* logout */
192 static void pam_logout() {
193     pam_close_session(pamh, 0);
194     pam_end(pamh, 0);
195     pamh = NULL;
196 }
197
198 /* change passwd */
199 static int pam_changepw(void *obj, char *username,
200                         struct passwd *pwd, char *ibuf, int ibuflen,
201                         char *rbuf, int *rbuflen)
202 {
203     char pw[PASSWDLEN + 1];
204     pam_handle_t *lpamh;
205     uid_t uid;
206     int PAM_error;
207
208     /* old password */
209     memcpy(pw, ibuf, PASSWDLEN);
210     memset(ibuf, 0, PASSWDLEN);
211     pw[PASSWDLEN] = '\0';
212
213     /* let's do a quick check for the same password */
214     if (memcmp(pw, ibuf + PASSWDLEN, PASSWDLEN) == 0)
215       return AFPERR_PWDSAME;
216
217     /* Set these things up for the conv function */
218     PAM_username = username;
219     PAM_password = pw; 
220
221     PAM_error = pam_start("netatalk", username, &PAM_conversation,
222                           &lpamh);
223     if (PAM_error != PAM_SUCCESS) 
224       return AFPERR_PARAM;
225     pam_set_item(lpamh, PAM_TTY, "afpd");
226     pam_set_item(lpamh, PAM_RHOST, hostname);
227
228     /* we might need to do this as root */
229     uid = geteuid();
230     seteuid(0);
231     PAM_error = pam_authenticate(lpamh,0);
232     if (PAM_error != PAM_SUCCESS) {
233       seteuid(uid);
234       pam_end(lpamh, PAM_error);
235       return AFPERR_NOTAUTH;
236     }
237
238     /* new password */
239     ibuf += PASSWDLEN;
240     PAM_password = ibuf;
241     ibuf[PASSWDLEN] = '\0';
242     
243     /* this really does need to be done as root */
244     PAM_error = pam_chauthtok(lpamh, 0);
245     seteuid(uid); /* un-root ourselves. */
246     memset(pw, 0, PASSWDLEN);
247     memset(ibuf, 0, PASSWDLEN);
248     if (PAM_error != PAM_SUCCESS) {
249       pam_end(lpamh, PAM_error);
250       return AFPERR_ACCESS;
251     }
252
253     pam_end(lpamh, 0);
254     return AFP_OK;
255 }
256
257
258 static int uam_setup(const char *path)
259 {
260   if (uam_register(UAM_SERVER_LOGIN, path, "Cleartxt Passwrd", 
261                    pam_login, NULL, pam_logout) < 0)
262     return -1;
263
264   if (uam_register(UAM_SERVER_CHANGEPW, path, "Cleartxt Passwrd",
265                    pam_changepw) < 0) {
266     uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
267     return -1;
268   }
269
270   /*uam_register(UAM_SERVER_PRINTAUTH, path, "Cleartxt Passwrd",
271     pam_printer);*/
272
273   return 0;
274 }
275
276 static void uam_cleanup(void)
277 {
278   uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
279   uam_unregister(UAM_SERVER_CHANGEPW, "Cleartxt Passwrd");
280   /*uam_unregister(UAM_SERVER_PRINTAUTH, "Cleartxt Passwrd"); */
281 }
282
283 UAM_MODULE_EXPORT struct uam_export uams_clrtxt = {
284   UAM_MODULE_SERVER,
285   UAM_MODULE_VERSION,
286   uam_setup, uam_cleanup
287 };
288
289 #endif /* USE_PAM */