2 * $Id: uams_dhx_passwd.c,v 1.19 2003-06-11 07:16:14 srittau Exp $
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.
9 #define _XOPEN_SOURCE /* for crypt() */
13 #endif /* HAVE_CONFIG_H */
20 #endif /* HAVE_UNISTD_H */
23 #endif /* ! NO_CRYPT_H */
25 #include <atalk/logger.h>
31 #if defined(GNUTLS_DHX)
32 #include <gnutls/openssl.h>
33 #elif defined(OPENSSL_DHX)
34 #include <openssl/bn.h>
35 #include <openssl/dh.h>
36 #include <openssl/cast.h>
37 #else /* OPENSSL_DHX */
41 #endif /* OPENSSL_DHX */
43 #include <atalk/afp.h>
44 #include <atalk/uam.h>
48 #define CRYPTBUFLEN (KEYSIZE*2)
49 #define CRYPT2BUFLEN (KEYSIZE + PASSWDLEN)
51 /* hash a number to a 16-bit quantity */
52 #define dhxhash(a) ((((unsigned long) (a) >> 8) ^ \
53 (unsigned long) (a)) & 0xffff)
56 static CAST_KEY castkey;
57 static struct passwd *dhxpwd;
58 static u_int8_t randbuf[16];
64 static char *clientname;
68 static int pwd_login(void *obj, char *username, int ulen, struct passwd **uam_pwd,
69 char *ibuf, int ibuflen,
70 char *rbuf, int *rbuflen)
72 unsigned char iv[] = "CJalbert";
73 u_int8_t p[] = {0xBA, 0x28, 0x73, 0xDF, 0xB0, 0x60, 0x57, 0xD4,
74 0x3F, 0x20, 0x24, 0x74, 0x4C, 0xEE, 0xE7, 0x5B };
79 BIGNUM *bn, *gbn, *pbn;
88 static const char rnd_seed[] = "string to make the random number generator think it has entropy";
89 RAND_seed(rnd_seed, sizeof rnd_seed);
95 if( uam_afpserver_option( obj, UAM_OPTION_CLIENTNAME,
96 (void *) &clientname, NULL ) < 0 )
100 if (( dhxpwd = uam_getname(username, ulen)) == NULL ) {
104 LOG(log_info, logtype_uams, "dhx login: %s", username);
105 if (uam_checkuser(dhxpwd) < 0)
106 return AFPERR_NOTAUTH;
109 if (( sp = getspnam( dhxpwd->pw_name )) == NULL ) {
110 LOG(log_info, logtype_uams, "no shadow passwd entry for %s", username);
111 return AFPERR_NOTAUTH;
113 dhxpwd->pw_passwd = sp->sp_pwdp;
114 #endif /* SHADOWPW */
116 if (!dhxpwd->pw_passwd)
117 return AFPERR_NOTAUTH;
119 /* get the client's public key */
120 if (!(bn = BN_bin2bn(ibuf, KEYSIZE, NULL))) {
125 if (!(gbn = BN_bin2bn(&g, sizeof(g), NULL))) {
130 if (!(pbn = BN_bin2bn(p, sizeof(p), NULL))) {
136 /* okay, we're ready */
137 if (!(dh = DH_new())) {
144 /* generate key and make sure we have enough space */
147 if (!DH_generate_key(dh) || (BN_num_bytes(dh->pub_key) > KEYSIZE)) {
151 /* figure out the key. use rbuf as a temporary buffer. */
152 i = DH_compute_key(rbuf, bn, dh);
155 CAST_set_key(&castkey, i, rbuf);
157 /* session id. it's just a hashed version of the object pointer. */
158 sessid = dhxhash(obj);
159 memcpy(rbuf, &sessid, sizeof(sessid));
160 rbuf += sizeof(sessid);
161 *rbuflen += sizeof(sessid);
163 /* send our public key */
164 BN_bn2bin(dh->pub_key, rbuf);
168 /* buffer to be encrypted */
170 if (uam_afpserver_option(obj, UAM_OPTION_RANDNUM, (void *) randbuf,
175 memcpy(rbuf, &randbuf, sizeof(randbuf));
178 /* get the signature. it's always 16 bytes. */
179 if (uam_afpserver_option(obj, UAM_OPTION_SIGNATURE,
180 (void *) &name, NULL) < 0) {
184 memcpy(rbuf + KEYSIZE, name, KEYSIZE);
186 memset(rbuf + KEYSIZE, 0, KEYSIZE);
189 /* encrypt using cast */
190 CAST_cbc_encrypt(rbuf, rbuf, CRYPTBUFLEN, &castkey, iv, CAST_ENCRYPT);
191 *rbuflen += CRYPTBUFLEN;
194 return AFPERR_AUTHCONT;
203 static int passwd_login(void *obj, struct passwd **uam_pwd,
204 char *ibuf, int ibuflen,
205 char *rbuf, int *rbuflen)
212 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME,
213 (void *) &username, &ulen) < 0)
217 return( AFPERR_PARAM );
220 len = (unsigned char) *ibuf++;
222 if (!len || len > ibuflen || len > ulen ) {
223 return( AFPERR_PARAM );
225 memcpy(username, ibuf, len );
228 username[ len ] = '\0';
230 if ((unsigned long) ibuf & 1) { /* pad character */
234 return (pwd_login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
238 /* cleartxt login ext
241 2 bytes len (network order)
242 len bytes unicode name
244 static int passwd_login_ext(void *obj, char *uname, struct passwd **uam_pwd,
245 char *ibuf, int ibuflen,
246 char *rbuf, int *rbuflen)
254 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME,
255 (void *) &username, &ulen) < 0)
261 memcpy(&temp16, uname, sizeof(temp16));
263 if (!len || len > ulen ) {
264 return( AFPERR_PARAM );
266 memcpy(username, uname +2, len );
267 username[ len ] = '\0';
268 return (pwd_login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
271 static int passwd_logincont(void *obj, struct passwd **uam_pwd,
272 char *ibuf, int ibuflen,
273 char *rbuf, int *rbuflen)
275 unsigned char iv[] = "LWallace";
276 BIGNUM *bn1, *bn2, *bn3;
282 /* check for session id */
283 memcpy(&sessid, ibuf, sizeof(sessid));
284 if (sessid != dhxhash(obj))
286 ibuf += sizeof(sessid);
288 /* use rbuf as scratch space */
289 CAST_cbc_encrypt(ibuf, rbuf, CRYPT2BUFLEN, &castkey,
292 /* check to make sure that the random number is the same. we
293 * get sent back an incremented random number. */
294 if (!(bn1 = BN_bin2bn(rbuf, KEYSIZE, NULL)))
297 if (!(bn2 = BN_bin2bn(randbuf, sizeof(randbuf), NULL))) {
302 /* zero out the random number */
303 memset(rbuf, 0, sizeof(randbuf));
304 memset(randbuf, 0, sizeof(randbuf));
307 if (!(bn3 = BN_new())) {
313 BN_sub(bn3, bn1, bn2);
317 /* okay. is it one more? */
318 if (!BN_is_one(bn3)) {
324 rbuf[PASSWDLEN] = '\0';
331 uam_afp_getcmdline( &ac, &av );
332 sprintf( hostname, "%s@%s", dhxpwd->pw_name, clientname );
334 if( uam_sia_validate_user( NULL, ac, av, hostname, dhxpwd->pw_name,
335 NULL, FALSE, NULL, rbuf ) != SIASUCCESS )
336 return AFPERR_NOTAUTH;
338 memset( rbuf, 0, PASSWDLEN );
343 p = crypt( rbuf, dhxpwd->pw_passwd );
344 memset(rbuf, 0, PASSWDLEN);
345 if ( strcmp( p, dhxpwd->pw_passwd ) == 0 ) {
351 return AFPERR_NOTAUTH;
355 static int uam_setup(const char *path)
357 if (uam_register(UAM_SERVER_LOGIN_EXT, path, "DHCAST128",
358 passwd_login, passwd_logincont, NULL, passwd_login_ext) < 0)
360 /*uam_register(UAM_SERVER_PRINTAUTH, path, "DHCAST128",
366 static void uam_cleanup(void)
368 uam_unregister(UAM_SERVER_LOGIN, "DHCAST128");
369 /*uam_unregister(UAM_SERVER_PRINTAUTH, "DHCAST128"); */
372 UAM_MODULE_EXPORT struct uam_export uams_dhx = {
375 uam_setup, uam_cleanup