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