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 */
11 #if defined (USE_PAM) && defined (UAM_DHX2)
15 #include <atalk/logger.h>
19 #endif /* HAVE_UNISTD_H */
21 #ifdef HAVE_SECURITY_PAM_APPL_H
22 #include <security/pam_appl.h>
24 #ifdef HAVE_PAM_PAM_APPL_H
25 #include <pam/pam_appl.h>
31 #endif /* HAVE_LIBGCRYPT */
33 #include <atalk/afp.h>
34 #include <atalk/uam.h>
35 #include "../afpd/globals.h"
37 /* Number of bits for p which we generate. Everybode out there uses 512, so we beet them */
38 #define PRIMEBITS 1024
40 /* hash a number to a 16-bit quantity */
41 #define dhxhash(a) ((((unsigned long) (a) >> 8) ^ \
42 (unsigned long) (a)) & 0xffff)
44 /* Some parameters need be maintained across calls */
45 static gcry_mpi_t p, g, Ra;
46 static gcry_mpi_t serverNonce;
47 static char *K_MD5hash = NULL;
48 static int K_hash_len;
51 /* The initialization vectors for CAST128 are fixed by Apple. */
52 static unsigned char dhx_c2siv[] = { 'L', 'W', 'a', 'l', 'l', 'a', 'c', 'e' };
53 static unsigned char dhx_s2civ[] = { 'C', 'J', 'a', 'l', 'b', 'e', 'r', 't' };
55 /* Static variables used to communicate between the conversation function
56 * and the server_login function */
57 static pam_handle_t *pamh = NULL;
58 static char *PAM_username;
59 static char *PAM_password;
60 static struct passwd *dhxpwd;
62 /*********************************************************
63 * Crypto helper func to generate p and g for use in DH.
64 * libgcrypt doesn't provide one directly.
65 * Algorithm taken from GNUTLS:gnutls_dh_primes.c
66 *********************************************************/
69 * This function will generate a new pair of prime and generator for use in
70 * the Diffie-Hellman key exchange.
71 * The bits value should be one of 768, 1024, 2048, 3072 or 4096.
73 static int dh_params_generate (unsigned int bits) {
75 int result, times = 0, qbits;
76 gcry_mpi_t gtmp = NULL;
77 gcry_mpi_t prime = NULL;
78 gcry_mpi_t *factors = NULL;
81 /* Version check should be the very first call because it
82 makes sure that important subsystems are intialized. */
83 if (!gcry_check_version (GCRYPT_VERSION)) {
84 LOG(log_error, logtype_uams, "PAM DHX2: libgcrypt versions mismatch. Need: %s", GCRYPT_VERSION);
92 qbits = (bits / 40) + 105;
94 if (qbits & 1) /* better have an even number */
97 /* find a prime number of size bits. */
100 gcry_mpi_release (prime);
101 gcry_prime_release_factors (factors);
103 err = gcry_prime_generate (&prime, bits, qbits, &factors, NULL, NULL,
104 GCRY_STRONG_RANDOM, GCRY_PRIME_FLAG_SPECIAL_FACTOR);
106 result = AFPERR_MISC;
109 err = gcry_prime_check (prime, 0);
111 } while (err != 0 && times < 10);
114 result = AFPERR_MISC;
118 /* generate the group generator. */
119 err = gcry_prime_group_generator (&g, prime, factors, NULL);
121 result = AFPERR_MISC;
125 gcry_prime_release_factors(factors);
133 gcry_prime_release_factors(factors);
134 gcry_mpi_release(gtmp);
135 gcry_mpi_release(prime);
141 /* PAM conversation function
142 * Here we assume (for now, at least) that echo on means login name, and
143 * echo off means password.
145 static int PAM_conv (int num_msg,
146 const struct pam_message **msg,
147 struct pam_response **resp,
148 void *appdata_ptr _U_) {
150 struct pam_response *reply;
152 #define COPY_STRING(s) (s) ? strdup(s) : NULL
158 LOG(log_info, logtype_uams, "PAM DHX2 Conversation Err -- %s",
164 reply = (struct pam_response *)
165 calloc(num_msg, sizeof(struct pam_response));
169 LOG(log_info, logtype_uams, "PAM DHX2: Conversation Err -- %s",
175 for (count = 0; count < num_msg; count++) {
178 switch (msg[count]->msg_style) {
179 case PAM_PROMPT_ECHO_ON:
180 if (!(string = COPY_STRING(PAM_username))) {
182 LOG(log_info, logtype_uams, "PAM DHX2: username failure -- %s",
188 case PAM_PROMPT_ECHO_OFF:
189 if (!(string = COPY_STRING(PAM_password))) {
191 LOG(log_info, logtype_uams, "PAM DHX2: passwd failure: --: %s",
198 #ifdef PAM_BINARY_PROMPT
199 case PAM_BINARY_PROMPT:
200 #endif /* PAM_BINARY_PROMPT */
205 LOG(log_info, logtype_uams, "PAM DHX2: Binary_Prompt -- %s", strerror(errno));
210 reply[count].resp_retcode = 0;
211 reply[count].resp = string;
217 LOG(log_info, logtype_uams, "PAM DHX2: PAM Success");
221 for (count = 0; count < num_msg; count++) {
222 if (!reply[count].resp)
224 switch (msg[count]->msg_style) {
225 case PAM_PROMPT_ECHO_OFF:
226 case PAM_PROMPT_ECHO_ON:
227 free(reply[count].resp);
233 LOG(log_info, logtype_uams, "PAM DHX2: Conversation Err -- %s",
239 static struct pam_conv PAM_conversation = {
245 static int dhx2_setup(void *obj, char *ibuf _U_, size_t ibuflen _U_,
246 char *rbuf, size_t *rbuflen)
251 char *Ra_binary = NULL;
255 // p = gcry_mpi_new(0);
256 // g = gcry_mpi_new(0);
257 Ra = gcry_mpi_new(0);
258 Ma = gcry_mpi_new(0);
260 /* Generate our random number Ra. */
261 Ra_binary = calloc(1, PRIMEBITS/8);
262 if (Ra_binary == NULL) {
266 gcry_randomize(Ra_binary, PRIMEBITS/8, GCRY_STRONG_RANDOM);
267 gcry_mpi_scan(&Ra, GCRYMPI_FMT_USG, Ra_binary, PRIMEBITS/8, NULL);
271 /* Ma = g^Ra mod p. This is our "public" key */
272 gcry_mpi_powm(Ma, g, Ra, p);
274 /* ------- DH Init done ------ */
275 /* Start building reply packet */
277 /* Session ID first */
279 *(u_int16_t *)rbuf = htons(ID);
284 gcry_mpi_print( GCRYMPI_FMT_USG, (unsigned char *)rbuf, 4, &nwritten, g);
286 memmove( rbuf+4-nwritten, rbuf, nwritten);
287 memset( rbuf, 0, 4-nwritten);
292 /* len = length of p = PRIMEBITS/8 */
293 *(u_int16_t *)rbuf = htons((u_int16_t) PRIMEBITS/8);
298 gcry_mpi_print( GCRYMPI_FMT_USG, (unsigned char *)rbuf, PRIMEBITS/8, NULL, p);
300 *rbuflen += PRIMEBITS/8;
303 gcry_mpi_print( GCRYMPI_FMT_USG, (unsigned char *)rbuf, PRIMEBITS/8, &nwritten, Ma);
304 if (nwritten < PRIMEBITS/8) {
305 memmove(rbuf + (PRIMEBITS/8) - nwritten, rbuf, nwritten);
306 memset(rbuf, 0, (PRIMEBITS/8) - nwritten);
309 *rbuflen += PRIMEBITS/8;
311 ret = AFPERR_AUTHCONT;
313 error: /* We exit here anyway */
314 /* We will need Ra later, but mustn't forget to release it ! */
315 gcry_mpi_release(Ma);
319 /* -------------------------------- */
320 static int login(void *obj, char *username, int ulen, struct passwd **uam_pwd _U_,
321 char *ibuf, size_t ibuflen,
322 char *rbuf, size_t *rbuflen)
324 if (( dhxpwd = uam_getname(obj, username, ulen)) == NULL ) {
325 LOG(log_info, logtype_uams, "DHX2: unknown username");
326 return AFPERR_NOTAUTH;
329 PAM_username = username;
330 LOG(log_info, logtype_uams, "DHX2 login: %s", username);
331 return dhx2_setup(obj, ibuf, ibuflen, rbuf, rbuflen);
334 /* -------------------------------- */
335 /* dhx login: things are done in a slightly bizarre order to avoid
336 * having to clean things up if there's an error. */
337 static int pam_login(void *obj, struct passwd **uam_pwd,
338 char *ibuf, size_t ibuflen,
339 char *rbuf, size_t *rbuflen)
346 /* grab some of the options */
347 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, (void *) &username, &ulen) < 0) {
348 LOG(log_info, logtype_uams, "DHX2: uam_afpserver_option didn't meet uam_option_username -- %s",
353 len = (unsigned char) *ibuf++;
355 LOG(log_info, logtype_uams, "DHX2: Signature Retieval Failure -- %s",
360 memcpy(username, ibuf, len );
362 username[ len ] = '\0';
364 if ((unsigned long) ibuf & 1) /* pad to even boundary */
367 return (login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
370 /* ----------------------------- */
371 static int pam_login_ext(void *obj, char *uname, struct passwd **uam_pwd,
372 char *ibuf, size_t ibuflen,
373 char *rbuf, size_t *rbuflen)
381 /* grab some of the options */
382 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, (void *) &username, &ulen) < 0) {
383 LOG(log_info, logtype_uams, "DHX2: uam_afpserver_option didn't meet uam_option_username -- %s",
391 memcpy(&temp16, uname, sizeof(temp16));
394 if ( !len || len > ulen ) {
395 LOG(log_info, logtype_uams, "DHX2: Signature Retrieval Failure -- %s",
399 memcpy(username, uname +2, len );
400 username[ len ] = '\0';
402 return (login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
405 /* -------------------------------- */
406 static int logincont1(void *obj _U_, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
410 gcry_mpi_t Mb, K, clientNonce;
411 unsigned char *K_bin = NULL;
412 char serverNonce_bin[16];
413 gcry_cipher_hd_t ctx;
414 gcry_error_t ctxerror;
418 Mb = gcry_mpi_new(0);
420 clientNonce = gcry_mpi_new(0);
421 serverNonce = gcry_mpi_new(0);
423 /* Packet size should be: Session ID + Ma + Encrypted client nonce */
424 if (ibuflen != 2 + PRIMEBITS/8 + 16) {
425 LOG(log_error, logtype_uams, "DHX2: Paket length not correct");
430 /* Skip session id */
433 /* Extract Mb, client's "public" key */
434 gcry_mpi_scan(&Mb, GCRYMPI_FMT_USG, ibuf, PRIMEBITS/8, NULL);
437 /* Now finally generate the Key: K = Mb^Ra mod p */
438 gcry_mpi_powm(K, Mb, Ra, p);
440 /* We need K in binary form in order to ... */
441 K_bin = calloc(1, PRIMEBITS/8);
446 gcry_mpi_print(GCRYMPI_FMT_USG, K_bin, PRIMEBITS/8, &nwritten, K);
447 if (nwritten < PRIMEBITS/8) {
448 memmove(K_bin + PRIMEBITS/8 - nwritten, K_bin, nwritten);
449 memset(K_bin, 0, PRIMEBITS/8 - nwritten);
452 /* ... generate the MD5 hash of K. K_MD5hash is what we actually use ! */
453 K_MD5hash = calloc(1, K_hash_len = gcry_md_get_algo_dlen(GCRY_MD_MD5));
454 if (K_MD5hash == NULL) {
458 gcry_md_hash_buffer(GCRY_MD_MD5, K_MD5hash, K_bin, PRIMEBITS/8);
462 /* FIXME: To support the Reconnect UAM, we need to store this key somewhere */
464 /* Set up our encryption context. */
465 ctxerror = gcry_cipher_open( &ctx, GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CBC, 0);
466 if (gcry_err_code(ctxerror) != GPG_ERR_NO_ERROR) {
471 ctxerror = gcry_cipher_setkey(ctx, K_MD5hash, K_hash_len);
472 if (gcry_err_code(ctxerror) != GPG_ERR_NO_ERROR) {
476 /* Set the initialization vector for client->server transfer. */
477 ctxerror = gcry_cipher_setiv(ctx, dhx_c2siv, sizeof(dhx_c2siv));
478 if (gcry_err_code(ctxerror) != GPG_ERR_NO_ERROR) {
482 /* Finally: decrypt client's md5_K(client nonce, C2SIV) inplace */
483 ctxerror = gcry_cipher_decrypt(ctx, ibuf, 16, NULL, 0);
484 if (gcry_err_code(ctxerror) != GPG_ERR_NO_ERROR) {
488 /* Pull out clients nonce */
489 gcry_mpi_scan(&clientNonce, GCRYMPI_FMT_USG, ibuf, 16, NULL);
490 /* Increment nonce */
491 gcry_mpi_add_ui(clientNonce, clientNonce, 1);
493 /* Generate our nonce and remember it for Logincont2 */
494 gcry_create_nonce(serverNonce_bin, 16); /* We'll use this here */
495 gcry_mpi_scan(&serverNonce, GCRYMPI_FMT_USG, serverNonce_bin, 16, NULL); /* For use in Logincont2 */
497 /* ---- Start building reply packet ---- */
499 /* Session ID + 1 first */
500 *(u_int16_t *)rbuf = htons(ID+1);
504 /* Client nonce + 1 */
505 gcry_mpi_print(GCRYMPI_FMT_USG, (unsigned char *)rbuf, PRIMEBITS/8, NULL, clientNonce);
507 memcpy(rbuf+16, serverNonce_bin, 16);
509 /* Set the initialization vector for server->client transfer. */
510 ctxerror = gcry_cipher_setiv(ctx, dhx_s2civ, sizeof(dhx_s2civ));
511 if (gcry_err_code(ctxerror) != GPG_ERR_NO_ERROR) {
515 /* Encrypt md5_K(clientNonce+1, serverNonce) inplace */
516 ctxerror = gcry_cipher_encrypt(ctx, rbuf, 32, NULL, 0);
517 if (gcry_err_code(ctxerror) != GPG_ERR_NO_ERROR) {
524 ret = AFPERR_AUTHCONT;
528 gcry_cipher_close(ctx);
530 gcry_mpi_release(serverNonce);
535 gcry_mpi_release(Mb);
536 gcry_mpi_release(Ra);
537 gcry_mpi_release(clientNonce);
541 static int logincont2(void *obj, struct passwd **uam_pwd,
542 char *ibuf, size_t ibuflen,
543 char *rbuf _U_, size_t *rbuflen)
547 const char *hostname = NULL;
548 gcry_mpi_t retServerNonce;
549 gcry_cipher_hd_t ctx;
550 gcry_error_t ctxerror;
554 /* Packet size should be: Session ID + ServerNonce + Passwd buffer (evantually +10 extra bytes, see Apples Docs) */
555 if ((ibuflen != 2 + 16 + 256) && (ibuflen != 2 + 16 + 256 + 10)) {
556 LOG(log_error, logtype_uams, "DHX2: Paket length not correct: %u. Should be 274 or 284.", ibuflen);
561 retServerNonce = gcry_mpi_new(0);
564 uam_afpserver_option(obj, UAM_OPTION_CLIENTNAME, (void *) &hostname, NULL);
566 /* Set up our encryption context. */
567 ctxerror = gcry_cipher_open( &ctx, GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CBC, 0);
568 if (gcry_err_code(ctxerror) != GPG_ERR_NO_ERROR) {
573 ctxerror = gcry_cipher_setkey(ctx, K_MD5hash, K_hash_len);
574 if (gcry_err_code(ctxerror) != GPG_ERR_NO_ERROR) {
578 /* Set the initialization vector for client->server transfer. */
579 ctxerror = gcry_cipher_setiv(ctx, dhx_c2siv, sizeof(dhx_c2siv));
580 if (gcry_err_code(ctxerror) != GPG_ERR_NO_ERROR) {
585 /* Skip Session ID */
588 /* Finally: decrypt client's md5_K(serverNonce+1, passwor, C2SIV) inplace */
589 ctxerror = gcry_cipher_decrypt(ctx, ibuf, 16+256, NULL, 0);
590 if (gcry_err_code(ctxerror) != GPG_ERR_NO_ERROR) {
594 /* Pull out nonce. Should be serverNonce+1 */
595 gcry_mpi_scan(&retServerNonce, GCRYMPI_FMT_USG, ibuf, 16, NULL);
596 gcry_mpi_sub_ui(retServerNonce, retServerNonce, 1);
597 if ( gcry_mpi_cmp( serverNonce, retServerNonce) != 0) {
599 ret = AFPERR_NOTAUTH;
604 /* ---- Start authentication with PAM --- */
606 /* Set these things up for the conv function */
609 ret = AFPERR_NOTAUTH;
610 PAM_error = pam_start("netatalk", PAM_username, &PAM_conversation, &pamh);
611 if (PAM_error != PAM_SUCCESS) {
612 LOG(log_info, logtype_uams, "DHX2: PAM_Error: %s",
613 pam_strerror(pamh,PAM_error));
617 /* solaris craps out if PAM_TTY and PAM_RHOST aren't set. */
618 pam_set_item(pamh, PAM_TTY, "afpd");
619 pam_set_item(pamh, PAM_RHOST, hostname);
620 PAM_error = pam_authenticate(pamh, 0);
621 if (PAM_error != PAM_SUCCESS) {
622 if (PAM_error == PAM_MAXTRIES)
623 ret = AFPERR_PWDEXPR;
624 LOG(log_info, logtype_uams, "DHX2: PAM_Error: %s",
625 pam_strerror(pamh, PAM_error));
629 PAM_error = pam_acct_mgmt(pamh, 0);
630 if (PAM_error != PAM_SUCCESS ) {
631 LOG(log_info, logtype_uams, "DHX2: PAM_Error: %s",
632 pam_strerror(pamh, PAM_error));
633 if (PAM_error == PAM_NEW_AUTHTOK_REQD) /* password expired */
634 ret = AFPERR_PWDEXPR;
635 #ifdef PAM_AUTHTOKEN_REQD
636 else if (PAM_error == PAM_AUTHTOKEN_REQD)
637 ret = AFPERR_PWDCHNG;
643 #ifndef PAM_CRED_ESTABLISH
644 #define PAM_CRED_ESTABLISH PAM_ESTABLISH_CRED
646 PAM_error = pam_setcred(pamh, PAM_CRED_ESTABLISH);
647 if (PAM_error != PAM_SUCCESS) {
648 LOG(log_info, logtype_uams, "DHX2: PAM_Error: %s",
649 pam_strerror(pamh, PAM_error));
653 PAM_error = pam_open_session(pamh, 0);
654 if (PAM_error != PAM_SUCCESS) {
655 LOG(log_info, logtype_uams, "DHX2: PAM_Error: %s",
656 pam_strerror(pamh, PAM_error));
660 memset(ibuf, 0, 256); /* zero out the password */
662 LOG(log_info, logtype_uams, "DHX2: PAM Auth OK!");
663 if ( ret == AFPERR_PWDEXPR)
668 gcry_cipher_close(ctx);
672 gcry_mpi_release(serverNonce);
673 gcry_mpi_release(retServerNonce);
677 static int pam_logincont(void *obj, struct passwd **uam_pwd,
678 char *ibuf, size_t ibuflen,
679 char *rbuf, size_t *rbuflen)
684 /* check for session id */
685 retID = ntohs(*(u_int16_t *)ibuf);
687 ret = logincont1(obj, ibuf, ibuflen, rbuf, rbuflen);
688 else if (retID == ID+1)
689 ret = logincont2(obj, uam_pwd, ibuf,ibuflen, rbuf, rbuflen);
691 LOG(log_info, logtype_uams, "DHX2: Session ID Mismatch");
699 static void pam_logout(void) {
700 pam_close_session(pamh, 0);
705 /****************************
706 * --- Change pwd stuff --- */
708 static int changepw_1(void *obj, char *uname,
709 char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
713 /* Remember it now, use it in changepw_3 */
714 PAM_username = uname;
715 return( dhx2_setup(obj, ibuf, ibuflen, rbuf, rbuflen) );
718 static int changepw_2(void *obj,
719 char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
721 return( logincont1(obj, ibuf, ibuflen, rbuf, rbuflen) );
724 static int changepw_3(void *obj _U_,
725 char *ibuf, size_t ibuflen _U_,
726 char *rbuf _U_, size_t *rbuflen _U_)
732 const char *hostname = NULL;
733 gcry_mpi_t retServerNonce;
734 gcry_cipher_hd_t ctx;
735 gcry_error_t ctxerror;
739 LOG(log_error, logtype_uams, "DHX2 ChangePW: packet 3 processing");
741 /* Packet size should be: Session ID + ServerNonce + 2*Passwd buffer */
742 if (ibuflen != 2 + 16 + 2*256) {
743 LOG(log_error, logtype_uams, "DHX2: Paket length not correct");
748 retServerNonce = gcry_mpi_new(0);
751 uam_afpserver_option(obj, UAM_OPTION_CLIENTNAME, (void *) &hostname, NULL);
753 /* Set up our encryption context. */
754 ctxerror = gcry_cipher_open( &ctx, GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CBC, 0);
755 if (gcry_err_code(ctxerror) != GPG_ERR_NO_ERROR) {
760 ctxerror = gcry_cipher_setkey(ctx, K_MD5hash, K_hash_len);
761 if (gcry_err_code(ctxerror) != GPG_ERR_NO_ERROR) {
766 /* Set the initialization vector for client->server transfer. */
767 ctxerror = gcry_cipher_setiv(ctx, dhx_c2siv, sizeof(dhx_c2siv));
768 if (gcry_err_code(ctxerror) != GPG_ERR_NO_ERROR) {
773 /* Skip Session ID */
776 /* Finally: decrypt client's md5_K(serverNonce+1, 2*password, C2SIV) inplace */
777 ctxerror = gcry_cipher_decrypt(ctx, ibuf, 16+2*256, NULL, 0);
778 if (gcry_err_code(ctxerror) != GPG_ERR_NO_ERROR) {
782 /* Pull out nonce. Should be serverNonce+1 */
783 gcry_mpi_scan(&retServerNonce, GCRYMPI_FMT_USG, ibuf, 16, NULL);
784 gcry_mpi_sub_ui(retServerNonce, retServerNonce, 1);
785 if ( gcry_mpi_cmp( serverNonce, retServerNonce) != 0) {
787 ret = AFPERR_NOTAUTH;
792 /* ---- Start pwd changing with PAM --- */
793 ibuf[255] = '\0'; /* For safety */
796 /* check if new and old password are equal */
797 if (memcmp(ibuf, ibuf + 256, 255) == 0) {
798 LOG(log_info, logtype_uams, "DHX2 Chgpwd: new and old password are equal");
799 ret = AFPERR_PWDSAME;
803 /* Set these things up for the conv function. PAM_username was set in changepw_1 */
804 PAM_password = ibuf + 256;
805 PAM_error = pam_start("netatalk", PAM_username, &PAM_conversation, &lpamh);
806 if (PAM_error != PAM_SUCCESS) {
807 LOG(log_info, logtype_uams, "DHX2 Chgpwd: PAM error in pam_start");
811 pam_set_item(lpamh, PAM_TTY, "afpd");
812 uam_afpserver_option(obj, UAM_OPTION_CLIENTNAME, (void *) &hostname, NULL);
813 pam_set_item(lpamh, PAM_RHOST, hostname);
816 PAM_error = pam_authenticate(lpamh,0);
817 if (PAM_error != PAM_SUCCESS) {
818 LOG(log_info, logtype_uams, "DHX2 Chgpwd: error authenticating with PAM");
820 pam_end(lpamh, PAM_error);
821 ret = AFPERR_NOTAUTH;
825 PAM_error = pam_chauthtok(lpamh, 0);
826 seteuid(uid); /* un-root ourselves. */
827 memset(ibuf, 0, 512);
828 if (PAM_error != PAM_SUCCESS) {
829 LOG(log_info, logtype_uams, "DHX2 Chgpwd: error changing pw with PAM");
830 pam_end(lpamh, PAM_error);
838 gcry_cipher_close(ctx);
842 gcry_mpi_release(serverNonce);
843 gcry_mpi_release(retServerNonce);
847 static int dhx2_changepw(void *obj _U_, char *uname,
848 struct passwd *pwd _U_, char *ibuf, size_t ibuflen _U_,
849 char *rbuf _U_, size_t *rbuflen _U_)
851 /* We use this to serialize the three incoming FPChangePassword calls */
852 static int dhx2_changepw_status = 1;
854 int ret = AFPERR_NOTAUTH; /* gcc can't figure out it's always initialized */
856 switch (dhx2_changepw_status) {
858 ret = changepw_1( obj, uname, ibuf, ibuflen, rbuf, rbuflen);
859 if ( ret == AFPERR_AUTHCONT)
860 dhx2_changepw_status = 2;
863 ret = changepw_2( obj, ibuf, ibuflen, rbuf, rbuflen);
864 if ( ret == AFPERR_AUTHCONT)
865 dhx2_changepw_status = 3;
867 dhx2_changepw_status = 1;
870 ret = changepw_3( obj, ibuf, ibuflen, rbuf, rbuflen);
871 dhx2_changepw_status = 1; /* Whether is was succesfull or not: we
878 static int uam_setup(const char *path)
880 if (uam_register(UAM_SERVER_LOGIN_EXT, path, "DHX2", pam_login,
881 pam_logincont, pam_logout, pam_login_ext) < 0)
883 if (uam_register(UAM_SERVER_CHANGEPW, path, "DHX2", dhx2_changepw) < 0)
889 LOG(log_note, logtype_uams, "DHX2: generating mersenne primes");
890 /* Generate p and g for DH */
891 if (dh_params_generate(PRIMEBITS) != 0) {
892 LOG(log_error, logtype_uams, "DHX2: Couldn't generate p and g");
899 static void uam_cleanup(void)
901 uam_unregister(UAM_SERVER_LOGIN, "DHX2");
902 uam_unregister(UAM_SERVER_CHANGEPW, "DHX2");
909 UAM_MODULE_EXPORT struct uam_export uams_dhx2 = {
912 uam_setup, uam_cleanup
916 UAM_MODULE_EXPORT struct uam_export uams_dhx2_pam = {
919 uam_setup, uam_cleanup
922 #endif /* USE_PAM && UAM_DHX2 */