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