1/* 2 * $Id: uams_dhx_pam.c,v 1.33 2010-03-30 10:25:49 franklahm 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 /* HAVE_CONFIG_H */ 12 13#if defined(USE_PAM) && defined(UAM_DHX) 14#include <stdio.h> 15#include <stdlib.h> 16#include <string.h> 17#include <atalk/logger.h> 18 19#ifdef HAVE_UNISTD_H 20#include <unistd.h> 21#endif /* HAVE_UNISTD_H */ 22#include <errno.h> 23#ifdef HAVE_SECURITY_PAM_APPL_H 24#include <security/pam_appl.h> 25#endif 26#ifdef HAVE_PAM_PAM_APPL_H 27#include <pam/pam_appl.h> 28#endif 29 30 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#include <openssl/err.h> 38#else /* OPENSSL_DHX */ 39#include <bn.h> 40#include <dh.h> 41#include <cast.h> 42#include <err.h> 43#endif /* OPENSSL_DHX */ 44 45#include <atalk/afp.h> 46#include <atalk/uam.h> 47 48#define KEYSIZE 16 49#define PASSWDLEN 64 50#define CRYPTBUFLEN (KEYSIZE*2) 51#define CRYPT2BUFLEN (KEYSIZE + PASSWDLEN) 52#define CHANGEPWBUFLEN (KEYSIZE + 2*PASSWDLEN) 53 54/* hash a number to a 16-bit quantity */ 55#define dhxhash(a) ((((unsigned long) (a) >> 8) ^ \ 56 (unsigned long) (a)) & 0xffff) 57 58/* the secret key */ 59static CAST_KEY castkey; 60static struct passwd *dhxpwd; 61static u_int8_t randbuf[KEYSIZE]; 62 63/* diffie-hellman bits */ 64static unsigned char msg2_iv[] = "CJalbert"; 65static unsigned char msg3_iv[] = "LWallace"; 66static const u_int8_t p[] = {0xBA, 0x28, 0x73, 0xDF, 0xB0, 0x60, 0x57, 0xD4, 67 0x3F, 0x20, 0x24, 0x74, 0x4C, 0xEE, 0xE7, 0x5B}; 68static const u_int8_t g = 0x07; 69 70 71/* Static variables used to communicate between the conversation function 72 * and the server_login function 73 */ 74static pam_handle_t *pamh = NULL; 75static char *PAM_username; 76static char *PAM_password; 77 78/* PAM conversation function 79 * Here we assume (for now, at least) that echo on means login name, and 80 * echo off means password. 81 */ 82static int PAM_conv (int num_msg, 83 const struct pam_message **msg, 84 struct pam_response **resp, 85 void *appdata_ptr _U_) { 86 int count = 0; 87 struct pam_response *reply; 88 89#define COPY_STRING(s) (s) ? strdup(s) : NULL 90 91 errno = 0; 92 93 if (num_msg < 1) { 94 /* Log Entry */ 95 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM DHX Conversation Err -- %s", 96 strerror(errno)); 97 /* Log Entry */ 98 return PAM_CONV_ERR; 99 } 100 101 reply = (struct pam_response *) 102 calloc(num_msg, sizeof(struct pam_response)); 103 104 if (!reply) { 105 /* Log Entry */ 106 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM DHX Conversation Err -- %s", 107 strerror(errno)); 108 /* Log Entry */ 109 return PAM_CONV_ERR; 110 } 111 112 for (count = 0; count < num_msg; count++) { 113 char *string = NULL; 114 115 switch (msg[count]->msg_style) { 116 case PAM_PROMPT_ECHO_ON: 117 if (!(string = COPY_STRING(PAM_username))) { 118 /* Log Entry */ 119 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: username failure -- %s", 120 strerror(errno)); 121 /* Log Entry */ 122 goto pam_fail_conv; 123 } 124 break; 125 case PAM_PROMPT_ECHO_OFF: 126 if (!(string = COPY_STRING(PAM_password))) { 127 /* Log Entry */ 128 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: passwd failure: --: %s", 129 strerror(errno)); 130 /* Log Entry */ 131 goto pam_fail_conv; 132 } 133 break; 134 case PAM_TEXT_INFO: 135#ifdef PAM_BINARY_PROMPT 136 case PAM_BINARY_PROMPT: 137#endif /* PAM_BINARY_PROMPT */ 138 /* ignore it... */ 139 break; 140 case PAM_ERROR_MSG: 141 default: 142 /* Log Entry */ 143 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: Binary_Prompt -- %s", 144 strerror(errno)); 145 /* Log Entry */ 146 goto pam_fail_conv; 147 } 148 149 if (string) { 150 reply[count].resp_retcode = 0; 151 reply[count].resp = string; 152 string = NULL; 153 } 154 } 155 156 *resp = reply; 157 /* Log Entry */ 158 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: PAM Success"); 159 /* Log Entry */ 160 return PAM_SUCCESS; 161 162pam_fail_conv: 163 for (count = 0; count < num_msg; count++) { 164 if (!reply[count].resp) 165 continue; 166 switch (msg[count]->msg_style) { 167 case PAM_PROMPT_ECHO_OFF: 168 case PAM_PROMPT_ECHO_ON: 169 free(reply[count].resp); 170 break; 171 } 172 } 173 free(reply); 174 /* Log Entry */ 175 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM DHX Conversation Err -- %s", 176 strerror(errno)); 177 /* Log Entry */ 178 return PAM_CONV_ERR; 179} 180 181static struct pam_conv PAM_conversation = { 182 &PAM_conv, 183 NULL 184}; 185 186 187static int dhx_setup(void *obj, char *ibuf, size_t ibuflen _U_, 188 char *rbuf, size_t *rbuflen) 189{ 190 u_int16_t sessid; 191 size_t i; 192 BIGNUM *bn, *gbn, *pbn; 193 DH *dh; 194 195 /* get the client's public key */ 196 if (!(bn = BN_bin2bn(ibuf, KEYSIZE, NULL))) { 197 /* Log Entry */ 198 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM No Public Key -- %s", 199 strerror(errno)); 200 /* Log Entry */ 201 return AFPERR_PARAM; 202 } 203 204 /* get our primes */ 205 if (!(gbn = BN_bin2bn(&g, sizeof(g), NULL))) { 206 BN_clear_free(bn); 207 /* Log Entry */ 208 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM No Primes: GBN -- %s", 209 strerror(errno)); 210 /* Log Entry */ 211 return AFPERR_PARAM; 212 } 213 214 if (!(pbn = BN_bin2bn(p, sizeof(p), NULL))) { 215 BN_free(gbn); 216 BN_clear_free(bn); 217 /* Log Entry */ 218 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM No Primes: PBN -- %s", 219 strerror(errno)); 220 /* Log Entry */ 221 return AFPERR_PARAM; 222 } 223 224 /* okay, we're ready */ 225 if (!(dh = DH_new())) { 226 BN_free(pbn); 227 BN_free(gbn); 228 BN_clear_free(bn); 229 /* Log Entry */ 230 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM DH was equal to DH_New... Go figure... -- %s", 231 strerror(errno)); 232 /* Log Entry */ 233 return AFPERR_PARAM; 234 } 235 236 /* generate key and make sure that we have enough space */ 237 dh->p = pbn; 238 dh->g = gbn; 239 if (DH_generate_key(dh) == 0) { 240 unsigned long dherror; 241 char errbuf[256]; 242 243 ERR_load_crypto_strings(); 244 dherror = ERR_get_error(); 245 ERR_error_string_n(dherror, errbuf, 256); 246 247 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: Err Generating Key (OpenSSL error code: %u, %s)", dherror, errbuf); 248 249 ERR_free_strings(); 250 goto pam_fail; 251 } 252 if (BN_num_bytes(dh->pub_key) > KEYSIZE) { 253 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: Err Generating Key -- Not enough Space? -- %s", strerror(errno)); 254 goto pam_fail; 255 } 256 257 /* figure out the key. store the key in rbuf for now. */ 258 i = DH_compute_key(rbuf, bn, dh); 259 260 /* set the key */ 261 CAST_set_key(&castkey, i, rbuf); 262 263 /* session id. it's just a hashed version of the object pointer. */ 264 sessid = dhxhash(obj); 265 memcpy(rbuf, &sessid, sizeof(sessid)); 266 rbuf += sizeof(sessid); 267 *rbuflen += sizeof(sessid); 268 269 /* public key */ 270 BN_bn2bin(dh->pub_key, rbuf); 271 rbuf += KEYSIZE; 272 *rbuflen += KEYSIZE; 273 274 /* buffer to be encrypted */ 275 i = sizeof(randbuf); 276 if (uam_afpserver_option(obj, UAM_OPTION_RANDNUM, (void *) randbuf, 277 &i) < 0) { 278 *rbuflen = 0; 279 /* Log Entry */ 280 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: Buffer Encryption Err. -- %s", 281 strerror(errno)); 282 /* Log Entry */ 283 goto pam_fail; 284 } 285 memcpy(rbuf, &randbuf, sizeof(randbuf)); 286 287 /* get the signature. it's always 16 bytes. */ 288#if 0 289 if (uam_afpserver_option(obj, UAM_OPTION_SIGNATURE, 290 (void *) &buf, NULL) < 0) { 291 *rbuflen = 0; 292 /* Log Entry */ 293 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: Signature Retieval Failure -- %s", 294 strerror(errno)); 295 /* Log Entry */ 296 goto pam_fail; 297 } 298 memcpy(rbuf + KEYSIZE, buf, KEYSIZE); 299#else /* 0 */ 300 memset(rbuf + KEYSIZE, 0, KEYSIZE); 301#endif /* 0 */ 302 303 /* encrypt using cast */ 304 CAST_cbc_encrypt(rbuf, rbuf, CRYPTBUFLEN, &castkey, msg2_iv, 305 CAST_ENCRYPT); 306 *rbuflen += CRYPTBUFLEN; 307 BN_free(bn); 308 DH_free(dh); 309 return AFPERR_AUTHCONT; 310 311pam_fail: 312 BN_free(bn); 313 DH_free(dh); 314 /* Log Entry */ 315 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: Fail - Cast Encryption -- %s", 316 strerror(errno)); 317 /* Log Entry */ 318 return AFPERR_PARAM; 319} 320 321/* -------------------------------- */ 322static int login(void *obj, char *username, int ulen, struct passwd **uam_pwd _U_, 323 char *ibuf, size_t ibuflen, 324 char *rbuf, size_t *rbuflen) 325{ 326 if (( dhxpwd = uam_getname(obj, username, ulen)) == NULL ) { 327 LOG(log_info, logtype_uams, "uams_dhx_pam.c: unknown username [%s]", username); 328 return AFPERR_NOTAUTH; 329 } 330 331 PAM_username = username; 332 LOG(log_info, logtype_uams, "dhx login: %s", username); 333 return dhx_setup(obj, ibuf, ibuflen, rbuf, rbuflen); 334} 335 336/* -------------------------------- */ 337/* dhx login: things are done in a slightly bizarre order to avoid 338 * having to clean things up if there's an error. */ 339static int pam_login(void *obj, struct passwd **uam_pwd, 340 char *ibuf, size_t ibuflen, 341 char *rbuf, size_t *rbuflen) 342{ 343 char *username; 344 size_t len, ulen; 345 346 *rbuflen = 0; 347 348 /* grab some of the options */ 349 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, (void *) &username, &ulen) < 0) { 350 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: uam_afpserver_option didn't meet uam_option_username -- %s", 351 strerror(errno)); 352 return AFPERR_PARAM; 353 } 354 355 len = (unsigned char) *ibuf++; 356 if ( len > ulen ) { 357 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: Signature Retieval Failure -- %s", 358 strerror(errno)); 359 return AFPERR_PARAM; 360 } 361 362 memcpy(username, ibuf, len ); 363 ibuf += len; 364 username[ len ] = '\0'; 365 366 if ((unsigned long) ibuf & 1) /* pad to even boundary */ 367 ++ibuf; 368 369 return (login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen)); 370} 371 372/* ----------------------------- */ 373static int pam_login_ext(void *obj, char *uname, struct passwd **uam_pwd, 374 char *ibuf, size_t ibuflen, 375 char *rbuf, size_t *rbuflen) 376{ 377 char *username; 378 int len, ulen; 379 u_int16_t temp16; 380 381 *rbuflen = 0; 382 383 /* grab some of the options */ 384 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, (void *) &username, &ulen) < 0) { 385 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: uam_afpserver_option didn't meet uam_option_username -- %s", 386 strerror(errno)); 387 return AFPERR_PARAM; 388 } 389 390 if (*uname != 3) 391 return AFPERR_PARAM; 392 uname++; 393 memcpy(&temp16, uname, sizeof(temp16)); 394 len = ntohs(temp16); 395 396 if ( !len || len > ulen ) { 397 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: Signature Retrieval Failure -- %s", 398 strerror(errno)); 399 return AFPERR_PARAM; 400 } 401 memcpy(username, uname +2, len ); 402 username[ len ] = '\0'; 403 404 return (login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen)); 405} 406 407/* -------------------------------- */ 408 409static int pam_logincont(void *obj, struct passwd **uam_pwd, 410 char *ibuf, size_t ibuflen _U_, 411 char *rbuf, size_t *rbuflen) 412{ 413 const char *hostname; 414 BIGNUM *bn1, *bn2, *bn3; 415 u_int16_t sessid; 416 int err, PAM_error; 417 418 *rbuflen = 0; 419 420 /* check for session id */ 421 memcpy(&sessid, ibuf, sizeof(sessid)); 422 if (sessid != dhxhash(obj)) { 423 /* Log Entry */ 424 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM Session ID - DHXHash Mismatch -- %s", 425 strerror(errno)); 426 /* Log Entry */ 427 return AFPERR_PARAM; 428 } 429 ibuf += sizeof(sessid); 430 431 if (uam_afpserver_option(obj, UAM_OPTION_CLIENTNAME, 432 (void *) &hostname, NULL) < 0) 433 { 434 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: unable to retrieve client hostname"); 435 hostname = NULL; 436 } 437 438 CAST_cbc_encrypt(ibuf, rbuf, CRYPT2BUFLEN, &castkey, 439 msg3_iv, CAST_DECRYPT); 440 memset(&castkey, 0, sizeof(castkey)); 441 442 /* check to make sure that the random number is the same. we 443 * get sent back an incremented random number. */ 444 if (!(bn1 = BN_bin2bn(rbuf, KEYSIZE, NULL))) 445 return AFPERR_PARAM; 446 447 if (!(bn2 = BN_bin2bn(randbuf, sizeof(randbuf), NULL))) { 448 BN_free(bn1); 449 return AFPERR_PARAM; 450 } 451 452 /* zero out the random number */ 453 memset(rbuf, 0, sizeof(randbuf)); 454 memset(randbuf, 0, sizeof(randbuf)); 455 rbuf += KEYSIZE; 456 457 if (!(bn3 = BN_new())) { 458 BN_free(bn2); 459 BN_free(bn1); 460 return AFPERR_PARAM; 461 } 462 463 BN_sub(bn3, bn1, bn2); 464 BN_free(bn2); 465 BN_free(bn1); 466 467 /* okay. is it one more? */ 468 if (!BN_is_one(bn3)) { 469 BN_free(bn3); 470 return AFPERR_PARAM; 471 } 472 BN_free(bn3); 473 474 /* Set these things up for the conv function */ 475 rbuf[PASSWDLEN] = '\0'; 476 PAM_password = rbuf; 477 478 err = AFPERR_NOTAUTH; 479 PAM_error = pam_start("netatalk", PAM_username, &PAM_conversation, 480 &pamh); 481 if (PAM_error != PAM_SUCCESS) { 482 /* Log Entry */ 483 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: PAM_Error: %s", 484 pam_strerror(pamh,PAM_error)); 485 /* Log Entry */ 486 goto logincont_err; 487 } 488 489 /* solaris craps out if PAM_TTY and PAM_RHOST aren't set. */ 490 pam_set_item(pamh, PAM_TTY, "afpd"); 491 pam_set_item(pamh, PAM_RHOST, hostname); 492 PAM_error = pam_authenticate(pamh,0); 493 if (PAM_error != PAM_SUCCESS) { 494 if (PAM_error == PAM_MAXTRIES) 495 err = AFPERR_PWDEXPR; 496 /* Log Entry */ 497 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: PAM_Error: %s", 498 pam_strerror(pamh, PAM_error)); 499 /* Log Entry */ 500 goto logincont_err; 501 } 502 503 PAM_error = pam_acct_mgmt(pamh, 0); 504 if (PAM_error != PAM_SUCCESS ) { 505 /* Log Entry */ 506 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: PAM_Error: %s", 507 pam_strerror(pamh, PAM_error)); 508 /* Log Entry */ 509 if (PAM_error == PAM_NEW_AUTHTOK_REQD) /* password expired */ 510 err = AFPERR_PWDEXPR; 511#ifdef PAM_AUTHTOKEN_REQD 512 else if (PAM_error == PAM_AUTHTOKEN_REQD) 513 err = AFPERR_PWDCHNG; 514#endif 515 else 516 goto logincont_err; 517 } 518 519#ifndef PAM_CRED_ESTABLISH 520#define PAM_CRED_ESTABLISH PAM_ESTABLISH_CRED 521#endif 522 PAM_error = pam_setcred(pamh, PAM_CRED_ESTABLISH); 523 if (PAM_error != PAM_SUCCESS) { 524 /* Log Entry */ 525 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: PAM_Error: %s", 526 pam_strerror(pamh, PAM_error)); 527 /* Log Entry */ 528 goto logincont_err; 529 } 530 531 PAM_error = pam_open_session(pamh, 0); 532 if (PAM_error != PAM_SUCCESS) { 533 /* Log Entry */ 534 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: PAM_Error: %s", 535 pam_strerror(pamh, PAM_error)); 536 /* Log Entry */ 537 goto logincont_err; 538 } 539 540 memset(rbuf, 0, PASSWDLEN); /* zero out the password */ 541 *uam_pwd = dhxpwd; 542 /* Log Entry */ 543 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: PAM Auth OK!"); 544 /* Log Entry */ 545 if ( err == AFPERR_PWDEXPR) 546 return err; 547 return AFP_OK; 548 549logincont_err: 550 pam_end(pamh, PAM_error); 551 pamh = NULL; 552 memset(rbuf, 0, CRYPT2BUFLEN); 553 return err; 554} 555 556/* logout */ 557static void pam_logout(void) { 558 pam_close_session(pamh, 0); 559 pam_end(pamh, 0); 560 pamh = NULL; 561} 562 563 564/* change pw for dhx needs a couple passes to get everything all 565 * right. basically, it's like the login/logincont sequence */ 566static int pam_changepw(void *obj, char *username, 567 struct passwd *pwd _U_, char *ibuf, size_t ibuflen, 568 char *rbuf, size_t *rbuflen) 569{ 570 BIGNUM *bn1, *bn2, *bn3; 571 572 char *hostname; 573 pam_handle_t *lpamh; 574 uid_t uid; 575 u_int16_t sessid; 576 int PAM_error; 577 578 if (ibuflen < sizeof(sessid)) { 579 return AFPERR_PARAM; 580 } 581 582 /* grab the id */ 583 memcpy(&sessid, ibuf, sizeof(sessid)); 584 ibuf += sizeof(sessid); 585 586 if (!sessid) { /* no sessid -> initialization phase */ 587 PAM_username = username; 588 ibuflen -= sizeof(sessid); 589 return dhx_setup(obj, ibuf, ibuflen, rbuf, rbuflen); 590 } 591 592 593 /* otherwise, it's like logincont but different. */ 594 595 /* check out the session id */ 596 if (sessid != dhxhash(obj)) { 597 /* Log Entry */ 598 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: Session ID not Equal to DHX Hash -- %s", 599 strerror(errno)); 600 /* Log Entry */ 601 return AFPERR_PARAM; 602 } 603 604 /* we need this for pam */ 605 if (uam_afpserver_option(obj, UAM_OPTION_HOSTNAME, 606 (void *) &hostname, NULL) < 0) { 607 /* Log Entry */ 608 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: Hostname Null?? -- %s", 609 strerror(errno)); 610 /* Log Entry */ 611 return AFPERR_MISC; 612 } 613 614 /* grab the client's nonce, old password, and new password. */ 615 CAST_cbc_encrypt(ibuf, ibuf, CHANGEPWBUFLEN, &castkey, 616 msg3_iv, CAST_DECRYPT); 617 memset(&castkey, 0, sizeof(castkey)); 618 619 /* check to make sure that the random number is the same. we 620 * get sent back an incremented random number. */ 621 if (!(bn1 = BN_bin2bn(ibuf, KEYSIZE, NULL))) { 622 /* Log Entry */ 623 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: Random Number Not the same or not incremented-- %s", 624 strerror(errno)); 625 /* Log Entry */ 626 return AFPERR_PARAM; 627 } 628 629 if (!(bn2 = BN_bin2bn(randbuf, sizeof(randbuf), NULL))) { 630 BN_free(bn1); 631 /* Log Entry */ 632 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: Random Number Not the same or not incremented -- %s", 633 strerror(errno)); 634 /* Log Entry */ 635 return AFPERR_PARAM; 636 } 637 638 /* zero out the random number */ 639 memset(rbuf, 0, sizeof(randbuf)); 640 memset(randbuf, 0, sizeof(randbuf)); 641 642 if (!(bn3 = BN_new())) { 643 BN_free(bn2); 644 BN_free(bn1); 645 /* Log Entry */ 646 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: Random Number did not Zero -- %s", 647 strerror(errno)); 648 /* Log Entry */ 649 return AFPERR_PARAM; 650 } 651 652 BN_sub(bn3, bn1, bn2); 653 BN_free(bn2); 654 BN_free(bn1); 655 656 /* okay. is it one more? */ 657#if 0 658 if (!BN_is_one(bn3)) { 659 BN_free(bn3); 660 /* Log Entry */ 661 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: After Random Number not Zero, is it one more? -- %s", 662 strerror(errno)); 663 /* Log Entry */ 664 return AFPERR_PARAM; 665 } 666#endif 667 BN_free(bn3); 668 669 /* Set these things up for the conv function. the old password 670 * is at the end. */ 671 ibuf += KEYSIZE; 672 ibuf[PASSWDLEN + PASSWDLEN] = '\0'; 673 PAM_password = ibuf + PASSWDLEN; 674 675 PAM_error = pam_start("netatalk", username, &PAM_conversation, 676 &lpamh); 677 if (PAM_error != PAM_SUCCESS) { 678 /* Log Entry */ 679 LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: Needless to say, PAM_error is != to PAM_SUCCESS -- %s", 680 strerror(errno)); 681 /* Log Entry */ 682 return AFPERR_PARAM; 683 } 684 pam_set_item(lpamh, PAM_TTY, "afpd"); 685 pam_set_item(lpamh, PAM_RHOST, hostname); 686 687 /* we might need to do this as root */ 688 uid = geteuid(); 689 seteuid(0); 690 PAM_error = pam_authenticate(lpamh, 0); 691 if (PAM_error != PAM_SUCCESS) { 692 seteuid(uid); 693 pam_end(lpamh, PAM_error); 694 return AFPERR_NOTAUTH; 695 } 696 697 /* clear out old passwd */ 698 memset(ibuf + PASSWDLEN, 0, PASSWDLEN); 699 700 /* new password */ 701 PAM_password = ibuf; 702 ibuf[PASSWDLEN] = '\0'; 703 704 /* this really does need to be done as root */ 705 PAM_error = pam_chauthtok(lpamh, 0); 706 seteuid(uid); /* un-root ourselves. */ 707 memset(ibuf, 0, PASSWDLEN); 708 if (PAM_error != PAM_SUCCESS) { 709 pam_end(lpamh, PAM_error); 710 return AFPERR_ACCESS; 711 } 712 713 pam_end(lpamh, 0); 714 return AFP_OK; 715} 716 717 718static int uam_setup(const char *path) 719{ 720 if (uam_register(UAM_SERVER_LOGIN_EXT, path, "DHCAST128", pam_login, 721 pam_logincont, pam_logout, pam_login_ext) < 0) 722 return -1; 723 724 if (uam_register(UAM_SERVER_CHANGEPW, path, "DHCAST128", 725 pam_changepw) < 0) { 726 uam_unregister(UAM_SERVER_LOGIN, "DHCAST128"); 727 return -1; 728 } 729 730 /*uam_register(UAM_SERVER_PRINTAUTH, path, "DHCAST128", 731 pam_printer);*/ 732 733 return 0; 734} 735 736static void uam_cleanup(void) 737{ 738 uam_unregister(UAM_SERVER_LOGIN, "DHCAST128"); 739 uam_unregister(UAM_SERVER_CHANGEPW, "DHCAST128"); 740 /*uam_unregister(UAM_SERVER_PRINTAUTH, "DHCAST128"); */ 741} 742 743UAM_MODULE_EXPORT struct uam_export uams_dhx = { 744 UAM_MODULE_SERVER, 745 UAM_MODULE_VERSION, 746 uam_setup, uam_cleanup 747}; 748 749UAM_MODULE_EXPORT struct uam_export uams_dhx_pam = { 750 UAM_MODULE_SERVER, 751 UAM_MODULE_VERSION, 752 uam_setup, uam_cleanup 753}; 754 755#endif /* USE_PAM && UAM_DHX */ 756 757