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