]> arthur.barton.de Git - netatalk.git/blob - etc/uams/uams_dhx_passwd.c
b7d4eae1e9e428ae376d319d731f003cb811eb6d
[netatalk.git] / etc / uams / uams_dhx_passwd.c
1 /*
2  * $Id: uams_dhx_passwd.c,v 1.12 2001-10-24 16:21:33 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 SHADOWPW
28 #include <shadow.h>
29 #endif /* SHADOWPW */
30
31 #ifdef 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 passwd_login(void *obj, 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     if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, (void *) &name, &i) < 0)
91       return AFPERR_PARAM;
92
93 #ifdef TRU64
94     if( uam_afpserver_option( obj, UAM_OPTION_CLIENTNAME,
95                               (void *) &clientname, NULL ) < 0 )
96         return AFPERR_PARAM;
97 #endif /* TRU64 */
98
99     len = (unsigned char) *ibuf++;
100     if ( len + 1 > i ) {
101         return( AFPERR_PARAM );
102     }
103
104     memcpy(name, ibuf, len );
105     ibuf += len;
106     name[ len ] = '\0';
107     if ((unsigned long) ibuf & 1) /* padding */
108       ++ibuf;
109
110     if (( dhxpwd = uam_getname(name, i)) == NULL ) {
111       return AFPERR_PARAM;
112     }
113
114     syslog( LOG_INFO, "dhx login: %s", name);
115     if (uam_checkuser(dhxpwd) < 0)
116       return AFPERR_NOTAUTH;
117
118 #ifdef SHADOWPW
119     if (( sp = getspnam( dhxpwd->pw_name )) == NULL ) {
120         syslog( LOG_INFO, "no shadow passwd entry for %s", name);
121         return AFPERR_NOTAUTH;
122     }
123     dhxpwd->pw_passwd = sp->sp_pwdp;
124 #endif /* SHADOWPW */
125
126     if (!dhxpwd->pw_passwd)
127       return AFPERR_NOTAUTH;
128
129     /* get the client's public key */
130     if (!(bn = BN_bin2bn(ibuf, KEYSIZE, NULL))) {
131       return AFPERR_PARAM;
132     }
133
134     /* get our primes */
135     if (!(gbn = BN_bin2bn(&g, sizeof(g), NULL))) {
136       BN_free(bn);
137       return AFPERR_PARAM;
138     }
139
140     if (!(pbn = BN_bin2bn(p, sizeof(p), NULL))) {
141       BN_free(gbn);
142       BN_free(bn);
143       return AFPERR_PARAM;
144     }
145
146     /* okay, we're ready */
147     if (!(dh = DH_new())) {
148       BN_free(pbn);
149       BN_free(gbn);
150       BN_free(bn);
151       return AFPERR_PARAM;
152     }
153
154     /* generate key and make sure we have enough space */
155     dh->p = pbn;
156     dh->g = gbn;
157     if (!DH_generate_key(dh) || (BN_num_bytes(dh->pub_key) > KEYSIZE)) {
158       goto passwd_fail;
159     }
160
161     /* figure out the key. use rbuf as a temporary buffer. */
162     i = DH_compute_key(rbuf, bn, dh);
163     
164     /* set the key */
165     CAST_set_key(&castkey, i, rbuf);
166     
167     /* session id. it's just a hashed version of the object pointer. */
168     sessid = dhxhash(obj);
169     memcpy(rbuf, &sessid, sizeof(sessid));
170     rbuf += sizeof(sessid);
171     *rbuflen += sizeof(sessid);
172     
173     /* send our public key */
174     BN_bn2bin(dh->pub_key, rbuf); 
175     rbuf += KEYSIZE;
176     *rbuflen += KEYSIZE;
177
178     /* buffer to be encrypted */
179     i = sizeof(randbuf);
180     if (uam_afpserver_option(obj, UAM_OPTION_RANDNUM, (void *) randbuf,
181                              &i) < 0) {
182       *rbuflen = 0;
183       goto passwd_fail;
184     }    
185     memcpy(rbuf, &randbuf, sizeof(randbuf));
186
187 #if 0
188     /* get the signature. it's always 16 bytes. */
189     if (uam_afpserver_option(obj, UAM_OPTION_SIGNATURE, 
190                              (void *) &name, NULL) < 0) {
191       *rbuflen = 0;
192       goto passwd_fail;
193     }
194     memcpy(rbuf + KEYSIZE, name, KEYSIZE); 
195 #else /* 0 */
196     memset(rbuf + KEYSIZE, 0, KEYSIZE);
197 #endif /* 0 */
198
199     /* encrypt using cast */
200     CAST_cbc_encrypt(rbuf, rbuf, CRYPTBUFLEN, &castkey, iv, CAST_ENCRYPT);
201     *rbuflen += CRYPTBUFLEN;
202     BN_free(bn);
203     DH_free(dh);
204     return AFPERR_AUTHCONT;
205
206 passwd_fail:
207     BN_free(bn);
208     DH_free(dh);
209     return AFPERR_PARAM;
210 }
211
212 static int passwd_logincont(void *obj, struct passwd **uam_pwd,
213                             char *ibuf, int ibuflen, 
214                             char *rbuf, int *rbuflen)
215 {
216     unsigned char iv[] = "LWallace";
217     BIGNUM *bn1, *bn2, *bn3;
218     u_int16_t sessid;
219     char *p;
220
221     *rbuflen = 0;
222
223     /* check for session id */
224     memcpy(&sessid, ibuf, sizeof(sessid));
225     if (sessid != dhxhash(obj))
226       return AFPERR_PARAM;
227     ibuf += sizeof(sessid);
228    
229     /* use rbuf as scratch space */
230     CAST_cbc_encrypt(ibuf, rbuf, CRYPT2BUFLEN, &castkey,
231                      iv, CAST_DECRYPT);
232     
233     /* check to make sure that the random number is the same. we
234      * get sent back an incremented random number. */
235     if (!(bn1 = BN_bin2bn(rbuf, KEYSIZE, NULL)))
236       return AFPERR_PARAM;
237
238     if (!(bn2 = BN_bin2bn(randbuf, sizeof(randbuf), NULL))) {
239       BN_free(bn1);
240       return AFPERR_PARAM;
241     }
242       
243     /* zero out the random number */
244     memset(rbuf, 0, sizeof(randbuf));
245     memset(randbuf, 0, sizeof(randbuf));
246     rbuf += KEYSIZE;
247
248     if (!(bn3 = BN_new())) {
249       BN_free(bn2);
250       BN_free(bn1);
251       return AFPERR_PARAM;
252     }
253
254     BN_sub(bn3, bn1, bn2);
255     BN_free(bn2);
256     BN_free(bn1);
257
258     /* okay. is it one more? */
259     if (!BN_is_one(bn3)) {
260       BN_free(bn3);
261       return AFPERR_PARAM;
262     }
263     BN_free(bn3);
264
265     rbuf[PASSWDLEN] = '\0';
266 #ifdef TRU64
267     {
268         int ac;
269         char **av;
270         char hostname[256];
271
272         uam_afp_getcmdline( &ac, &av );
273         sprintf( hostname, "%s@%s", dhxpwd->pw_name, clientname );
274
275         if( sia_validate_user( NULL, ac, av, hostname, dhxpwd->pw_name,
276                                NULL, FALSE, NULL, rbuf ) != SIASUCCESS )
277             return AFPERR_NOTAUTH;
278
279         memset( rbuf, 0, PASSWDLEN );
280         *uam_pwd = dhxpwd;
281         return AFP_OK;
282     }
283 #else /* TRU64 */
284     p = crypt( rbuf, dhxpwd->pw_passwd );
285     memset(rbuf, 0, PASSWDLEN);
286     if ( strcmp( p, dhxpwd->pw_passwd ) == 0 ) {
287       *uam_pwd = dhxpwd;
288       return AFP_OK;
289     }
290 #endif /* TRU64 */
291
292     return AFPERR_NOTAUTH;
293 }
294
295
296 static int uam_setup(const char *path)
297 {
298   if (uam_register(UAM_SERVER_LOGIN, path, "DHCAST128",
299                    passwd_login, passwd_logincont, NULL) < 0)
300     return -1;
301   /*uam_register(UAM_SERVER_PRINTAUTH, path, "DHCAST128",
302     passwd_printer);*/
303
304   return 0;
305 }
306
307 static void uam_cleanup(void)
308 {
309   uam_unregister(UAM_SERVER_LOGIN, "DHCAST128");
310   /*uam_unregister(UAM_SERVER_PRINTAUTH, "DHCAST128"); */
311 }
312
313 UAM_MODULE_EXPORT struct uam_export uams_dhx = {
314   UAM_MODULE_SERVER,
315   UAM_MODULE_VERSION,
316   uam_setup, uam_cleanup
317 };
318
319 #endif /* UAM_DHX */