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