2 * Copyright (c) 1990,1993 Regents of The University of Michigan.
3 * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu)
4 * All Rights Reserved. See COPYRIGHT.
9 #endif /* HAVE_CONFIG_H */
12 #define _XOPEN_SOURCE 500 /* for crypt() */
15 #define _XOPEN_SOURCE /* for crypt() */
24 #endif /* ! HAVE_CRYPT_H */
28 #include <arpa/inet.h>
34 #if defined(GNUTLS_DHX)
35 #include <gnutls/openssl.h>
36 #elif defined(OPENSSL_DHX)
37 #include <openssl/bn.h>
38 #include <openssl/dh.h>
39 #include <openssl/cast.h>
40 #else /* OPENSSL_DHX */
44 #endif /* OPENSSL_DHX */
46 #include <atalk/logger.h>
47 #include <atalk/afp.h>
48 #include <atalk/uam.h>
52 #define CRYPTBUFLEN (KEYSIZE*2)
53 #define CRYPT2BUFLEN (KEYSIZE + PASSWDLEN)
55 /* hash a number to a 16-bit quantity */
56 #define dhxhash(a) ((((unsigned long) (a) >> 8) ^ \
57 (unsigned long) (a)) & 0xffff)
60 static CAST_KEY castkey;
61 static struct passwd *dhxpwd;
62 static u_int8_t randbuf[16];
68 static const char *clientname;
72 static int pwd_login(void *obj, char *username, int ulen, struct passwd **uam_pwd _U_,
73 char *ibuf, size_t ibuflen _U_,
74 char *rbuf, size_t *rbuflen)
76 unsigned char iv[] = "CJalbert";
77 u_int8_t p[] = {0xBA, 0x28, 0x73, 0xDF, 0xB0, 0x60, 0x57, 0xD4,
78 0x3F, 0x20, 0x24, 0x74, 0x4C, 0xEE, 0xE7, 0x5B };
83 BIGNUM *bn, *gbn, *pbn;
90 for (i = 0; i < 256; i++)
91 rnd_seed[i] = random();
92 RAND_seed(rnd_seed, sizeof(rnd_seed));
98 if( uam_afpserver_option( obj, UAM_OPTION_CLIENTNAME,
99 (void *) &clientname, NULL ) < 0 )
103 if (( dhxpwd = uam_getname(obj, username, ulen)) == NULL ) {
104 return AFPERR_NOTAUTH;
107 LOG(log_info, logtype_uams, "dhx login: %s", username);
108 if (uam_checkuser(dhxpwd) < 0)
109 return AFPERR_NOTAUTH;
112 if (( sp = getspnam( dhxpwd->pw_name )) == NULL ) {
113 LOG(log_info, logtype_uams, "no shadow passwd entry for %s", username);
114 return AFPERR_NOTAUTH;
116 dhxpwd->pw_passwd = sp->sp_pwdp;
117 #endif /* SHADOWPW */
119 if (!dhxpwd->pw_passwd)
120 return AFPERR_NOTAUTH;
122 /* get the client's public key */
123 if (!(bn = BN_bin2bn((unsigned char *)ibuf, KEYSIZE, NULL))) {
128 if (!(gbn = BN_bin2bn(&g, sizeof(g), NULL))) {
133 if (!(pbn = BN_bin2bn(p, sizeof(p), NULL))) {
139 /* okay, we're ready */
140 if (!(dh = DH_new())) {
147 /* generate key and make sure we have enough space */
150 if (!DH_generate_key(dh) || (BN_num_bytes(dh->pub_key) > KEYSIZE)) {
154 /* figure out the key. use rbuf as a temporary buffer. */
155 i = DH_compute_key((unsigned char *)rbuf, bn, dh);
158 CAST_set_key(&castkey, i, (unsigned char *)rbuf);
160 /* session id. it's just a hashed version of the object pointer. */
161 sessid = dhxhash(obj);
162 memcpy(rbuf, &sessid, sizeof(sessid));
163 rbuf += sizeof(sessid);
164 *rbuflen += sizeof(sessid);
166 /* send our public key */
167 BN_bn2bin(dh->pub_key, (unsigned char *)rbuf);
171 /* buffer to be encrypted */
173 if (uam_afpserver_option(obj, UAM_OPTION_RANDNUM, (void *) randbuf,
178 memcpy(rbuf, &randbuf, sizeof(randbuf));
181 /* get the signature. it's always 16 bytes. */
182 if (uam_afpserver_option(obj, UAM_OPTION_SIGNATURE,
183 (void *) &name, NULL) < 0) {
187 memcpy(rbuf + KEYSIZE, name, KEYSIZE);
189 memset(rbuf + KEYSIZE, 0, KEYSIZE);
192 /* encrypt using cast */
193 CAST_cbc_encrypt((unsigned char *)rbuf, (unsigned char *)rbuf, CRYPTBUFLEN, &castkey, iv, CAST_ENCRYPT);
194 *rbuflen += CRYPTBUFLEN;
197 return AFPERR_AUTHCONT;
206 static int passwd_login(void *obj, struct passwd **uam_pwd,
207 char *ibuf, size_t ibuflen,
208 char *rbuf, size_t *rbuflen)
215 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME,
216 (void *) &username, &ulen) < 0)
220 return( AFPERR_PARAM );
223 len = (unsigned char) *ibuf++;
225 if (!len || len > ibuflen || len > ulen ) {
226 return( AFPERR_PARAM );
228 memcpy(username, ibuf, len );
231 username[ len ] = '\0';
233 if ((unsigned long) ibuf & 1) { /* pad character */
237 return (pwd_login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
241 /* cleartxt login ext
244 2 bytes len (network order)
247 static int passwd_login_ext(void *obj, char *uname, struct passwd **uam_pwd,
248 char *ibuf, size_t ibuflen,
249 char *rbuf, size_t *rbuflen)
257 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME,
258 (void *) &username, &ulen) < 0)
264 memcpy(&temp16, uname, sizeof(temp16));
266 if (!len || len > ulen ) {
267 return( AFPERR_PARAM );
269 memcpy(username, uname +2, len );
270 username[ len ] = '\0';
271 return (pwd_login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
274 static int passwd_logincont(void *obj, struct passwd **uam_pwd,
275 char *ibuf, size_t ibuflen _U_,
276 char *rbuf, size_t *rbuflen)
280 #endif /* SHADOWPW */
281 unsigned char iv[] = "LWallace";
282 BIGNUM *bn1, *bn2, *bn3;
285 int err = AFPERR_NOTAUTH;
289 /* check for session id */
290 memcpy(&sessid, ibuf, sizeof(sessid));
291 if (sessid != dhxhash(obj))
293 ibuf += sizeof(sessid);
295 /* use rbuf as scratch space */
296 CAST_cbc_encrypt((unsigned char *)ibuf, (unsigned char *)rbuf, CRYPT2BUFLEN, &castkey,
299 /* check to make sure that the random number is the same. we
300 * get sent back an incremented random number. */
301 if (!(bn1 = BN_bin2bn((unsigned char *)rbuf, KEYSIZE, NULL)))
304 if (!(bn2 = BN_bin2bn(randbuf, sizeof(randbuf), NULL))) {
309 /* zero out the random number */
310 memset(rbuf, 0, sizeof(randbuf));
311 memset(randbuf, 0, sizeof(randbuf));
314 if (!(bn3 = BN_new())) {
320 BN_sub(bn3, bn1, bn2);
324 /* okay. is it one more? */
325 if (!BN_is_one(bn3)) {
331 rbuf[PASSWDLEN] = '\0';
338 uam_afp_getcmdline( &ac, &av );
339 sprintf( hostname, "%s@%s", dhxpwd->pw_name, clientname );
341 if( uam_sia_validate_user( NULL, ac, av, hostname, dhxpwd->pw_name,
342 NULL, FALSE, NULL, rbuf ) != SIASUCCESS )
343 return AFPERR_NOTAUTH;
345 memset( rbuf, 0, PASSWDLEN );
350 p = crypt( rbuf, dhxpwd->pw_passwd );
351 memset(rbuf, 0, PASSWDLEN);
352 if ( strcmp( p, dhxpwd->pw_passwd ) == 0 ) {
357 if (( sp = getspnam( dhxpwd->pw_name )) == NULL ) {
358 LOG(log_info, logtype_uams, "no shadow passwd entry for %s", dhxpwd->pw_name);
359 return (AFPERR_NOTAUTH);
362 /* check for expired password */
363 if (sp && sp->sp_max != -1 && sp->sp_lstchg) {
364 time_t now = time(NULL) / (60*60*24);
365 int32_t expire_days = sp->sp_lstchg - now + sp->sp_max;
366 if ( expire_days < 0 ) {
367 LOG(log_info, logtype_uams, "password for user %s expired", dhxpwd->pw_name);
368 err = AFPERR_PWDEXPR;
371 #endif /* SHADOWPW */
375 return AFPERR_NOTAUTH;
379 static int uam_setup(const char *path)
381 if (uam_register(UAM_SERVER_LOGIN_EXT, path, "DHCAST128",
382 passwd_login, passwd_logincont, NULL, passwd_login_ext) < 0)
384 /*uam_register(UAM_SERVER_PRINTAUTH, path, "DHCAST128",
390 static void uam_cleanup(void)
392 uam_unregister(UAM_SERVER_LOGIN, "DHCAST128");
393 /*uam_unregister(UAM_SERVER_PRINTAUTH, "DHCAST128"); */
396 UAM_MODULE_EXPORT struct uam_export uams_dhx = {
399 uam_setup, uam_cleanup
402 UAM_MODULE_EXPORT struct uam_export uams_dhx_passwd = {
405 uam_setup, uam_cleanup