]> arthur.barton.de Git - netatalk.git/blob - etc/uams/uams_dhx_passwd.c
cb2471f701804830166d836149636ebb56da4b64
[netatalk.git] / etc / uams / uams_dhx_passwd.c
1 /*
2  * $Id: uams_dhx_passwd.c,v 1.8 2001-05-22 19:13:36 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 TRU64
60 #include <sys/types.h>
61 #include <sys/security.h>
62 #include <prot.h>
63 #include <sia.h>
64
65 static int c2security = 0;
66 #endif /* TRU64 */
67
68 /* dhx passwd */
69 static int passwd_login(void *obj, struct passwd **uam_pwd,
70                         char *ibuf, int ibuflen,
71                         char *rbuf, int *rbuflen)
72 {
73     unsigned char iv[] = "CJalbert";
74     u_int8_t p[] = {0xBA, 0x28, 0x73, 0xDF, 0xB0, 0x60, 0x57, 0xD4,
75                     0x3F, 0x20, 0x24, 0x74, 0x4C, 0xEE, 0xE7, 0x5B };
76     u_int8_t g = 0x07;
77 #ifdef SHADOWPW
78     struct spwd *sp;
79 #endif
80     BIGNUM *bn, *gbn, *pbn;
81     u_int16_t sessid;
82     int len, i;
83     char *name;
84     DH *dh;
85
86 #ifdef TRU64
87     static const char rnd_seed[] = "string to make the random number generator think it has entropy";
88     RAND_seed(rnd_seed, sizeof rnd_seed);
89 #endif /* TRU64 */
90
91     *rbuflen = 0;
92
93     if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, (void *) &name, &i) < 0)
94       return AFPERR_PARAM;
95
96     len = (unsigned char) *ibuf++;
97     if ( len > i ) {
98         return( AFPERR_PARAM );
99     }
100
101     memcpy(name, ibuf, len );
102     ibuf += len;
103     name[ len ] = '\0';
104     if ((unsigned long) ibuf & 1) /* padding */
105       ++ibuf;
106
107     if (( dhxpwd = uam_getname(name, i)) == NULL ) {
108       return AFPERR_PARAM;
109     }
110
111     syslog( LOG_INFO, "dhx login: %s", name);
112     if (uam_checkuser(dhxpwd) < 0)
113       return AFPERR_NOTAUTH;
114
115 #ifdef SHADOWPW
116     if (( sp = getspnam( dhxpwd->pw_name )) == NULL ) {
117         syslog( LOG_INFO, "no shadow passwd entry for %s", name);
118         return AFPERR_NOTAUTH;
119     }
120     dhxpwd->pw_passwd = sp->sp_pwdp;
121 #endif SHADOWPW
122
123     if (!dhxpwd->pw_passwd)
124       return AFPERR_NOTAUTH;
125
126     /* get the client's public key */
127     if (!(bn = BN_bin2bn(ibuf, KEYSIZE, NULL))) {
128       return AFPERR_PARAM;
129     }
130
131     /* get our primes */
132     if (!(gbn = BN_bin2bn(&g, sizeof(g), NULL))) {
133       BN_free(bn);
134       return AFPERR_PARAM;
135     }
136
137     if (!(pbn = BN_bin2bn(p, sizeof(p), NULL))) {
138       BN_free(gbn);
139       BN_free(bn);
140       return AFPERR_PARAM;
141     }
142
143     /* okay, we're ready */
144     if (!(dh = DH_new())) {
145       BN_free(pbn);
146       BN_free(gbn);
147       BN_free(bn);
148       return AFPERR_PARAM;
149     }
150
151     /* generate key and make sure we have enough space */
152     dh->p = pbn;
153     dh->g = gbn;
154     if (!DH_generate_key(dh) || (BN_num_bytes(dh->pub_key) > KEYSIZE)) {
155       goto passwd_fail;
156     }
157
158     /* figure out the key. use rbuf as a temporary buffer. */
159     i = DH_compute_key(rbuf, bn, dh);
160     
161     /* set the key */
162     CAST_set_key(&castkey, i, rbuf);
163     
164     /* session id. it's just a hashed version of the object pointer. */
165     sessid = dhxhash(obj);
166     memcpy(rbuf, &sessid, sizeof(sessid));
167     rbuf += sizeof(sessid);
168     *rbuflen += sizeof(sessid);
169     
170     /* send our public key */
171     BN_bn2bin(dh->pub_key, rbuf); 
172     rbuf += KEYSIZE;
173     *rbuflen += KEYSIZE;
174
175     /* buffer to be encrypted */
176     i = sizeof(randbuf);
177     if (uam_afpserver_option(obj, UAM_OPTION_RANDNUM, (void *) randbuf,
178                              &i) < 0) {
179       *rbuflen = 0;
180       goto passwd_fail;
181     }    
182     memcpy(rbuf, &randbuf, sizeof(randbuf));
183
184 #if 0
185     /* get the signature. it's always 16 bytes. */
186     if (uam_afpserver_option(obj, UAM_OPTION_SIGNATURE, 
187                              (void *) &name, NULL) < 0) {
188       *rbuflen = 0;
189       goto passwd_fail;
190     }
191     memcpy(rbuf + KEYSIZE, name, KEYSIZE); 
192 #else
193     memset(rbuf + KEYSIZE, 0, KEYSIZE);
194 #endif
195
196     /* encrypt using cast */
197     CAST_cbc_encrypt(rbuf, rbuf, CRYPTBUFLEN, &castkey, iv, CAST_ENCRYPT);
198     *rbuflen += CRYPTBUFLEN;
199     BN_free(bn);
200     DH_free(dh);
201     return AFPERR_AUTHCONT;
202
203 passwd_fail:
204     BN_free(bn);
205     DH_free(dh);
206     return AFPERR_PARAM;
207 }
208
209 static int passwd_logincont(void *obj, struct passwd **uam_pwd,
210                             char *ibuf, int ibuflen, 
211                             char *rbuf, int *rbuflen)
212 {
213     unsigned char iv[] = "LWallace";
214     BIGNUM *bn1, *bn2, *bn3;
215     u_int16_t sessid;
216     char *p;
217
218     *rbuflen = 0;
219
220     /* check for session id */
221     memcpy(&sessid, ibuf, sizeof(sessid));
222     if (sessid != dhxhash(obj))
223       return AFPERR_PARAM;
224     ibuf += sizeof(sessid);
225    
226     /* use rbuf as scratch space */
227     CAST_cbc_encrypt(ibuf, rbuf, CRYPT2BUFLEN, &castkey,
228                      iv, CAST_DECRYPT);
229     
230     /* check to make sure that the random number is the same. we
231      * get sent back an incremented random number. */
232     if (!(bn1 = BN_bin2bn(rbuf, KEYSIZE, NULL)))
233       return AFPERR_PARAM;
234
235     if (!(bn2 = BN_bin2bn(randbuf, sizeof(randbuf), NULL))) {
236       BN_free(bn1);
237       return AFPERR_PARAM;
238     }
239       
240     /* zero out the random number */
241     memset(rbuf, 0, sizeof(randbuf));
242     memset(randbuf, 0, sizeof(randbuf));
243     rbuf += KEYSIZE;
244
245     if (!(bn3 = BN_new())) {
246       BN_free(bn2);
247       BN_free(bn1);
248       return AFPERR_PARAM;
249     }
250
251     BN_sub(bn3, bn1, bn2);
252     BN_free(bn2);
253     BN_free(bn1);
254
255     /* okay. is it one more? */
256     if (!BN_is_one(bn3)) {
257       BN_free(bn3);
258       return AFPERR_PARAM;
259     }
260     BN_free(bn3);
261
262     rbuf[PASSWDLEN] = '\0';
263 #ifdef TRU64
264     if ( c2security == 1 ) {
265         struct pr_passwd *pr = getprpwnam( dhxpwd->pw_name );
266         if ( pr == NULL )
267             return AFPERR_NOTAUTH;
268         if ( strcmp( dispcrypt( rbuf, pr->ufld.fd_encrypt,
269             pr->ufld.fd_oldcrypt ), pr->ufld.fd_encrypt ) == 0 ) {
270             *uam_pwd = dhxpwd;
271             return AFP_OK;
272         }
273     } else {
274         p = crypt( rbuf, dhxpwd->pw_passwd );
275         memset(rbuf, 0, PASSWDLEN);
276         if ( strcmp( p, dhxpwd->pw_passwd ) == 0 ) {
277             *uam_pwd = dhxpwd;
278             return AFP_OK;
279         }
280     }
281 #else /* TRU64 */
282     p = crypt( rbuf, dhxpwd->pw_passwd );
283     memset(rbuf, 0, PASSWDLEN);
284     if ( strcmp( p, dhxpwd->pw_passwd ) == 0 ) {
285       *uam_pwd = dhxpwd;
286       return AFP_OK;
287     }
288 #endif /* TRU64 */
289
290     return AFPERR_NOTAUTH;
291 }
292
293
294 static int uam_setup(const char *path)
295 {
296 #ifdef TRU64
297     FILE *f;
298     char buf[256];
299     char siad[] = "siad_ses_init=";
300
301     if ( access( SIAIGOODFILE, F_OK ) == -1 ) {
302         syslog( LOG_ERR, "dhx uam_setup: %s does not exist",
303             SIAIGOODFILE);
304         return -1;
305     }
306
307     if ( ( f = fopen(MATRIX_CONF, "r" ) ) == NULL ) {
308         syslog( LOG_ERR, "dhx uam_setup: %s is unreadable",
309             MATRIX_CONF );
310         return -1;
311     }
312
313     while ( fgets( buf, sizeof(buf), f ) != NULL ) {
314         if ( strncmp( buf, siad, sizeof(siad) - 1 ) == 0 ) {
315             if ( strstr( buf, "OSFC2" ) != NULL )
316                 c2security = 1;
317             break;
318         }
319     }
320
321     fclose(f);
322
323     syslog( LOG_INFO, "dhx uam_setup: security level %s",
324         c2security == 0 ? "BSD" : "OSFC2" );
325 #endif /* TRU64 */
326
327   if (uam_register(UAM_SERVER_LOGIN, path, "DHCAST128",
328                    passwd_login, passwd_logincont, NULL) < 0)
329     return -1;
330   /*uam_register(UAM_SERVER_PRINTAUTH, path, "DHCAST128",
331     passwd_printer);*/
332
333   return 0;
334 }
335
336 static void uam_cleanup(void)
337 {
338   uam_unregister(UAM_SERVER_LOGIN, "DHCAST128");
339   /*uam_unregister(UAM_SERVER_PRINTAUTH, "DHCAST128"); */
340 }
341
342 UAM_MODULE_EXPORT struct uam_export uams_dhx = {
343   UAM_MODULE_SERVER,
344   UAM_MODULE_VERSION,
345   uam_setup, uam_cleanup
346 };
347 #endif