]> arthur.barton.de Git - netatalk.git/blobdiff - etc/uams/uams_dhx2_pam.c
Merge remote-tracking branch 'origin/develop' into spotlight
[netatalk.git] / etc / uams / uams_dhx2_pam.c
index e195ba3858aecf5027f76a6ad9406b5351d0c540..5229d372433603b810ece221f427e92ed71079ee 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: uams_dhx2_pam.c,v 1.3 2008-11-24 21:50:02 didg Exp $
- *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu)
  * All Rights Reserved.  See COPYRIGHT.
 
 #include <atalk/afp.h>
 #include <atalk/uam.h>
-#include "../afpd/globals.h"
+#include <atalk/globals.h>
 
 /* Number of bits for p which we generate. Everybode out there uses 512, so we beet them */
 #define PRIMEBITS 1024
 
 /* hash a number to a 16-bit quantity */
-#define dhxhash(a) ((((unsigned long) (a) >> 8) ^ \
+#define dhxhash(a) ((((unsigned long) (a) >> 8) ^   \
                      (unsigned long) (a)) & 0xffff)
 
 /* Some parameters need be maintained across calls */
-static gcry_mpi_t p, Ra;
+static gcry_mpi_t p, g, Ra;
 static gcry_mpi_t serverNonce;
 static char *K_MD5hash = NULL;
 static int K_hash_len;
-static u_int16_t ID;
+static uint16_t ID;
 
 /* The initialization vectors for CAST128 are fixed by Apple. */
 static unsigned char dhx_c2siv[] = { 'L', 'W', 'a', 'l', 'l', 'a', 'c', 'e' };
@@ -63,8 +61,8 @@ static struct passwd *dhxpwd;
 
 /*********************************************************
  * Crypto helper func to generate p and g for use in DH.
- * libgcrpyt doesn't provide one directly.
- * Algorithm taken from GNUTLS:gnutls_dh_primes.c 
+ * libgcrypt doesn't provide one directly.
+ * Algorithm taken from GNUTLS:gnutls_dh_primes.c
  *********************************************************/
 
 /**
@@ -72,78 +70,62 @@ static struct passwd *dhxpwd;
  * the Diffie-Hellman key exchange.
  * The bits value should be one of 768, 1024, 2048, 3072 or 4096.
  **/
-
-static int
-dh_params_generate (gcry_mpi_t *ret_p, gcry_mpi_t *ret_g, unsigned int bits) {
+static int dh_params_generate (unsigned int bits) {
 
     int result, times = 0, qbits;
-
-    gcry_mpi_t g = NULL, prime = NULL;
     gcry_mpi_t *factors = NULL;
     gcry_error_t err;
 
     /* Version check should be the very first call because it
        makes sure that important subsystems are intialized. */
     if (!gcry_check_version (GCRYPT_VERSION)) {
-        LOG(log_info, logtype_uams, "PAM DHX2: libgcrypt versions mismatch. Need: %u", GCRYPT_VERSION);
-       result = AFPERR_MISC;
-       goto error;
+        LOG(log_error, logtype_uams, "PAM DHX2: libgcrypt versions mismatch. Need: %s", GCRYPT_VERSION);
+        result = AFPERR_MISC;
+        goto error;
     }
 
     if (bits < 256)
-       qbits = bits / 2;
+        qbits = bits / 2;
     else
-       qbits = (bits / 40) + 105;
+        qbits = (bits / 40) + 105;
 
     if (qbits & 1) /* better have an even number */
-       qbits++;
+        qbits++;
 
     /* find a prime number of size bits. */
     do {
-       if (times) {
-           gcry_mpi_release (prime);
-           gcry_prime_release_factors (factors);
-       }
-       err = gcry_prime_generate (&prime, bits, qbits, &factors, NULL, NULL,
-                                  GCRY_STRONG_RANDOM, GCRY_PRIME_FLAG_SPECIAL_FACTOR);
-       if (err != 0) {
-           result = AFPERR_MISC;
-           goto error;
-       }
-       err = gcry_prime_check (prime, 0);
-       times++;
+        if (times) {
+            gcry_mpi_release(p);
+            gcry_prime_release_factors (factors);
+        }
+        err = gcry_prime_generate(&p, bits, qbits, &factors, NULL, NULL,
+                                  GCRY_STRONG_RANDOM, GCRY_PRIME_FLAG_SPECIAL_FACTOR);
+        if (err != 0) {
+            result = AFPERR_MISC;
+            goto error;
+        }
+        err = gcry_prime_check(p, 0);
+        times++;
     } while (err != 0 && times < 10);
-    
+
     if (err != 0) {
-       result = AFPERR_MISC;
-       goto error;
+        result = AFPERR_MISC;
+        goto error;
     }
 
     /* generate the group generator. */
-    err = gcry_prime_group_generator (&g, prime, factors, NULL);
+    err = gcry_prime_group_generator(&g, p, factors, NULL);
     if (err != 0) {
-       result = AFPERR_MISC;
-       goto error;
-    }
-    
-    gcry_prime_release_factors (factors);
-    factors = NULL;
-    
-    if (ret_g)
-       *ret_g = g;
-    else
-       gcry_mpi_release (g);
-    if (ret_p)
-       *ret_p = prime;
-    else
-       gcry_mpi_release (prime);
-    
+        result = AFPERR_MISC;
+        goto error;
+    }
+
+    gcry_prime_release_factors(factors);
+
     return 0;
 
 error:
-    gcry_prime_release_factors (factors);
-    gcry_mpi_release (g);
-    gcry_mpi_release (prime);
+    gcry_prime_release_factors(factors);
 
     return result;
 }
