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