1/* 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. 5 */ 6 7#ifdef HAVE_CONFIG_H 8#include "config.h" 9#endif /* HAVE_CONFIG_H */ 10 11#include <atalk/standards.h> 12 13#include <stdio.h> 14#include <stdlib.h> 15#include <string.h> 16#include <unistd.h> 17#ifdef HAVE_CRYPT_H 18#include <crypt.h> 19#endif /* ! HAVE_CRYPT_H */ 20#include <sys/time.h> 21#include <time.h> 22#include <pwd.h> 23#include <arpa/inet.h> 24 25#ifdef SHADOWPW 26#include <shadow.h> 27#endif /* SHADOWPW */ 28 29#if defined(GNUTLS_DHX) 30#include <gnutls/openssl.h> 31#elif defined(OPENSSL_DHX) 32#include <openssl/bn.h> 33#include <openssl/dh.h> 34#include <openssl/cast.h> 35#else /* OPENSSL_DHX */ 36#include <bn.h> 37#include <dh.h> 38#include <cast.h> 39#endif /* OPENSSL_DHX */ 40 41#include <atalk/logger.h> 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 */ 55static CAST_KEY castkey; 56static struct passwd *dhxpwd; 57static uint8_t randbuf[16]; 58 59#ifdef TRU64 60#include <sia.h> 61#include <siad.h> 62 63static const char *clientname; 64#endif /* TRU64 */ 65 66/* dhx passwd */ 67static int pwd_login(void *obj, char *username, int ulen, struct passwd **uam_pwd _U_, 68 char *ibuf, size_t ibuflen _U_, 69 char *rbuf, size_t *rbuflen) 70{ 71 unsigned char iv[] = "CJalbert"; 72 uint8_t p[] = {0xBA, 0x28, 0x73, 0xDF, 0xB0, 0x60, 0x57, 0xD4, 73 0x3F, 0x20, 0x24, 0x74, 0x4C, 0xEE, 0xE7, 0x5B }; 74 uint8_t g = 0x07; 75#ifdef SHADOWPW 76 struct spwd *sp; 77#endif /* SHADOWPW */ 78 BIGNUM *bn, *gbn, *pbn; 79 uint16_t sessid; 80 size_t i; 81 DH *dh; 82 83#ifdef TRU64 84 int rnd_seed[256]; 85 for (i = 0; i < 256; i++) 86 rnd_seed[i] = random(); 87 RAND_seed(rnd_seed, sizeof(rnd_seed)); 88#endif /* TRU64 */ 89 90 *rbuflen = 0; 91 92#ifdef TRU64 93 if( uam_afpserver_option( obj, UAM_OPTION_CLIENTNAME, 94 (void *) &clientname, NULL ) < 0 ) 95 return AFPERR_PARAM; 96#endif /* TRU64 */ 97 98 if (( dhxpwd = uam_getname(obj, username, ulen)) == NULL ) { 99 return AFPERR_NOTAUTH; 100 } 101 102 LOG(log_info, logtype_uams, "dhx login: %s", username); 103 if (uam_checkuser(dhxpwd) < 0) 104 return AFPERR_NOTAUTH; 105 106#ifdef SHADOWPW 107 if (( sp = getspnam( dhxpwd->pw_name )) == NULL ) { 108 LOG(log_info, logtype_uams, "no shadow passwd entry for %s", username); 109 return AFPERR_NOTAUTH; 110 } 111 dhxpwd->pw_passwd = sp->sp_pwdp; 112#endif /* SHADOWPW */ 113 114 if (!dhxpwd->pw_passwd) 115 return AFPERR_NOTAUTH; 116 117 /* get the client's public key */ 118 if (!(bn = BN_bin2bn((unsigned char *)ibuf, KEYSIZE, NULL))) { 119 return AFPERR_PARAM; 120 } 121 122 /* get our primes */ 123 if (!(gbn = BN_bin2bn(&g, sizeof(g), NULL))) { 124 BN_free(bn); 125 return AFPERR_PARAM; 126 } 127 128 if (!(pbn = BN_bin2bn(p, sizeof(p), NULL))) { 129 BN_free(gbn); 130 BN_free(bn); 131 return AFPERR_PARAM; 132 } 133 134 /* okay, we're ready */ 135 if (!(dh = DH_new())) { 136 BN_free(pbn); 137 BN_free(gbn); 138 BN_free(bn); 139 return AFPERR_PARAM; 140 } 141 142 /* generate key and make sure we have enough space */ 143 dh->p = pbn; 144 dh->g = gbn; 145 if (!DH_generate_key(dh) || (BN_num_bytes(dh->pub_key) > KEYSIZE)) { 146 goto passwd_fail; 147 } 148 149 /* figure out the key. use rbuf as a temporary buffer. */ 150 i = DH_compute_key((unsigned char *)rbuf, bn, dh); 151 152 /* set the key */ 153 CAST_set_key(&castkey, i, (unsigned char *)rbuf); 154 155 /* session id. it's just a hashed version of the object pointer. */ 156 sessid = dhxhash(obj); 157 memcpy(rbuf, &sessid, sizeof(sessid)); 158 rbuf += sizeof(sessid); 159 *rbuflen += sizeof(sessid); 160 161 /* send our public key */ 162 BN_bn2bin(dh->pub_key, (unsigned char *)rbuf); 163 rbuf += KEYSIZE; 164 *rbuflen += KEYSIZE; 165 166 /* buffer to be encrypted */ 167 i = sizeof(randbuf); 168 if (uam_afpserver_option(obj, UAM_OPTION_RANDNUM, (void *) randbuf, 169 &i) < 0) { 170 *rbuflen = 0; 171 goto passwd_fail; 172 } 173 memcpy(rbuf, &randbuf, sizeof(randbuf)); 174 175#if 0 176 /* get the signature. it's always 16 bytes. */ 177 if (uam_afpserver_option(obj, UAM_OPTION_SIGNATURE, 178 (void *) &name, NULL) < 0) { 179 *rbuflen = 0; 180 goto passwd_fail; 181 } 182 memcpy(rbuf + KEYSIZE, name, KEYSIZE); 183#else /* 0 */ 184 memset(rbuf + KEYSIZE, 0, KEYSIZE); 185#endif /* 0 */ 186 187 /* encrypt using cast */ 188 CAST_cbc_encrypt((unsigned char *)rbuf, (unsigned char *)rbuf, CRYPTBUFLEN, &castkey, iv, CAST_ENCRYPT); 189 *rbuflen += CRYPTBUFLEN; 190 BN_free(bn); 191 DH_free(dh); 192 return AFPERR_AUTHCONT; 193 194passwd_fail: 195 BN_free(bn); 196 DH_free(dh); 197 return AFPERR_PARAM; 198} 199 200/* cleartxt login */ 201static int passwd_login(void *obj, struct passwd **uam_pwd, 202 char *ibuf, size_t ibuflen, 203 char *rbuf, size_t *rbuflen) 204{ 205 char *username; 206 size_t len, ulen; 207 208 *rbuflen = 0; 209 210 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, 211 (void *) &username, &ulen) < 0) 212 return AFPERR_MISC; 213 214 if (ibuflen < 2) { 215 return( AFPERR_PARAM ); 216 } 217 218 len = (unsigned char) *ibuf++; 219 ibuflen--; 220 if (!len || len > ibuflen || len > ulen ) { 221 return( AFPERR_PARAM ); 222 } 223 memcpy(username, ibuf, len ); 224 ibuf += len; 225 ibuflen -=len; 226 username[ len ] = '\0'; 227 228 if ((unsigned long) ibuf & 1) { /* pad character */ 229 ++ibuf; 230 ibuflen--; 231 } 232 return (pwd_login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen)); 233 234} 235 236/* cleartxt login ext 237 * uname format : 238 byte 3 239 2 bytes len (network order) 240 len bytes utf8 name 241*/ 242static int passwd_login_ext(void *obj, char *uname, struct passwd **uam_pwd, 243 char *ibuf, size_t ibuflen, 244 char *rbuf, size_t *rbuflen) 245{ 246 char *username; 247 size_t len, ulen; 248 uint16_t temp16; 249 250 *rbuflen = 0; 251 252 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, 253 (void *) &username, &ulen) < 0) 254 return AFPERR_MISC; 255 256 if (*uname != 3) 257 return AFPERR_PARAM; 258 uname++; 259 memcpy(&temp16, uname, sizeof(temp16)); 260 len = ntohs(temp16); 261 if (!len || len > ulen ) { 262 return( AFPERR_PARAM ); 263 } 264 memcpy(username, uname +2, len ); 265 username[ len ] = '\0'; 266 return (pwd_login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen)); 267} 268 269static int passwd_logincont(void *obj, struct passwd **uam_pwd, 270 char *ibuf, size_t ibuflen _U_, 271 char *rbuf, size_t *rbuflen) 272{ 273#ifdef SHADOWPW 274 struct spwd *sp; 275#endif /* SHADOWPW */ 276 unsigned char iv[] = "LWallace"; 277 BIGNUM *bn1, *bn2, *bn3; 278 uint16_t sessid; 279 char *p; 280 int err = AFPERR_NOTAUTH; 281 282 *rbuflen = 0; 283 284 /* check for session id */ 285 memcpy(&sessid, ibuf, sizeof(sessid)); 286 if (sessid != dhxhash(obj)) 287 return AFPERR_PARAM; 288 ibuf += sizeof(sessid); 289 290 /* use rbuf as scratch space */ 291 CAST_cbc_encrypt((unsigned char *)ibuf, (unsigned char *)rbuf, CRYPT2BUFLEN, &castkey, 292 iv, CAST_DECRYPT); 293 294 /* check to make sure that the random number is the same. we 295 * get sent back an incremented random number. */ 296 if (!(bn1 = BN_bin2bn((unsigned char *)rbuf, KEYSIZE, NULL))) 297 return AFPERR_PARAM; 298 299 if (!(bn2 = BN_bin2bn(randbuf, sizeof(randbuf), NULL))) { 300 BN_free(bn1); 301 return AFPERR_PARAM; 302 } 303 304 /* zero out the random number */ 305 memset(rbuf, 0, sizeof(randbuf)); 306 memset(randbuf, 0, sizeof(randbuf)); 307 rbuf += KEYSIZE; 308 309 if (!(bn3 = BN_new())) { 310 BN_free(bn2); 311 BN_free(bn1); 312 return AFPERR_PARAM; 313 } 314 315 BN_sub(bn3, bn1, bn2); 316 BN_free(bn2); 317 BN_free(bn1); 318 319 /* okay. is it one more? */ 320 if (!BN_is_one(bn3)) { 321 BN_free(bn3); 322 return AFPERR_PARAM; 323 } 324 BN_free(bn3); 325 326 rbuf[PASSWDLEN] = '\0'; 327#ifdef TRU64 328 { 329 int ac; 330 char **av; 331 char hostname[256]; 332 333 uam_afp_getcmdline( &ac, &av ); 334 sprintf( hostname, "%s@%s", dhxpwd->pw_name, clientname ); 335 336 if( uam_sia_validate_user( NULL, ac, av, hostname, dhxpwd->pw_name, 337 NULL, FALSE, NULL, rbuf ) != SIASUCCESS ) 338 return AFPERR_NOTAUTH; 339 340 memset( rbuf, 0, PASSWDLEN ); 341 *uam_pwd = dhxpwd; 342 return AFP_OK; 343 } 344#else /* TRU64 */ 345 p = crypt( rbuf, dhxpwd->pw_passwd ); 346 memset(rbuf, 0, PASSWDLEN); 347 if ( strcmp( p, dhxpwd->pw_passwd ) == 0 ) { 348 *uam_pwd = dhxpwd; 349 err = AFP_OK; 350 } 351#ifdef SHADOWPW 352 if (( sp = getspnam( dhxpwd->pw_name )) == NULL ) { 353 LOG(log_info, logtype_uams, "no shadow passwd entry for %s", dhxpwd->pw_name); 354 return (AFPERR_NOTAUTH); 355 } 356 357 /* check for expired password */ 358 if (sp && sp->sp_max != -1 && sp->sp_lstchg) { 359 time_t now = time(NULL) / (60*60*24); 360 int32_t expire_days = sp->sp_lstchg - now + sp->sp_max; 361 if ( expire_days < 0 ) { 362 LOG(log_info, logtype_uams, "password for user %s expired", dhxpwd->pw_name); 363 err = AFPERR_PWDEXPR; 364 } 365 } 366#endif /* SHADOWPW */ 367 return err; 368#endif /* TRU64 */ 369 370 return AFPERR_NOTAUTH; 371} 372 373 374static int uam_setup(const char *path) 375{ 376 if (uam_register(UAM_SERVER_LOGIN_EXT, path, "DHCAST128", 377 passwd_login, passwd_logincont, NULL, passwd_login_ext) < 0) 378 return -1; 379 /*uam_register(UAM_SERVER_PRINTAUTH, path, "DHCAST128", 380 passwd_printer);*/ 381 382 return 0; 383} 384 385static void uam_cleanup(void) 386{ 387 uam_unregister(UAM_SERVER_LOGIN, "DHCAST128"); 388 /*uam_unregister(UAM_SERVER_PRINTAUTH, "DHCAST128"); */ 389} 390 391UAM_MODULE_EXPORT struct uam_export uams_dhx = { 392 UAM_MODULE_SERVER, 393 UAM_MODULE_VERSION, 394 uam_setup, uam_cleanup 395}; 396 397UAM_MODULE_EXPORT struct uam_export uams_dhx_passwd = { 398 UAM_MODULE_SERVER, 399 UAM_MODULE_VERSION, 400 uam_setup, uam_cleanup 401}; 402