@@ -154,7 +136,11 @@ error:
  * echo off means password.
  */
 static int PAM_conv (int num_msg,
+#ifdef LINUX
                      const struct pam_message **msg,
+#else
+                     struct pam_message **msg,
+#endif
                      struct pam_response **resp,
                      void *appdata_ptr _U_) {
     int count = 0;
@@ -253,34 +239,25 @@ static struct pam_conv PAM_conversation = {
 };
 
 
-static int dhx2_setup(void *obj, char *ibuf _U_, int ibuflen _U_,
-                     char *rbuf, int *rbuflen)
+static int dhx2_setup(void *obj, char *ibuf _U_, size_t ibuflen _U_,
+                      char *rbuf, size_t *rbuflen)
 {
     int ret;
     size_t nwritten;
-    gcry_mpi_t g, Ma;
+    gcry_mpi_t Ma;
     char *Ra_binary = NULL;
+    uint16_t uint16;
 
     *rbuflen = 0;
 
-    p = gcry_mpi_new(0);
-    g = gcry_mpi_new(0);
     Ra = gcry_mpi_new(0);
     Ma = gcry_mpi_new(0);
 
-    /* Generate p and g for DH */
-    ret = dh_params_generate( &p, &g, PRIMEBITS);
-    if (ret != 0) {
-       LOG(log_info, logtype_uams, "DHX2: Couldn't generate p and g");
-       ret = AFPERR_MISC;
-       goto error;
-    }
-
     /* Generate our random number Ra. */
     Ra_binary = calloc(1, PRIMEBITS/8);
     if (Ra_binary == NULL) {
-       ret = AFPERR_MISC;
-       goto error;
+        ret = AFPERR_MISC;
+        goto error;
     }
     gcry_randomize(Ra_binary, PRIMEBITS/8, GCRY_STRONG_RANDOM);
     gcry_mpi_scan(&Ra, GCRYMPI_FMT_USG, Ra_binary, PRIMEBITS/8, NULL);
@@ -295,21 +272,24 @@ static int dhx2_setup(void *obj, char *ibuf _U_, int ibuflen _U_,
 
     /* Session ID first */
     ID = dhxhash(obj);
-    *(u_int16_t *)rbuf = htons(ID);
+    uint16 = htons(ID);
+    memcpy(rbuf, &uint16, sizeof(uint16_t));
     rbuf += 2;
     *rbuflen += 2;
 
     /* g is next */
     gcry_mpi_print( GCRYMPI_FMT_USG, (unsigned char *)rbuf, 4, &nwritten, g);
     if (nwritten < 4) {
-       memmove( rbuf+4-nwritten, rbuf, nwritten);
-       memset( rbuf, 0, 4-nwritten);
+        memmove( rbuf+4-nwritten, rbuf, nwritten);
+        memset( rbuf, 0, 4-nwritten);
     }
     rbuf += 4;
     *rbuflen += 4;
 
     /* len = length of p = PRIMEBITS/8 */
-    *(u_int16_t *)rbuf = htons((u_int16_t) PRIMEBITS/8);
+
+    uint16 = htons((uint16_t) PRIMEBITS/8);
+    memcpy(rbuf, &uint16, sizeof(uint16_t));
     rbuf += 2;
     *rbuflen += 2;
 
@@ -321,29 +301,28 @@ static int dhx2_setup(void *obj, char *ibuf _U_, int ibuflen _U_,
     /* Ma */
     gcry_mpi_print( GCRYMPI_FMT_USG, (unsigned char *)rbuf, PRIMEBITS/8, &nwritten, Ma);
     if (nwritten < PRIMEBITS/8) {
-       memmove(rbuf + (PRIMEBITS/8) - nwritten, rbuf, nwritten);
-       memset(rbuf, 0, (PRIMEBITS/8) - nwritten);
+        memmove(rbuf + (PRIMEBITS/8) - nwritten, rbuf, nwritten);
+        memset(rbuf, 0, (PRIMEBITS/8) - nwritten);
     }
     rbuf += PRIMEBITS/8;
     *rbuflen += PRIMEBITS/8;
 
     ret = AFPERR_AUTHCONT;
 
-error:                         /* We exit here anyway */
-    /* We will only need p and Ra later, but mustn't forget to release it ! */
-    gcry_mpi_release(g);
+error:              /* We exit here anyway */
+    /* We will need Ra later, but mustn't forget to release it ! */
     gcry_mpi_release(Ma);
     return ret;
 }
 
 /* -------------------------------- */
 static int login(void *obj, char *username, int ulen,  struct passwd **uam_pwd _U_,
-                 char *ibuf, int ibuflen,
-                 char *rbuf, int *rbuflen)
+                 char *ibuf, size_t ibuflen,
+                 char *rbuf, size_t *rbuflen)
 {
     if (( dhxpwd = uam_getname(obj, username, ulen)) == NULL ) {
         LOG(log_info, logtype_uams, "DHX2: unknown username");
-        return AFPERR_PARAM;
+        return AFPERR_NOTAUTH;
     }
 
     PAM_username = username;
@@ -355,11 +334,11 @@ static int login(void *obj, char *username, int ulen,  struct passwd **uam_pwd _
 /* dhx login: things are done in a slightly bizarre order to avoid
  * having to clean things up if there's an error. */
 static int pam_login(void *obj, struct passwd **uam_pwd,
-                     char *ibuf, int ibuflen,
-                     char *rbuf, int *rbuflen)
+                     char *ibuf, size_t ibuflen,
+                     char *rbuf, size_t *rbuflen)
 {
     char *username;
-    int len, ulen;
+    size_t len, ulen;
 
     *rbuflen = 0;
 
@@ -389,12 +368,12 @@ static int pam_login(void *obj, struct passwd **uam_pwd,
 
 /* ----------------------------- */
 static int pam_login_ext(void *obj, char *uname, struct passwd **uam_pwd,
-                         char *ibuf, int ibuflen,
-                         char *rbuf, int *rbuflen)
+                         char *ibuf, size_t ibuflen,
+                         char *rbuf, size_t *rbuflen)
 {
     char *username;
-    int len, ulen;
-    u_int16_t  temp16;
+    size_t len, ulen;
+    uint16_t  temp16;
 
     *rbuflen = 0;
 
@@ -423,8 +402,7 @@ static int pam_login_ext(void *obj, char *uname, struct passwd **uam_pwd,
 }
 
 /* -------------------------------- */
-
-static int logincont1(void *obj _U_, char *ibuf, int ibuflen, char *rbuf, int *rbuflen)
+static int logincont1(void *obj _U_, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
 {
     int ret;
     size_t nwritten;
@@ -433,6 +411,9 @@ static int logincont1(void *obj _U_, char *ibuf, int ibuflen, char *rbuf, int *r
     char serverNonce_bin[16];
     gcry_cipher_hd_t ctx;
     gcry_error_t ctxerror;
+    uint16_t uint16;
+
+    *rbuflen = 0;
 
     Mb = gcry_mpi_new(0);
     K = gcry_mpi_new(0);
@@ -441,9 +422,9 @@ static int logincont1(void *obj _U_, char *ibuf, int ibuflen, char *rbuf, int *r
 
     /* Packet size should be: Session ID + Ma + Encrypted client nonce */
     if (ibuflen != 2 + PRIMEBITS/8 + 16) {
-       LOG(log_error, logtype_uams, "DHX2: Paket length not correct");
+        LOG(log_error, logtype_uams, "DHX2: Paket length not correct");
         ret = AFPERR_PARAM;
-       goto error_noctx;
+        goto error_noctx;
     }
 
     /* Skip session id */
@@ -459,20 +440,20 @@ static int logincont1(void *obj _U_, char *ibuf, int ibuflen, char *rbuf, int *r
     /* We need K in binary form in order to ... */
     K_bin = calloc(1, PRIMEBITS/8);
     if (K_bin == NULL) {
-       ret = AFPERR_MISC;
-       goto error_noctx;
+        ret = AFPERR_MISC;
+        goto error_noctx;
     }
     gcry_mpi_print(GCRYMPI_FMT_USG, K_bin, PRIMEBITS/8, &nwritten, K);
     if (nwritten < PRIMEBITS/8) {
-       memmove(K_bin + PRIMEBITS/8 - nwritten, K_bin, nwritten);
-       memset(K_bin, 0, PRIMEBITS/8 - nwritten);
+        memmove(K_bin + PRIMEBITS/8 - nwritten, K_bin, nwritten);
+        memset(K_bin, 0, PRIMEBITS/8 - nwritten);
     }
 
     /* ... generate the MD5 hash of K. K_MD5hash is what we actually use ! */
     K_MD5hash = calloc(1, K_hash_len = gcry_md_get_algo_dlen(GCRY_MD_MD5));
     if (K_MD5hash == NULL) {
-       ret = AFPERR_MISC;
-       goto error_noctx;
+        ret = AFPERR_MISC;
+        goto error_noctx;
     }
     gcry_md_hash_buffer(GCRY_MD_MD5, K_MD5hash, K_bin, PRIMEBITS/8);
     free(K_bin);
@@ -483,25 +464,25 @@ static int logincont1(void *obj _U_, char *ibuf, int ibuflen, char *rbuf, int *r
     /* Set up our encryption context. */
     ctxerror = gcry_cipher_open( &ctx, GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CBC, 0);
     if (gcry_err_code(ctxerror) != GPG_ERR_NO_ERROR) {
-       ret = AFPERR_MISC;
+        ret = AFPERR_MISC;
         goto error_ctx;
     }
     /* Set key */
     ctxerror = gcry_cipher_setkey(ctx, K_MD5hash, K_hash_len);
     if (gcry_err_code(ctxerror) != GPG_ERR_NO_ERROR) {
-       ret = AFPERR_MISC;
+        ret = AFPERR_MISC;
         goto error_ctx;
     }
     /* Set the initialization vector for client->server transfer. */
     ctxerror = gcry_cipher_setiv(ctx, dhx_c2siv, sizeof(dhx_c2siv));
     if (gcry_err_code(ctxerror) != GPG_ERR_NO_ERROR) {
-       ret = AFPERR_MISC;
+        ret = AFPERR_MISC;
         goto error_ctx;
     }
     /* Finally: decrypt client's md5_K(client nonce, C2SIV) inplace */
     ctxerror = gcry_cipher_decrypt(ctx, ibuf, 16, NULL, 0);
     if (gcry_err_code(ctxerror) != GPG_ERR_NO_ERROR) {
-       ret = AFPERR_MISC;
+        ret = AFPERR_MISC;
         goto error_ctx;
     }
     /* Pull out clients nonce */
@@ -516,7 +497,8 @@ static int logincont1(void *obj _U_, char *ibuf, int ibuflen, char *rbuf, int *r
     /* ---- Start building reply packet ---- */
 
     /* Session ID + 1 first */
-    *(u_int16_t *)rbuf = htons(ID+1);
+    uint16 = htons(ID+1);
+    memcpy(rbuf, &uint16, sizeof(uint16_t));
     rbuf += 2;
     *rbuflen += 2;
 
@@ -528,14 +510,14 @@ static int logincont1(void *obj _U_, char *ibuf, int ibuflen, char *rbuf, int *r
     /* Set the initialization vector for server->client transfer. */
     ctxerror = gcry_cipher_setiv(ctx, dhx_s2civ, sizeof(dhx_s2civ));
     if (gcry_err_code(ctxerror) != GPG_ERR_NO_ERROR) {
-       ret = AFPERR_MISC;
+        ret = AFPERR_MISC;
         goto error_ctx;
     }
     /* Encrypt md5_K(clientNonce+1, serverNonce) inplace */
     ctxerror = gcry_cipher_encrypt(ctx, rbuf, 32, NULL, 0);
     if (gcry_err_code(ctxerror) != GPG_ERR_NO_ERROR) {
-       ret = AFPERR_MISC;
-       goto error_ctx;
+        ret = AFPERR_MISC;
+        goto error_ctx;
     }
     rbuf += 32;
     *rbuflen += 32;
@@ -553,27 +535,56 @@ exit:
     gcry_mpi_release(K);
     gcry_mpi_release(Mb);
     gcry_mpi_release(Ra);
-    gcry_mpi_release(p);
     gcry_mpi_release(clientNonce);
     return ret;
 }
 
-static int logincont2(void *obj, struct passwd **uam_pwd,
-                     char *ibuf, int ibuflen,
-                     char *rbuf _U_, int *rbuflen)
+/**
+ * Try to authenticate via PAM as "adminauthuser"
+ **/
+static int loginasroot(const char *adminauthuser, const char **hostname, int status)
 {
-    int ret;
     int PAM_error;
-    char *hostname = NULL;
+
+    if ((PAM_error = pam_end(pamh, status)) != PAM_SUCCESS)
+        goto exit;
+    pamh = NULL;
+
+    if ((PAM_error = pam_start("netatalk", adminauthuser, &PAM_conversation, &pamh)) != PAM_SUCCESS) {
+        LOG(log_info, logtype_uams, "DHX2: PAM_Error: %s", pam_strerror(pamh,PAM_error));
+        goto exit;
+    }
+
+    /* solaris craps out if PAM_TTY and PAM_RHOST aren't set. */
+    pam_set_item(pamh, PAM_TTY, "afpd");
+    pam_set_item(pamh, PAM_RHOST, *hostname);
+    if ((PAM_error = pam_authenticate(pamh, 0)) != PAM_SUCCESS)
+        goto exit;
+
+    LOG(log_warning, logtype_uams, "DHX2: Authenticated as \"%s\"", adminauthuser);
+
+exit:
+    return PAM_error;
+}
+
+static int logincont2(void *obj_in, struct passwd **uam_pwd,
+                      char *ibuf, size_t ibuflen,
+                      char *rbuf _U_, size_t *rbuflen)
+{
+    AFPObj *obj = obj_in;
+    int ret = AFPERR_MISC;
+    int PAM_error;
+    const char *hostname = NULL;
     gcry_mpi_t retServerNonce;
     gcry_cipher_hd_t ctx;
     gcry_error_t ctxerror;
+    char *utfpass = NULL;
 
     *rbuflen = 0;
 
-    /* Packet size should be: Session ID + ServerNonce + Passwd buffer */
-    if (ibuflen != 2 + 16 + 256) {
-        LOG(log_error, logtype_uams, "DHX2: Paket length not correct");
+    /* Packet size should be: Session ID + ServerNonce + Passwd buffer (evantually +10 extra bytes, see Apples Docs) */
+    if ((ibuflen != 2 + 16 + 256) && (ibuflen != 2 + 16 + 256 + 10)) {
+        LOG(log_error, logtype_uams, "DHX2: Paket length not correct: %u. Should be 274 or 284.", ibuflen);
         ret = AFPERR_PARAM;
         goto error_noctx;
     }
@@ -615,51 +626,63 @@ static int logincont2(void *obj, struct passwd **uam_pwd,
     gcry_mpi_scan(&retServerNonce, GCRYMPI_FMT_USG, ibuf, 16, NULL);
     gcry_mpi_sub_ui(retServerNonce, retServerNonce, 1);
     if ( gcry_mpi_cmp( serverNonce, retServerNonce) != 0) {
-       /* We're hacked!  */
+        /* We're hacked!  */
         ret = AFPERR_NOTAUTH;
         goto error_ctx;
     }
     ibuf += 16;
 
-    LOG(log_info, logtype_uams, "DHX2: logincont2 alive!");
-
     /* ---- Start authentication with PAM --- */
 
+    /* The password is in legacy Mac encoding, convert it to host encoding */
+    if (convert_string_allocate(CH_MAC, CH_UNIX, ibuf, -1, &utfpass) == (size_t)-1) {
+        LOG(log_error, logtype_uams, "DHX2: conversion error");
+        goto error_ctx;
+    }
+    PAM_password = utfpass;
+
+#ifdef DEBUG
+    LOG(log_maxdebug, logtype_default, "DHX2: password: %s", PAM_password);
+#endif
+
     /* Set these things up for the conv function */
-    PAM_password = ibuf;
 
     ret = AFPERR_NOTAUTH;
     PAM_error = pam_start("netatalk", PAM_username, &PAM_conversation, &pamh);
     if (PAM_error != PAM_SUCCESS) {
-       LOG(log_info, logtype_uams, "DHX2: PAM_Error: %s",
-           pam_strerror(pamh,PAM_error));
-       goto error_ctx;
+        LOG(log_info, logtype_uams, "DHX2: PAM_Error: %s", pam_strerror(pamh,PAM_error));
+        goto error_ctx;
     }
 
     /* solaris craps out if PAM_TTY and PAM_RHOST aren't set. */
     pam_set_item(pamh, PAM_TTY, "afpd");
     pam_set_item(pamh, PAM_RHOST, hostname);
+    pam_set_item(pamh, PAM_RUSER, PAM_username);
+
     PAM_error = pam_authenticate(pamh, 0);
     if (PAM_error != PAM_SUCCESS) {
-       if (PAM_error == PAM_MAXTRIES)
-           ret = AFPERR_PWDEXPR;
-       LOG(log_info, logtype_uams, "DHX2: PAM_Error: %s",
-           pam_strerror(pamh, PAM_error));
-       goto error_ctx;
+        if (PAM_error == PAM_MAXTRIES)
+            ret = AFPERR_PWDEXPR;
+        LOG(log_info, logtype_uams, "DHX2: PAM_Error: %s", pam_strerror(pamh, PAM_error));
+
+        if (!obj->options.adminauthuser)
+            goto error_ctx;
+        if (loginasroot(obj->options.adminauthuser, &hostname, PAM_error) != PAM_SUCCESS) {
+            goto error_ctx;
+        }
     }
 
     PAM_error = pam_acct_mgmt(pamh, 0);
     if (PAM_error != PAM_SUCCESS ) {
-       LOG(log_info, logtype_uams, "DHX2: PAM_Error: %s",
-           pam_strerror(pamh, PAM_error));
-       if (PAM_error == PAM_NEW_AUTHTOK_REQD)    /* password expired */
-           ret = AFPERR_PWDEXPR;
+        LOG(log_info, logtype_uams, "DHX2: PAM_Error: %s",
+            pam_strerror(pamh, PAM_error));
+        if (PAM_error == PAM_NEW_AUTHTOK_REQD)    /* password expired */
+            ret = AFPERR_PWDEXPR;
 #ifdef PAM_AUTHTOKEN_REQD
-       else if (PAM_error == PAM_AUTHTOKEN_REQD)
-           ret = AFPERR_PWDCHNG;
+        else if (PAM_error == PAM_AUTHTOKEN_REQD)
+            ret = AFPERR_PWDCHNG;
 #endif
-       else
-           goto error_ctx;
+        goto error_ctx;
     }
 
 #ifndef PAM_CRED_ESTABLISH
@@ -667,44 +690,47 @@ static int logincont2(void *obj, struct passwd **uam_pwd,
 #endif
     PAM_error = pam_setcred(pamh, PAM_CRED_ESTABLISH);
     if (PAM_error != PAM_SUCCESS) {
-       LOG(log_info, logtype_uams, "DHX2: PAM_Error: %s",
-           pam_strerror(pamh, PAM_error));
-       goto error_ctx;
+        LOG(log_info, logtype_uams, "DHX2: PAM_Error: %s",
+            pam_strerror(pamh, PAM_error));
+        goto error_ctx;
     }
 
     PAM_error = pam_open_session(pamh, 0);
     if (PAM_error != PAM_SUCCESS) {
-       LOG(log_info, logtype_uams, "DHX2: PAM_Error: %s",
-           pam_strerror(pamh, PAM_error));
-       goto error_ctx;
+        LOG(log_info, logtype_uams, "DHX2: PAM_Error: %s",
+            pam_strerror(pamh, PAM_error));
+        goto error_ctx;
     }
 
     memset(ibuf, 0, 256); /* zero out the password */
+    if (utfpass)
+        memset(utfpass, 0, strlen(utfpass));
     *uam_pwd = dhxpwd;
     LOG(log_info, logtype_uams, "DHX2: PAM Auth OK!");
-    if ( ret == AFPERR_PWDEXPR)
-        return ret;
+
     ret = AFP_OK;
 
 error_ctx:
     gcry_cipher_close(ctx);
 error_noctx:
+    if (utfpass) free(utfpass);
     free(K_MD5hash);
     K_MD5hash=NULL;
     gcry_mpi_release(serverNonce);
-    gcry_mpi_release(retServerNonce);    
+    gcry_mpi_release(retServerNonce);
     return ret;
 }
 
 static int pam_logincont(void *obj, struct passwd **uam_pwd,
-                         char *ibuf, int ibuflen,
-                         char *rbuf, int *rbuflen)
+                         char *ibuf, size_t ibuflen,
+                         char *rbuf, size_t *rbuflen)
 {
-    u_int16_t retID;
+    uint16_t retID;
     int ret;
 
     /* check for session id */
-    retID = ntohs(*(u_int16_t *)ibuf);
+    memcpy(&retID, ibuf, sizeof(uint16_t));
+    retID = ntohs(retID);
     if (retID == ID)
         ret = logincont1(obj, ibuf, ibuflen, rbuf, rbuflen);
     else if (retID == ID+1)
@@ -718,7 +744,7 @@ static int pam_logincont(void *obj, struct passwd **uam_pwd,
 
 
 /* logout */
-static void pam_logout() {
+static void pam_logout(void) {
     pam_close_session(pamh, 0);
     pam_end(pamh, 0);
     pamh = NULL;
@@ -728,7 +754,7 @@ static void pam_logout() {
  * --- Change pwd stuff --- */
 
 static int changepw_1(void *obj, char *uname,
-                     char *ibuf, int ibuflen, char *rbuf, int *rbuflen)
+                      char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
 {
     *rbuflen = 0;
 
@@ -737,21 +763,21 @@ static int changepw_1(void *obj, char *uname,
     return( dhx2_setup(obj, ibuf, ibuflen, rbuf, rbuflen) );
 }
 
-static int changepw_2(void *obj, 
-                     char *ibuf, int ibuflen, char *rbuf, int *rbuflen)
+static int changepw_2(void *obj,
+                      char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
 {
     return( logincont1(obj, ibuf, ibuflen, rbuf, rbuflen) );
 }
 
 static int changepw_3(void *obj _U_,
-                     char *ibuf, int ibuflen _U_, 
-                     char *rbuf _U_, int *rbuflen _U_)
+                      char *ibuf, size_t ibuflen _U_,
+                      char *rbuf _U_, size_t *rbuflen _U_)
 {
     int ret;
     int PAM_error;
     uid_t uid;
     pam_handle_t *lpamh;
-    char *hostname = NULL;
+    const char *hostname = NULL;
     gcry_mpi_t retServerNonce;
     gcry_cipher_hd_t ctx;
     gcry_error_t ctxerror;
@@ -812,14 +838,14 @@ static int changepw_3(void *obj _U_,
     ibuf += 16;
 
     /* ---- Start pwd changing with PAM --- */
-    ibuf[255] = '\0';          /* For safety */
+    ibuf[255] = '\0';       /* For safety */
     ibuf[511] = '\0';
 
     /* check if new and old password are equal */
     if (memcmp(ibuf, ibuf + 256, 255) == 0) {
-       LOG(log_info, logtype_uams, "DHX2 Chgpwd: new and old password are equal");
+        LOG(log_info, logtype_uams, "DHX2 Chgpwd: new and old password are equal");
         ret = AFPERR_PWDSAME;
-       goto error_ctx;
+        goto error_ctx;
     }
 
     /* Set these things up for the conv function. PAM_username was set in changepw_1 */
@@ -827,7 +853,7 @@ static int changepw_3(void *obj _U_,
     PAM_error = pam_start("netatalk", PAM_username, &PAM_conversation, &lpamh);
     if (PAM_error != PAM_SUCCESS) {
         LOG(log_info, logtype_uams, "DHX2 Chgpwd: PAM error in pam_start");
-       ret = AFPERR_PARAM;
+        ret = AFPERR_PARAM;
         goto error_ctx;
     }
     pam_set_item(lpamh, PAM_TTY, "afpd");
@@ -837,21 +863,21 @@ static int changepw_3(void *obj _U_,
     seteuid(0);
     PAM_error = pam_authenticate(lpamh,0);
     if (PAM_error != PAM_SUCCESS) {
-       LOG(log_info, logtype_uams, "DHX2 Chgpwd: error authenticating with PAM");
-       seteuid(uid);
-       pam_end(lpamh, PAM_error);
-       ret = AFPERR_NOTAUTH;
-       goto error_ctx;
+        LOG(log_info, logtype_uams, "DHX2 Chgpwd: error authenticating with PAM");
+        seteuid(uid);
+        pam_end(lpamh, PAM_error);
+        ret = AFPERR_NOTAUTH;
+        goto error_ctx;
     }
     PAM_password = ibuf;
     PAM_error = pam_chauthtok(lpamh, 0);
     seteuid(uid); /* un-root ourselves. */
     memset(ibuf, 0, 512);
     if (PAM_error != PAM_SUCCESS) {
-       LOG(log_info, logtype_uams, "DHX2 Chgpwd: error changing pw with PAM");
-       pam_end(lpamh, PAM_error);
-       ret = AFPERR_ACCESS;
-       goto error_ctx;
+        LOG(log_info, logtype_uams, "DHX2 Chgpwd: error changing pw with PAM");
+        pam_end(lpamh, PAM_error);
+        ret = AFPERR_ACCESS;
+        goto error_ctx;
     }
     pam_end(lpamh, 0);
     ret = AFP_OK;
@@ -867,8 +893,8 @@ error_noctx:
 }
 
 static int dhx2_changepw(void *obj _U_, char *uname,
-                        struct passwd *pwd _U_, char *ibuf, int ibuflen _U_,
-                        char *rbuf _U_, int *rbuflen _U_)
+                         struct passwd *pwd _U_, char *ibuf, size_t ibuflen _U_,
+                         char *rbuf _U_, size_t *rbuflen _U_)
 {
     /* We use this to serialize the three incoming FPChangePassword calls */
     static int dhx2_changepw_status = 1;
@@ -877,22 +903,22 @@ static int dhx2_changepw(void *obj _U_, char *uname,
 
     switch (dhx2_changepw_status) {
     case 1:
-       ret = changepw_1( obj, uname, ibuf, ibuflen, rbuf, rbuflen);
-       if ( ret == AFPERR_AUTHCONT)
-           dhx2_changepw_status = 2;
-       break;
+        ret = changepw_1( obj, uname, ibuf, ibuflen, rbuf, rbuflen);
+        if ( ret == AFPERR_AUTHCONT)
+            dhx2_changepw_status = 2;
+        break;
     case 2:
-       ret = changepw_2( obj, ibuf, ibuflen, rbuf, rbuflen);
+        ret = changepw_2( obj, ibuf, ibuflen, rbuf, rbuflen);
         if ( ret == AFPERR_AUTHCONT)
             dhx2_changepw_status = 3;
-       else
-           dhx2_changepw_status = 1;
-       break;
+        else
+            dhx2_changepw_status = 1;
+        break;
     case 3:
-       ret = changepw_3( obj, ibuf, ibuflen, rbuf, rbuflen);
-       dhx2_changepw_status = 1; /* Whether is was succesfull or not: we
-                                    restart anyway !*/
-       break;
+        ret = changepw_3( obj, ibuf, ibuflen, rbuf, rbuflen);
+        dhx2_changepw_status = 1; /* Whether is was succesfull or not: we
+                                     restart anyway !*/
+        break;
     }
     return ret;
 }
@@ -904,6 +930,14 @@ static int uam_setup(const char *path)
         return -1;
     if (uam_register(UAM_SERVER_CHANGEPW, path, "DHX2", dhx2_changepw) < 0)
         return -1;
+
+    LOG(log_debug, logtype_uams, "DHX2: generating mersenne primes");
+    /* Generate p and g for DH */
+    if (dh_params_generate(PRIMEBITS) != 0) {
+        LOG(log_error, logtype_uams, "DHX2: Couldn't generate p and g");
+        return -1;
+    }
+
     return 0;
 }
 
@@ -911,8 +945,12 @@ static void uam_cleanup(void)
 {
     uam_unregister(UAM_SERVER_LOGIN, "DHX2");
     uam_unregister(UAM_SERVER_CHANGEPW, "DHX2");
-}
 
+    LOG(log_debug, logtype_uams, "DHX2: uam_cleanup");
+
+    gcry_mpi_release(p);
+    gcry_mpi_release(g);
+}
 
 UAM_MODULE_EXPORT struct uam_export uams_dhx2 = {
     UAM_MODULE_SERVER,
@@ -928,4 +966,3 @@ UAM_MODULE_EXPORT struct uam_export uams_dhx2_pam = {
 };
 
 #endif /* USE_PAM && UAM_DHX2 */
-