]> arthur.barton.de Git - netatalk.git/blob - etc/uams/uams_dhx_passwd.c
eb25e642d9dbc9e294faff3d60d0dc0a7bb6dc8e
[netatalk.git] / etc / uams / uams_dhx_passwd.c
1 /*
2  * $Id: uams_dhx_passwd.c,v 1.18 2003-02-11 16:41:56 didg 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 #include <string.h>
16 #ifdef HAVE_UNISTD_H
17 #include <unistd.h>
18 #endif /* HAVE_UNISTD_H */
19 #ifndef NO_CRYPT_H
20 #include <crypt.h>
21 #endif /* ! NO_CRYPT_H */
22 #include <pwd.h>
23 #include <atalk/logger.h>
24
25 #ifdef SHADOWPW
26 #include <shadow.h>
27 #endif /* SHADOWPW */
28
29 #if defined(GNUTLS_DHX)
30 #include <gnutls/openssl.h>
31 #elif defined(OPENSSL_DHX)
32 #include <openssl/bn.h>
33 #include <openssl/dh.h>
34 #include <openssl/cast.h>
35 #else /* OPENSSL_DHX */
36 #include <bn.h>
37 #include <dh.h>
38 #include <cast.h>
39 #endif /* OPENSSL_DHX */
40
41 #include <atalk/afp.h>
42 #include <atalk/uam.h>
43
44 #define KEYSIZE 16
45 #define PASSWDLEN 64
46 #define CRYPTBUFLEN  (KEYSIZE*2)
47 #define CRYPT2BUFLEN (KEYSIZE + PASSWDLEN)
48
49 /* hash a number to a 16-bit quantity */
50 #define dhxhash(a) ((((unsigned long) (a) >> 8) ^ \
51                      (unsigned long) (a)) & 0xffff)
52
53 /* the secret key */
54 static CAST_KEY castkey;
55 static struct passwd *dhxpwd;
56 static u_int8_t randbuf[16];
57
58 #ifdef TRU64
59 #include <sia.h>
60 #include <siad.h>
61
62 static char *clientname;
63 #endif /* TRU64 */
64
65 /* dhx passwd */
66 static int pwd_login(void *obj, char *username, int ulen, struct passwd **uam_pwd,
67                         char *ibuf, int ibuflen,
68                         char *rbuf, int *rbuflen)
69 {
70     unsigned char iv[] = "CJalbert";
71     u_int8_t p[] = {0xBA, 0x28, 0x73, 0xDF, 0xB0, 0x60, 0x57, 0xD4,
72                     0x3F, 0x20, 0x24, 0x74, 0x4C, 0xEE, 0xE7, 0x5B };
73     u_int8_t g = 0x07;
74 #ifdef SHADOWPW
75     struct spwd *sp;
76 #endif /* SHADOWPW */
77     BIGNUM *bn, *gbn, *pbn;
78     u_int16_t sessid;
79     int len, i;
80     char *name;
81     DH *dh;
82
83 #ifdef TRU64
84     static const char rnd_seed[] = "string to make the random number generator think it has entropy";
85     RAND_seed(rnd_seed, sizeof rnd_seed);
86 #endif /* TRU64 */
87
88     *rbuflen = 0;
89
90 #ifdef TRU64
91     if( uam_afpserver_option( obj, UAM_OPTION_CLIENTNAME,
92                               (void *) &clientname, NULL ) < 0 )
93         return AFPERR_PARAM;
94 #endif /* TRU64 */
95
96     if (( dhxpwd = uam_getname(username, ulen)) == NULL ) {
97         return AFPERR_PARAM;
98     }
99     
100     LOG(log_info, logtype_uams, "dhx login: %s", username);
101     if (uam_checkuser(dhxpwd) < 0)
102       return AFPERR_NOTAUTH;
103
104 #ifdef SHADOWPW
105     if (( sp = getspnam( dhxpwd->pw_name )) == NULL ) {
106         LOG(log_info, logtype_uams, "no shadow passwd entry for %s", username);
107         return AFPERR_NOTAUTH;
108     }
109     dhxpwd->pw_passwd = sp->sp_pwdp;
110 #endif /* SHADOWPW */
111
112     if (!dhxpwd->pw_passwd)
113       return AFPERR_NOTAUTH;
114
115     /* get the client's public key */
116     if (!(bn = BN_bin2bn(ibuf, KEYSIZE, NULL))) {
117       return AFPERR_PARAM;
118     }
119
120     /* get our primes */
121     if (!(gbn = BN_bin2bn(&g, sizeof(g), NULL))) {
122       BN_free(bn);
123       return AFPERR_PARAM;
124     }
125
126     if (!(pbn = BN_bin2bn(p, sizeof(p), NULL))) {
127       BN_free(gbn);
128       BN_free(bn);
129       return AFPERR_PARAM;
130     }
131
132     /* okay, we're ready */
133     if (!(dh = DH_new())) {
134       BN_free(pbn);
135       BN_free(gbn);
136       BN_free(bn);
137       return AFPERR_PARAM;
138     }
139
140     /* generate key and make sure we have enough space */
141     dh->p = pbn;
142     dh->g = gbn;
143     if (!DH_generate_key(dh) || (BN_num_bytes(dh->pub_key) > KEYSIZE)) {
144       goto passwd_fail;
145     }
146
147     /* figure out the key. use rbuf as a temporary buffer. */
148     i = DH_compute_key(rbuf, bn, dh);
149     
150     /* set the key */
151     CAST_set_key(&castkey, i, rbuf);
152     
153     /* session id. it's just a hashed version of the object pointer. */
154     sessid = dhxhash(obj);
155     memcpy(rbuf, &sessid, sizeof(sessid));
156     rbuf += sizeof(sessid);
157     *rbuflen += sizeof(sessid);
158     
159     /* send our public key */
160     BN_bn2bin(dh->pub_key, rbuf); 
161     rbuf += KEYSIZE;
162     *rbuflen += KEYSIZE;
163
164     /* buffer to be encrypted */
165     i = sizeof(randbuf);
166     if (uam_afpserver_option(obj, UAM_OPTION_RANDNUM, (void *) randbuf,
167                              &i) < 0) {
168       *rbuflen = 0;
169       goto passwd_fail;
170     }    
171     memcpy(rbuf, &randbuf, sizeof(randbuf));
172
173 #if 0
174     /* get the signature. it's always 16 bytes. */
175     if (uam_afpserver_option(obj, UAM_OPTION_SIGNATURE, 
176                              (void *) &name, NULL) < 0) {
177       *rbuflen = 0;
178       goto passwd_fail;
179     }
180     memcpy(rbuf + KEYSIZE, name, KEYSIZE); 
181 #else /* 0 */
182     memset(rbuf + KEYSIZE, 0, KEYSIZE);
183 #endif /* 0 */
184
185     /* encrypt using cast */
186     CAST_cbc_encrypt(rbuf, rbuf, CRYPTBUFLEN, &castkey, iv, CAST_ENCRYPT);
187     *rbuflen += CRYPTBUFLEN;
188     BN_free(bn);
189     DH_free(dh);
190     return AFPERR_AUTHCONT;
191
192 passwd_fail:
193     BN_free(bn);
194     DH_free(dh);
195     return AFPERR_PARAM;
196 }
197
198 /* cleartxt login */
199 static int passwd_login(void *obj, struct passwd **uam_pwd,
200                         char *ibuf, int ibuflen,
201                         char *rbuf, int *rbuflen)
202 {
203     char *username;
204     int len, ulen;
205
206     *rbuflen = 0;
207
208     if (uam_afpserver_option(obj, UAM_OPTION_USERNAME,
209                              (void *) &username, &ulen) < 0)
210         return AFPERR_MISC;
211
212     if (ibuflen <= 1) {
213         return( AFPERR_PARAM );
214     }
215
216     len = (unsigned char) *ibuf++;
217     ibuflen--;
218     if (!len || len > ibuflen || len > ulen ) {
219         return( AFPERR_PARAM );
220     }
221     memcpy(username, ibuf, len );
222     ibuf += len;
223     ibuflen -=len;
224     username[ len ] = '\0';
225
226     if ((unsigned long) ibuf & 1) { /* pad character */
227         ++ibuf;
228         ibuflen--;
229     }
230     return (pwd_login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
231     
232 }
233
234 /* cleartxt login ext 
235  * uname format :
236     byte      3
237     2 bytes   len (network order)
238     len bytes unicode name
239 */
240 static int passwd_login_ext(void *obj, char *uname, struct passwd **uam_pwd,
241                         char *ibuf, int ibuflen,
242                         char *rbuf, int *rbuflen)
243 {
244     char       *username;
245     int        len, ulen;
246     u_int16_t  temp16;
247
248     *rbuflen = 0;
249     
250     if (uam_afpserver_option(obj, UAM_OPTION_USERNAME,
251                              (void *) &username, &ulen) < 0)
252         return AFPERR_MISC;
253
254     if (*uname != 3)
255         return AFPERR_PARAM;
256     uname++;
257     memcpy(&temp16, uname, sizeof(temp16));
258     len = ntohs(temp16);
259     if (!len || len > ulen ) {
260         return( AFPERR_PARAM );
261     }
262     memcpy(username, uname +2, len );
263     username[ len ] = '\0';
264     return (pwd_login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
265 }
266                         
267 static int passwd_logincont(void *obj, struct passwd **uam_pwd,
268                             char *ibuf, int ibuflen, 
269                             char *rbuf, int *rbuflen)
270 {
271     unsigned char iv[] = "LWallace";
272     BIGNUM *bn1, *bn2, *bn3;
273     u_int16_t sessid;
274     char *p;
275
276     *rbuflen = 0;
277
278     /* check for session id */
279     memcpy(&sessid, ibuf, sizeof(sessid));
280     if (sessid != dhxhash(obj))
281       return AFPERR_PARAM;
282     ibuf += sizeof(sessid);
283    
284     /* use rbuf as scratch space */
285     CAST_cbc_encrypt(ibuf, rbuf, CRYPT2BUFLEN, &castkey,
286                      iv, CAST_DECRYPT);
287     
288     /* check to make sure that the random number is the same. we
289      * get sent back an incremented random number. */
290     if (!(bn1 = BN_bin2bn(rbuf, KEYSIZE, NULL)))
291       return AFPERR_PARAM;
292
293     if (!(bn2 = BN_bin2bn(randbuf, sizeof(randbuf), NULL))) {
294       BN_free(bn1);
295       return AFPERR_PARAM;
296     }
297       
298     /* zero out the random number */
299     memset(rbuf, 0, sizeof(randbuf));
300     memset(randbuf, 0, sizeof(randbuf));
301     rbuf += KEYSIZE;
302
303     if (!(bn3 = BN_new())) {
304       BN_free(bn2);
305       BN_free(bn1);
306       return AFPERR_PARAM;
307     }
308
309     BN_sub(bn3, bn1, bn2);
310     BN_free(bn2);
311     BN_free(bn1);
312
313     /* okay. is it one more? */
314     if (!BN_is_one(bn3)) {
315       BN_free(bn3);
316       return AFPERR_PARAM;
317     }
318     BN_free(bn3);
319
320     rbuf[PASSWDLEN] = '\0';
321 #ifdef TRU64
322     {
323         int ac;
324         char **av;
325         char hostname[256];
326
327         uam_afp_getcmdline( &ac, &av );
328         sprintf( hostname, "%s@%s", dhxpwd->pw_name, clientname );
329
330         if( uam_sia_validate_user( NULL, ac, av, hostname, dhxpwd->pw_name,
331                                    NULL, FALSE, NULL, rbuf ) != SIASUCCESS )
332             return AFPERR_NOTAUTH;
333
334         memset( rbuf, 0, PASSWDLEN );
335         *uam_pwd = dhxpwd;
336         return AFP_OK;
337     }
338 #else /* TRU64 */
339     p = crypt( rbuf, dhxpwd->pw_passwd );
340     memset(rbuf, 0, PASSWDLEN);
341     if ( strcmp( p, dhxpwd->pw_passwd ) == 0 ) {
342       *uam_pwd = dhxpwd;
343       return AFP_OK;
344     }
345 #endif /* TRU64 */
346
347     return AFPERR_NOTAUTH;
348 }
349
350
351 static int uam_setup(const char *path)
352 {
353   if (uam_register(UAM_SERVER_LOGIN_EXT, path, "DHCAST128",
354                    passwd_login, passwd_logincont, NULL, passwd_login_ext) < 0)
355     return -1;
356   /*uam_register(UAM_SERVER_PRINTAUTH, path, "DHCAST128",
357     passwd_printer);*/
358
359   return 0;
360 }
361
362 static void uam_cleanup(void)
363 {
364   uam_unregister(UAM_SERVER_LOGIN, "DHCAST128");
365   /*uam_unregister(UAM_SERVER_PRINTAUTH, "DHCAST128"); */
366 }
367
368 UAM_MODULE_EXPORT struct uam_export uams_dhx = {
369   UAM_MODULE_SERVER,
370   UAM_MODULE_VERSION,
371   uam_setup, uam_cleanup
372 };