pkgconfdir = @PKGCONFDIR@
-if USE_DHX
+if HAVE_OPENSSL
bin_PROGRAMS = afppasswd
else
bin_PROGRAMS =
-D_PATH_AFPDPWFILE=\"$(pkgconfdir)/afppasswd\"
install-exec-hook:
-if USE_DHX
+if HAVE_OPENSSL
chmod u+s $(DESTDIR)$(bindir)/afppasswd
endif
\ No newline at end of file
-dnl $Id: configure.in,v 1.179.2.3.2.37.2.7 2006-09-07 05:02:20 didg Exp $
+dnl $Id: configure.in,v 1.179.2.3.2.37.2.8 2008-12-02 03:11:58 didg Exp $
dnl configure.in for netatalk
AC_INIT(etc/afpd/main.c)
sysv_style=tru64
fi
-dnl -- look for openssl
+dnl -- check for libgcrypt, if found enables DHX UAM
+AM_PATH_LIBGCRYPT([1:1.2.3],[neta_cv_compile_dhx2=yes
+ neta_cv_have_libgcrypt=yes
+ AC_MSG_NOTICE([Enabling DHX2 UAM])
+ AC_DEFINE(HAVE_LIBGCRYPT, 1, [Define if the DHX2 modules should be built with libgcrypt])
+ AC_DEFINE(UAM_DHX2, 1, [Define if the DHX2 UAM modules should be compiled])
+ ])
+
+dnl -- look for openssl, if found enables DHX UAM and Randnum UAM
AC_PATH_SSL
dnl -- check for crypt
AC_ARG_ENABLE(pgp-uam,
[ --enable-pgp-uam enable build of PGP UAM module],[
if test "$enableval" = "yes"; then
- if test "$compile_ssl" = "yes"; then
+ if test "x$neta_cv_have_openssl" = "xyes"; then
AC_DEFINE(UAM_PGP, 1, [Define if the PGP UAM module should be compiled])
compile_pgp=yes
AC_MSG_RESULT([yes])
AM_CONDITIONAL(SOLARIS_MODULE, test x$solaris_module = xyes)
AM_CONDITIONAL(COMPILE_TIMELORD, test x$compile_timelord = xyes)
AM_CONDITIONAL(COMPILE_A2BOOT, test x$compile_a2boot = xyes)
-AM_CONDITIONAL(USE_DHX, test x$compile_ssl = xyes)
+AM_CONDITIONAL(HAVE_LIBGCRYPT, test x$neta_cv_have_libgcrypt = xyes)
+AM_CONDITIONAL(HAVE_OPENSSL, test x$neta_cv_have_openssl = xyes)
+AM_CONDITIONAL(USE_DHX, test x$neta_cv_compile_dhx = xyes)
+AM_CONDITIONAL(USE_DHX2, test x$neta_cv_compile_dhx2 = xyes)
+AM_CONDITIONAL(USE_RANDNUM, test x$neta_cv_have_openssl = xyes)
AM_CONDITIONAL(USE_KERBEROS, test x$compile_kerberos = xyes)
AM_CONDITIONAL(USE_PAM_SO, test x$use_pam_so = xyes)
AM_CONDITIONAL(USE_PAM, test x$netatalk_cv_install_pam = xyes)
AM_CONDITIONAL(BUILD_PAM, test x$compile_pam = xyes)
AM_CONDITIONAL(USE_PGP, test x$compile_pgp = xyes)
+AM_CONDITIONAL(DEFAULT_HOOK, test x$neta_cv_have_libgcrypt != xyes && test x$neta_cv_have_openssl != xyes)
AM_CONDITIONAL(USE_COBALT, test x$sysv_style = xcobalt)
AM_CONDITIONAL(USE_NETBSD, test x$sysv_style = xnetbsd)
AM_CONDITIONAL(USE_REDHAT, test x$sysv_style = xredhat)
#
UAMS_GENERIC = uams_guest.la uams_passwd.la
+uams_LINKS = uams_clrtxt.so
+dhx_exec_hook = echo
+dhx2_exec_hook = echo
+
+# these are complex: check if DHX and DHX2 module should be build
if USE_DHX
-UAMS_DHX_GENERIC = uams_randnum.la uams_dhx_passwd.la
+if HAVE_OPENSSL
+uams_LINKS += uams_dhx.so
+UAMS_DHX = uams_dhx_passwd.la
+if BUILD_PAM
+UAMS_DHX_PAM = uams_dhx_pam.la
+endif
+if USE_PAM_SO
+dhx_exec_hook += && $(LN_S) uams_dhx_pam.so uams_dhx.so
+else
+dhx_exec_hook += && $(LN_S) uams_dhx_passwd.so uams_dhx.so
endif
-if USE_PGP
-UAMS_PGP = uams_pgp.la
+endif
endif
+if USE_DHX2
+if HAVE_LIBGCRYPT
+uams_LINKS += uams_dhx2.so
+UAMS_DHX2 = uams_dhx2_passwd.la
+if BUILD_PAM
+UAMS_DHX2_PAM = uams_dhx2_pam.la
+endif
+if USE_PAM_SO
+dhx2_exec_hook += && $(LN_S) uams_dhx2_pam.so uams_dhx2.so
+else
+dhx2_exec_hook += && $(LN_S) uams_dhx2_passwd.so uams_dhx2.so
+endif
+endif
+endif
+
+# these are simple, though some the last three depend on OpenSSL
+
if BUILD_PAM
UAMS_PAM = uams_pam.la
-if USE_DHX
-UAMS_DHX_PAM = uams_dhx_pam.la
endif
+
+if USE_RANDNUM
+UAMS_RANDNUM = uams_randnum.la
+endif
+
+if USE_PGP
+UAMS_PGP = uams_pgp.la
endif
if USE_GSSAPI
endif
# links
+
if USE_PAM_SO
UAMS_CLRTXT_LINK = uams_pam.so
-UAMS_DHX_LINK = uams_dhx_pam.so
else
UAMS_CLRTXT_LINK = uams_passwd.so
-UAMS_DHX_LINK = uams_dhx_passwd.so
endif
#
uams_pgp_la_SOURCES = uams_pgp.c
uams_dhx_passwd_la_SOURCES = uams_dhx_passwd.c
uams_dhx_pam_la_SOURCES = uams_dhx_pam.c
+uams_dhx2_passwd_la_SOURCES = uams_dhx2_passwd.c
+uams_dhx2_pam_la_SOURCES = uams_dhx2_pam.c
uams_gss_la_SOURCES = uams_gss.c
#
#
# do that on behalf of the brokeness of automake 1.4
-CFLAGS = @CFLAGS@ @SSL_CFLAGS@
+CFLAGS = @CFLAGS@ @SSL_CFLAGS@ @LIBGCRYPT_CFLAGS@
uams_guest_la_CFLAGS = @CFLAGS@
uams_randnum_la_CFLAGS = @CFLAGS@ @SSL_CFLAGS@
uams_pgp_la_CFLAGS = @CFLAGS@ @SSL_CFLAGS@
uams_dhx_passwd_la_CFLAGS = @CFLAGS@ @SSL_CFLAGS@
uams_dhx_pam_la_CFLAGS = @CFLAGS@ @SSL_CFLAGS@ @PAM_CFLAGS@
+uams_dhx2_passwd_la_CFLAGS = @CFLAGS@ @LIBGCRYPT_CFLAGS@
+uams_dhx2_pam_la_CFLAGS = @CFLAGS@ @LIBGCRYPT_CFLAGS@ @PAM_CFLAGS@
uams_gss_la_CFLAGS = @CFLAGS@ @GSSAPI_CFLAGS@
uams_guest_la_LDFLAGS = -module -avoid-version
uams_pam_la_LDFLAGS = -module -avoid-version @PAM_LIBS@
uams_pgp_la_LDFLAGS = -module -avoid-version @SSL_LIBS@
uams_dhx_passwd_la_LDFLAGS = -module -avoid-version @CRYPT_LIBS@ @SSL_LIBS@
-uams_dhx_pam_la_LDFLAGS = -module -avoid-version @SSL_LIBS@ @PAM_LIBS@
+uams_dhx_pam_la_LDFLAGS = -module -avoid-version @CRYPT_LIBS@ @SSL_LIBS@ @PAM_LIBS@
+uams_dhx2_passwd_la_LDFLAGS = -module -avoid-version @CRYPT_LIBS@ @LIBGCRYPT_LIBS@
+uams_dhx2_pam_la_LDFLAGS = -module -avoid-version @LIBGCRYPT_LIBS@ @PAM_LIBS@
uams_gss_la_LDFLAGS = -module -avoid-version @GSSAPI_LIBS@
#
$(UAMS_GENERIC) \
$(UAMS_PGP) \
$(UAMS_PAM) \
- $(UAMS_DHX_GENERIC) \
+ $(UAMS_RANDNUM) \
+ $(UAMS_DHX) \
$(UAMS_DHX_PAM) \
+ $(UAMS_DHX2) \
+ $(UAMS_DHX2_PAM) \
$(UAMS_GSSAPI)
#
# link creation
#
-uams_LINKS =
-
-if USE_DHX
install-exec-hook:
(cd $(DESTDIR)$(uamsdir) && \
- rm -f uams_clrtxt.so uams_dhx.so && \
+ rm -f $(uams_LINKS) && \
$(LN_S) $(UAMS_CLRTXT_LINK) uams_clrtxt.so && \
- $(LN_S) $(UAMS_DHX_LINK) uams_dhx.so \
+ $(dhx_exec_hook) && \
+ $(dhx2_exec_hook) \
)
-uninstall-hook:
- (cd $(DESTDIR)$(uamsdir) && \
- rm -f uams_clrtxt.so uams_dhx.so \
- )
-else
-install-exec-hook:
- (cd $(DESTDIR)$(uamsdir) && \
- rm -f uams_clrtxt.so && \
- $(LN_S) $(UAMS_CLRTXT_LINK) uams_clrtxt.so \
- )
+
uninstall-hook:
(cd $(DESTDIR)$(uamsdir) && \
- rm -f uams_clrtxt.so \
+ rm -f $(uams_LINKS) \
)
-endif
--- /dev/null
+/*
+ * $Id: uams_dhx2_pam.c,v 1.5.2.2 2008-12-02 03:11:59 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#if defined (USE_PAM) && defined (UAM_DHX2)
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <atalk/logger.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <errno.h>
+#ifdef HAVE_SECURITY_PAM_APPL_H
+#include <security/pam_appl.h>
+#endif
+#ifdef HAVE_PAM_PAM_APPL_H
+#include <pam/pam_appl.h>
+#endif
+
+
+#ifdef HAVE_LIBGCRYPT
+#include <gcrypt.h>
+#endif /* HAVE_LIBGCRYPT */
+
+#include <atalk/afp.h>
+#include <atalk/uam.h>
+#include "../afpd/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) ^ \
+ (unsigned long) (a)) & 0xffff)
+
+/* Some parameters need be maintained across calls */
+static gcry_mpi_t p, Ra;
+static gcry_mpi_t serverNonce;
+static char *K_MD5hash = NULL;
+static int K_hash_len;
+static u_int16_t ID;
+
+/* The initialization vectors for CAST128 are fixed by Apple. */
+static unsigned char dhx_c2siv[] = { 'L', 'W', 'a', 'l', 'l', 'a', 'c', 'e' };
+static unsigned char dhx_s2civ[] = { 'C', 'J', 'a', 'l', 'b', 'e', 'r', 't' };
+
+/* Static variables used to communicate between the conversation function
+ * and the server_login function */
+static pam_handle_t *pamh = NULL;
+static char *PAM_username;
+static char *PAM_password;
+static struct passwd *dhxpwd;
+
+/*********************************************************
+ * Crypto helper func to generate p and g for use in DH.
+ * libgcrypt doesn't provide one directly.
+ * Algorithm taken from GNUTLS:gnutls_dh_primes.c
+ *********************************************************/
+
+/**
+ * This function will generate a new pair of prime and generator for use in
+ * 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) {
+
+ 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;
+ }
+
+ if (bits < 256)
+ qbits = bits / 2;
+ else
+ qbits = (bits / 40) + 105;
+
+ if (qbits & 1) /* better have an even number */
+ 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++;
+ } while (err != 0 && times < 10);
+
+ if (err != 0) {
+ result = AFPERR_MISC;
+ goto error;
+ }
+
+ /* generate the group generator. */
+ err = gcry_prime_group_generator (&g, prime, 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);
+
+ return 0;
+
+error:
+ gcry_prime_release_factors (factors);
+ gcry_mpi_release (g);
+ gcry_mpi_release (prime);
+
+ return result;
+}
+
+
+/* PAM conversation function
+ * Here we assume (for now, at least) that echo on means login name, and
+ * echo off means password.
+ */
+static int PAM_conv (int num_msg,
+ const struct pam_message **msg,
+ struct pam_response **resp,
+ void *appdata_ptr _U_) {
+ int count = 0;
+ struct pam_response *reply;
+
+#define COPY_STRING(s) (s) ? strdup(s) : NULL
+
+ errno = 0;
+
+ if (num_msg < 1) {
+ /* Log Entry */
+ LOG(log_info, logtype_uams, "PAM DHX2 Conversation Err -- %s",
+ strerror(errno));
+ /* Log Entry */
+ return PAM_CONV_ERR;
+ }
+
+ reply = (struct pam_response *)
+ calloc(num_msg, sizeof(struct pam_response));
+
+ if (!reply) {
+ /* Log Entry */
+ LOG(log_info, logtype_uams, "PAM DHX2: Conversation Err -- %s",
+ strerror(errno));
+ /* Log Entry */
+ return PAM_CONV_ERR;
+ }
+
+ for (count = 0; count < num_msg; count++) {
+ char *string = NULL;
+
+ switch (msg[count]->msg_style) {
+ case PAM_PROMPT_ECHO_ON:
+ if (!(string = COPY_STRING(PAM_username))) {
+ /* Log Entry */
+ LOG(log_info, logtype_uams, "PAM DHX2: username failure -- %s",
+ strerror(errno));
+ /* Log Entry */
+ goto pam_fail_conv;
+ }
+ break;
+ case PAM_PROMPT_ECHO_OFF:
+ if (!(string = COPY_STRING(PAM_password))) {
+ /* Log Entry */
+ LOG(log_info, logtype_uams, "PAM DHX2: passwd failure: --: %s",
+ strerror(errno));
+ /* Log Entry */
+ goto pam_fail_conv;
+ }
+ break;
+ case PAM_TEXT_INFO:
+#ifdef PAM_BINARY_PROMPT
+ case PAM_BINARY_PROMPT:
+#endif /* PAM_BINARY_PROMPT */
+ /* ignore it... */
+ break;
+ case PAM_ERROR_MSG:
+ default:
+ LOG(log_info, logtype_uams, "PAM DHX2: Binary_Prompt -- %s", strerror(errno));
+ goto pam_fail_conv;
+ }
+
+ if (string) {
+ reply[count].resp_retcode = 0;
+ reply[count].resp = string;
+ string = NULL;
+ }
+ }
+
+ *resp = reply;
+ LOG(log_info, logtype_uams, "PAM DHX2: PAM Success");
+ return PAM_SUCCESS;
+
+pam_fail_conv:
+ for (count = 0; count < num_msg; count++) {
+ if (!reply[count].resp)
+ continue;
+ switch (msg[count]->msg_style) {
+ case PAM_PROMPT_ECHO_OFF:
+ case PAM_PROMPT_ECHO_ON:
+ free(reply[count].resp);
+ break;
+ }
+ }
+ free(reply);
+ /* Log Entry */
+ LOG(log_info, logtype_uams, "PAM DHX2: Conversation Err -- %s",
+ strerror(errno));
+ /* Log Entry */
+ return PAM_CONV_ERR;
+}
+
+static struct pam_conv PAM_conversation = {
+ &PAM_conv,
+ NULL
+};
+
+
+static int dhx2_setup(void *obj, char *ibuf _U_, int ibuflen _U_,
+ char *rbuf, int *rbuflen)
+{
+ int ret;
+ size_t nwritten;
+ gcry_mpi_t g, Ma;
+ char *Ra_binary = NULL;
+
+ *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;
+ }
+ gcry_randomize(Ra_binary, PRIMEBITS/8, GCRY_STRONG_RANDOM);
+ gcry_mpi_scan(&Ra, GCRYMPI_FMT_USG, Ra_binary, PRIMEBITS/8, NULL);
+ free(Ra_binary);
+ Ra_binary = NULL;
+
+ /* Ma = g^Ra mod p. This is our "public" key */
+ gcry_mpi_powm(Ma, g, Ra, p);
+
+ /* ------- DH Init done ------ */
+ /* Start building reply packet */
+
+ /* Session ID first */
+ ID = dhxhash(obj);
+ *(u_int16_t *)rbuf = htons(ID);
+ 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);
+ }
+ rbuf += 4;
+ *rbuflen += 4;
+
+ /* len = length of p = PRIMEBITS/8 */
+ *(u_int16_t *)rbuf = htons((u_int16_t) PRIMEBITS/8);
+ rbuf += 2;
+ *rbuflen += 2;
+
+ /* p */
+ gcry_mpi_print( GCRYMPI_FMT_USG, (unsigned char *)rbuf, PRIMEBITS/8, NULL, p);
+ rbuf += PRIMEBITS/8;
+ *rbuflen += PRIMEBITS/8;
+
+ /* 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);
+ }
+ 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);
+ 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)
+{
+ if (( dhxpwd = uam_getname(obj, username, ulen)) == NULL ) {
+ LOG(log_info, logtype_uams, "DHX2: unknown username");
+ return AFPERR_PARAM;
+ }
+
+ PAM_username = username;
+ LOG(log_info, logtype_uams, "DHX2 login: %s", username);
+ return dhx2_setup(obj, ibuf, ibuflen, rbuf, rbuflen);
+}
+
+/* -------------------------------- */
+/* 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 *username;
+ int len, ulen;
+
+ *rbuflen = 0;
+
+ /* grab some of the options */
+ if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, (void *) &username, &ulen) < 0) {
+ LOG(log_info, logtype_uams, "DHX2: uam_afpserver_option didn't meet uam_option_username -- %s",
+ strerror(errno));
+ return AFPERR_PARAM;
+ }
+
+ len = (unsigned char) *ibuf++;
+ if ( len > ulen ) {
+ LOG(log_info, logtype_uams, "DHX2: Signature Retieval Failure -- %s",
+ strerror(errno));
+ return AFPERR_PARAM;
+ }
+
+ memcpy(username, ibuf, len );
+ ibuf += len;
+ username[ len ] = '\0';
+
+ if ((unsigned long) ibuf & 1) /* pad to even boundary */
+ ++ibuf;
+
+ return (login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
+}
+
+/* ----------------------------- */
+static int pam_login_ext(void *obj, char *uname, struct passwd **uam_pwd,
+ char *ibuf, int ibuflen,
+ char *rbuf, int *rbuflen)
+{
+ char *username;
+ int len, ulen;
+ u_int16_t temp16;
+
+ *rbuflen = 0;
+
+ /* grab some of the options */
+ if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, (void *) &username, &ulen) < 0) {
+ LOG(log_info, logtype_uams, "DHX2: uam_afpserver_option didn't meet uam_option_username -- %s",
+ strerror(errno));
+ return AFPERR_PARAM;
+ }
+
+ if (*uname != 3)
+ return AFPERR_PARAM;
+ uname++;
+ memcpy(&temp16, uname, sizeof(temp16));
+ len = ntohs(temp16);
+
+ if ( !len || len > ulen ) {
+ LOG(log_info, logtype_uams, "DHX2: Signature Retrieval Failure -- %s",
+ strerror(errno));
+ return AFPERR_PARAM;
+ }
+ memcpy(username, uname +2, len );
+ username[ len ] = '\0';
+
+ return (login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
+}
+
+/* -------------------------------- */
+
+static int logincont1(void *obj _U_, char *ibuf, int ibuflen, char *rbuf, int *rbuflen)
+{
+ int ret;
+ size_t nwritten;
+ gcry_mpi_t Mb, K, clientNonce;
+ unsigned char *K_bin = NULL;
+ char serverNonce_bin[16];
+ gcry_cipher_hd_t ctx;
+ gcry_error_t ctxerror;
+
+ *rbuflen = 0;
+
+ Mb = gcry_mpi_new(0);
+ K = gcry_mpi_new(0);
+ clientNonce = gcry_mpi_new(0);
+ serverNonce = gcry_mpi_new(0);
+
+ /* 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");
+ ret = AFPERR_PARAM;
+ goto error_noctx;
+ }
+
+ /* Skip session id */
+ ibuf += 2;
+
+ /* Extract Mb, client's "public" key */
+ gcry_mpi_scan(&Mb, GCRYMPI_FMT_USG, ibuf, PRIMEBITS/8, NULL);
+ ibuf += PRIMEBITS/8;
+
+ /* Now finally generate the Key: K = Mb^Ra mod p */
+ gcry_mpi_powm(K, Mb, Ra, p);
+
+ /* 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;
+ }
+ 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);
+ }
+
+ /* ... 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;
+ }
+ gcry_md_hash_buffer(GCRY_MD_MD5, K_MD5hash, K_bin, PRIMEBITS/8);
+ free(K_bin);
+ K_bin = NULL;
+
+ /* FIXME: To support the Reconnect UAM, we need to store this key somewhere */
+
+ /* 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;
+ 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;
+ 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;
+ 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;
+ goto error_ctx;
+ }
+ /* Pull out clients nonce */
+ gcry_mpi_scan(&clientNonce, GCRYMPI_FMT_USG, ibuf, 16, NULL);
+ /* Increment nonce */
+ gcry_mpi_add_ui(clientNonce, clientNonce, 1);
+
+ /* Generate our nonce and remember it for Logincont2 */
+ gcry_create_nonce(serverNonce_bin, 16); /* We'll use this here */
+ gcry_mpi_scan(&serverNonce, GCRYMPI_FMT_USG, serverNonce_bin, 16, NULL); /* For use in Logincont2 */
+
+ /* ---- Start building reply packet ---- */
+
+ /* Session ID + 1 first */
+ *(u_int16_t *)rbuf = htons(ID+1);
+ rbuf += 2;
+ *rbuflen += 2;
+
+ /* Client nonce + 1 */
+ gcry_mpi_print(GCRYMPI_FMT_USG, (unsigned char *)rbuf, PRIMEBITS/8, NULL, clientNonce);
+ /* Server nonce */
+ memcpy(rbuf+16, serverNonce_bin, 16);
+
+ /* 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;
+ 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;
+ }
+ rbuf += 32;
+ *rbuflen += 32;
+
+ ret = AFPERR_AUTHCONT;
+ goto exit;
+
+error_ctx:
+ gcry_cipher_close(ctx);
+error_noctx:
+ gcry_mpi_release(serverNonce);
+ free(K_MD5hash);
+ K_MD5hash=NULL;
+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)
+{
+ int ret;
+ int PAM_error;
+ char *hostname = NULL;
+ gcry_mpi_t retServerNonce;
+ gcry_cipher_hd_t ctx;
+ gcry_error_t ctxerror;
+
+ *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");
+ ret = AFPERR_PARAM;
+ goto error_noctx;
+ }
+
+ retServerNonce = gcry_mpi_new(0);
+
+ /* For PAM */
+ uam_afpserver_option(obj, UAM_OPTION_CLIENTNAME, (void *) &hostname, NULL);
+
+ /* 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;
+ 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;
+ 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;
+ goto error_ctx;
+ }
+
+ /* Skip Session ID */
+ ibuf += 2;
+
+ /* Finally: decrypt client's md5_K(serverNonce+1, passwor, C2SIV) inplace */
+ ctxerror = gcry_cipher_decrypt(ctx, ibuf, 16+256, NULL, 0);
+ if (gcry_err_code(ctxerror) != GPG_ERR_NO_ERROR) {
+ ret = AFPERR_MISC;
+ goto error_ctx;
+ }
+ /* Pull out nonce. Should be serverNonce+1 */
+ 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! */
+ ret = AFPERR_NOTAUTH;
+ goto error_ctx;
+ }
+ ibuf += 16;
+
+ LOG(log_info, logtype_uams, "DHX2: logincont2 alive!");
+
+ /* ---- Start authentication with PAM --- */
+
+ /* 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;
+ }
+
+ /* 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_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;
+ }
+
+ 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;
+#ifdef PAM_AUTHTOKEN_REQD
+ else if (PAM_error == PAM_AUTHTOKEN_REQD)
+ ret = AFPERR_PWDCHNG;
+#endif
+ else
+ goto error_ctx;
+ }
+
+#ifndef PAM_CRED_ESTABLISH
+#define PAM_CRED_ESTABLISH PAM_ESTABLISH_CRED
+#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;
+ }
+
+ 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;
+ }
+
+ memset(ibuf, 0, 256); /* zero out the password */
+ *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:
+ free(K_MD5hash);
+ K_MD5hash=NULL;
+ gcry_mpi_release(serverNonce);
+ gcry_mpi_release(retServerNonce);
+ return ret;
+}
+
+static int pam_logincont(void *obj, struct passwd **uam_pwd,
+ char *ibuf, int ibuflen,
+ char *rbuf, int *rbuflen)
+{
+ u_int16_t retID;
+ int ret;
+
+ /* check for session id */
+ retID = ntohs(*(u_int16_t *)ibuf);
+ if (retID == ID)
+ ret = logincont1(obj, ibuf, ibuflen, rbuf, rbuflen);
+ else if (retID == ID+1)
+ ret = logincont2(obj, uam_pwd, ibuf,ibuflen, rbuf, rbuflen);
+ else {
+ LOG(log_info, logtype_uams, "DHX2: Session ID Mismatch");
+ ret = AFPERR_PARAM;
+ }
+ return ret;
+}
+
+
+/* logout */
+static void pam_logout() {
+ pam_close_session(pamh, 0);
+ pam_end(pamh, 0);
+ pamh = NULL;
+}
+
+/****************************
+ * --- Change pwd stuff --- */
+
+static int changepw_1(void *obj, char *uname,
+ char *ibuf, int ibuflen, char *rbuf, int *rbuflen)
+{
+ *rbuflen = 0;
+
+ /* Remember it now, use it in changepw_3 */
+ PAM_username = uname;
+ return( dhx2_setup(obj, ibuf, ibuflen, rbuf, rbuflen) );
+}
+
+static int changepw_2(void *obj,
+ char *ibuf, int ibuflen, char *rbuf, int *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_)
+{
+ int ret;
+ int PAM_error;
+ uid_t uid;
+ pam_handle_t *lpamh;
+ char *hostname = NULL;
+ gcry_mpi_t retServerNonce;
+ gcry_cipher_hd_t ctx;
+ gcry_error_t ctxerror;
+
+ *rbuflen = 0;
+
+ LOG(log_error, logtype_uams, "DHX2 ChangePW: packet 3 processing");
+
+ /* Packet size should be: Session ID + ServerNonce + 2*Passwd buffer */
+ if (ibuflen != 2 + 16 + 2*256) {
+ LOG(log_error, logtype_uams, "DHX2: Paket length not correct");
+ ret = AFPERR_PARAM;
+ goto error_noctx;
+ }
+
+ retServerNonce = gcry_mpi_new(0);
+
+ /* For PAM */
+ uam_afpserver_option(obj, UAM_OPTION_CLIENTNAME, (void *) &hostname, NULL);
+
+ /* 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;
+ 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;
+ 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;
+ goto error_ctx;
+ }
+
+ /* Skip Session ID */
+ ibuf += 2;
+
+ /* Finally: decrypt client's md5_K(serverNonce+1, 2*password, C2SIV) inplace */
+ ctxerror = gcry_cipher_decrypt(ctx, ibuf, 16+2*256, NULL, 0);
+ if (gcry_err_code(ctxerror) != GPG_ERR_NO_ERROR) {
+ ret = AFPERR_MISC;
+ goto error_ctx;
+ }
+ /* Pull out nonce. Should be serverNonce+1 */
+ 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! */
+ ret = AFPERR_NOTAUTH;
+ goto error_ctx;
+ }
+ ibuf += 16;
+
+ /* ---- Start pwd changing with PAM --- */
+ 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");
+ ret = AFPERR_PWDSAME;
+ goto error_ctx;
+ }
+
+ /* Set these things up for the conv function. PAM_username was set in changepw_1 */
+ PAM_password = ibuf + 256;
+ 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;
+ goto error_ctx;
+ }
+ pam_set_item(lpamh, PAM_TTY, "afpd");
+ uam_afpserver_option(obj, UAM_OPTION_CLIENTNAME, (void *) &hostname, NULL);
+ pam_set_item(lpamh, PAM_RHOST, hostname);
+ uid = geteuid();
+ 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;
+ }
+ 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;
+ }
+ pam_end(lpamh, 0);
+ ret = AFP_OK;
+
+error_ctx:
+ gcry_cipher_close(ctx);
+error_noctx:
+ free(K_MD5hash);
+ K_MD5hash=NULL;
+ gcry_mpi_release(serverNonce);
+ gcry_mpi_release(retServerNonce);
+ return ret;
+}
+
+static int dhx2_changepw(void *obj _U_, char *uname,
+ struct passwd *pwd _U_, char *ibuf, int ibuflen _U_,
+ char *rbuf _U_, int *rbuflen _U_)
+{
+ /* We use this to serialize the three incoming FPChangePassword calls */
+ static int dhx2_changepw_status = 1;
+
+ int ret = AFPERR_NOTAUTH; /* gcc can't figure out it's always initialized */
+
+ switch (dhx2_changepw_status) {
+ case 1:
+ 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);
+ if ( ret == AFPERR_AUTHCONT)
+ dhx2_changepw_status = 3;
+ 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;
+ }
+ return ret;
+}
+
+static int uam_setup(const char *path)
+{
+ if (uam_register(UAM_SERVER_LOGIN_EXT, path, "DHX2", pam_login,
+ pam_logincont, pam_logout, pam_login_ext) < 0)
+ return -1;
+ if (uam_register(UAM_SERVER_CHANGEPW, path, "DHX2", dhx2_changepw) < 0)
+ return -1;
+ return 0;
+}
+
+static void uam_cleanup(void)
+{
+ uam_unregister(UAM_SERVER_LOGIN, "DHX2");
+ uam_unregister(UAM_SERVER_CHANGEPW, "DHX2");
+}
+
+
+UAM_MODULE_EXPORT struct uam_export uams_dhx2 = {
+ UAM_MODULE_SERVER,
+ UAM_MODULE_VERSION,
+ uam_setup, uam_cleanup
+};
+
+
+UAM_MODULE_EXPORT struct uam_export uams_dhx2_pam = {
+ UAM_MODULE_SERVER,
+ UAM_MODULE_VERSION,
+ uam_setup, uam_cleanup
+};
+
+#endif /* USE_PAM && UAM_DHX2 */
+
--- /dev/null
+/*
+ * $Id: uams_dhx2_passwd.c,v 1.4.2.2 2008-12-02 03:11:59 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef UAM_DHX2
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <pwd.h>
+
+#ifdef NETBSD
+#define _XOPEN_SOURCE 500 /* for crypt() */
+#endif
+#ifdef FREEBSD
+#define _XOPEN_SOURCE /* for crypt() */
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+
+#ifdef SHADOWPW
+#include <shadow.h>
+#endif
+
+#ifdef HAVE_LIBGCRYPT
+#include <gcrypt.h>
+#endif
+
+#include <atalk/afp.h>
+#include <atalk/uam.h>
+#include <atalk/logger.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) ^ \
+ (unsigned long) (a)) & 0xffff)
+
+/* Some parameters need be maintained across calls */
+static gcry_mpi_t p, Ra;
+static gcry_mpi_t serverNonce;
+static char *K_MD5hash = NULL;
+static int K_hash_len;
+static u_int16_t ID;
+
+/* The initialization vectors for CAST128 are fixed by Apple. */
+static unsigned char dhx_c2siv[] = { 'L', 'W', 'a', 'l', 'l', 'a', 'c', 'e' };
+static unsigned char dhx_s2civ[] = { 'C', 'J', 'a', 'l', 'b', 'e', 'r', 't' };
+
+/* Static variables used to communicate between the conversation function
+ * and the server_login function */
+static struct passwd *dhxpwd;
+
+/*********************************************************
+ * Crypto helper func to generate p and g for use in DH.
+ * libgcrypt doesn't provide one directly.
+ * Algorithm taken from GNUTLS:gnutls_dh_primes.c
+ *********************************************************/
+
+/**
+ * This function will generate a new pair of prime and generator for use in
+ * 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) {
+
+ 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;
+ }
+
+ if (bits < 256)
+ qbits = bits / 2;
+ else
+ qbits = (bits / 40) + 105;
+
+ if (qbits & 1) /* better have an even number */
+ 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++;
+ } while (err != 0 && times < 10);
+
+ if (err != 0) {
+ result = AFPERR_MISC;
+ goto error;
+ }
+
+ /* generate the group generator. */
+ err = gcry_prime_group_generator (&g, prime, 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);
+
+ return 0;
+
+error:
+ gcry_prime_release_factors (factors);
+ gcry_mpi_release (g);
+ gcry_mpi_release (prime);
+
+ return result;
+}
+
+static int dhx2_setup(void *obj, char *ibuf _U_, int ibuflen _U_,
+ char *rbuf, int *rbuflen)
+{
+ int ret;
+ size_t nwritten;
+ gcry_mpi_t g, Ma;
+ char *Ra_binary = NULL;
+#ifdef SHADOWPW
+ struct spwd *sp;
+#endif /* SHADOWPW */
+
+ *rbuflen = 0;
+
+ /* Initialize passwd/shadow */
+#ifdef SHADOWPW
+ if (( sp = getspnam( dhxpwd->pw_name )) == NULL ) {
+ LOG(log_info, logtype_uams, "DHX2: no shadow passwd entry for this user");
+ return AFPERR_NOTAUTH;
+ }
+ dhxpwd->pw_passwd = sp->sp_pwdp;
+#endif /* SHADOWPW */
+
+ if (!dhxpwd->pw_passwd)
+ return AFPERR_NOTAUTH;
+
+ /* Initialize DH params */
+
+ 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;
+ }
+ gcry_randomize(Ra_binary, PRIMEBITS/8, GCRY_STRONG_RANDOM);
+ gcry_mpi_scan(&Ra, GCRYMPI_FMT_USG, Ra_binary, PRIMEBITS/8, NULL);
+ free(Ra_binary);
+ Ra_binary = NULL;
+
+ /* Ma = g^Ra mod p. This is our "public" key */
+ gcry_mpi_powm(Ma, g, Ra, p);
+
+ /* ------- DH Init done ------ */
+ /* Start building reply packet */
+
+ /* Session ID first */
+ ID = dhxhash(obj);
+ *(u_int16_t *)rbuf = htons(ID);
+ 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);
+ }
+ rbuf += 4;
+ *rbuflen += 4;
+
+ /* len = length of p = PRIMEBITS/8 */
+ *(u_int16_t *)rbuf = htons((u_int16_t) PRIMEBITS/8);
+ rbuf += 2;
+ *rbuflen += 2;
+
+ /* p */
+ gcry_mpi_print( GCRYMPI_FMT_USG, (unsigned char *)rbuf, PRIMEBITS/8, NULL, p);
+ rbuf += PRIMEBITS/8;
+ *rbuflen += PRIMEBITS/8;
+
+ /* 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);
+ }
+ 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);
+ 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)
+{
+ if (( dhxpwd = uam_getname(obj, username, ulen)) == NULL ) {
+ LOG(log_info, logtype_uams, "DHX2: unknown username");
+ return AFPERR_PARAM;
+ }
+
+ LOG(log_info, logtype_uams, "DHX2 login: %s", username);
+ return dhx2_setup(obj, ibuf, ibuflen, rbuf, rbuflen);
+}
+
+/* -------------------------------- */
+/* dhx login: things are done in a slightly bizarre order to avoid
+ * having to clean things up if there's an error. */
+static int passwd_login(void *obj, struct passwd **uam_pwd,
+ char *ibuf, int ibuflen,
+ char *rbuf, int *rbuflen)
+{
+ char *username;
+ int len, ulen;
+
+ *rbuflen = 0;
+
+ /* grab some of the options */
+ if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, (void *) &username, &ulen) < 0) {
+ LOG(log_info, logtype_uams, "DHX2: uam_afpserver_option didn't meet uam_option_username -- %s",
+ strerror(errno));
+ return AFPERR_PARAM;
+ }
+
+ len = (unsigned char) *ibuf++;
+ if ( len > ulen ) {
+ LOG(log_info, logtype_uams, "DHX2: Signature Retieval Failure -- %s",
+ strerror(errno));
+ return AFPERR_PARAM;
+ }
+
+ memcpy(username, ibuf, len );
+ ibuf += len;
+ username[ len ] = '\0';
+
+ if ((unsigned long) ibuf & 1) /* pad to even boundary */
+ ++ibuf;
+
+ return (login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
+}
+
+/* ----------------------------- */
+static int passwd_login_ext(void *obj, char *uname, struct passwd **uam_pwd,
+ char *ibuf, int ibuflen,
+ char *rbuf, int *rbuflen)
+{
+ char *username;
+ int len, ulen;
+ u_int16_t temp16;
+
+ *rbuflen = 0;
+
+ /* grab some of the options */
+ if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, (void *) &username, &ulen) < 0) {
+ LOG(log_info, logtype_uams, "DHX2: uam_afpserver_option didn't meet uam_option_username -- %s",
+ strerror(errno));
+ return AFPERR_PARAM;
+ }
+
+ if (*uname != 3)
+ return AFPERR_PARAM;
+ uname++;
+ memcpy(&temp16, uname, sizeof(temp16));
+ len = ntohs(temp16);
+
+ if ( !len || len > ulen ) {
+ LOG(log_info, logtype_uams, "DHX2: Signature Retrieval Failure -- %s",
+ strerror(errno));
+ return AFPERR_PARAM;
+ }
+ memcpy(username, uname +2, len );
+ username[ len ] = '\0';
+
+ return (login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
+}
+
+/* -------------------------------- */
+
+static int logincont1(void *obj _U_, struct passwd **uam_pwd _U_,
+ char *ibuf, int ibuflen,
+ char *rbuf, int *rbuflen)
+{
+ size_t nwritten;
+ int ret;
+ gcry_mpi_t Mb, K, clientNonce;
+ unsigned char *K_bin = NULL;
+ char serverNonce_bin[16];
+ gcry_cipher_hd_t ctx;
+ gcry_error_t ctxerror;
+
+ *rbuflen = 0;
+
+ Mb = gcry_mpi_new(0);
+ K = gcry_mpi_new(0);
+ clientNonce = gcry_mpi_new(0);
+ serverNonce = gcry_mpi_new(0);
+
+ /* 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");
+ ret = AFPERR_PARAM;
+ goto error_noctx;
+ }
+
+ /* Skip session id */
+ ibuf += 2;
+
+ /* Extract Mb, client's "public" key */
+ gcry_mpi_scan(&Mb, GCRYMPI_FMT_USG, ibuf, PRIMEBITS/8, NULL);
+ ibuf += PRIMEBITS/8;
+
+ /* Now finally generate the Key: K = Mb^Ra mod p */
+ gcry_mpi_powm(K, Mb, Ra, p);
+
+ /* 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;
+ }
+ 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);
+ }
+
+ /* ... 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;
+ }
+ gcry_md_hash_buffer(GCRY_MD_MD5, K_MD5hash, K_bin, PRIMEBITS/8);
+ free(K_bin);
+ K_bin = NULL;
+
+ /* FIXME: To support the Reconnect UAM, we need to store this key somewhere */
+
+ /* 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;
+ 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;
+ 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;
+ 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;
+ goto error_ctx;
+ }
+ /* Pull out clients nonce */
+ gcry_mpi_scan(&clientNonce, GCRYMPI_FMT_USG, ibuf, 16, NULL);
+ /* Increment nonce */
+ gcry_mpi_add_ui(clientNonce, clientNonce, 1);
+
+ /* Generate our nonce and remember it for Logincont2 */
+ gcry_create_nonce(serverNonce_bin, 16); /* We'll use this here */
+ gcry_mpi_scan(&serverNonce, GCRYMPI_FMT_USG, serverNonce_bin, 16, NULL); /* For use in Logincont2 */
+
+ /* ---- Start building reply packet ---- */
+
+ /* Session ID + 1 first */
+ *(u_int16_t *)rbuf = htons(ID+1);
+ rbuf += 2;
+ *rbuflen += 2;
+
+ /* Client nonce + 1 */
+ gcry_mpi_print(GCRYMPI_FMT_USG, (unsigned char *)rbuf, PRIMEBITS/8, NULL, clientNonce);
+ /* Server nonce */
+ memcpy(rbuf+16, serverNonce_bin, 16);
+
+ /* 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;
+ 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;
+ }
+ rbuf += 32;
+ *rbuflen += 32;
+
+ ret = AFPERR_AUTHCONT;
+ goto exit;
+
+error_ctx:
+ gcry_cipher_close(ctx);
+error_noctx:
+ gcry_mpi_release(serverNonce);
+ free(K_MD5hash);
+ K_MD5hash=NULL;
+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 _U_, struct passwd **uam_pwd,
+ char *ibuf, int ibuflen,
+ char *rbuf _U_, int *rbuflen)
+{
+#ifdef SHADOWPW
+ struct spwd *sp;
+#endif /* SHADOWPW */
+ int ret;
+ char *p;
+ gcry_mpi_t retServerNonce;
+ gcry_cipher_hd_t ctx;
+ gcry_error_t ctxerror;
+
+ *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");
+ ret = AFPERR_PARAM;
+ goto error_noctx;
+ }
+
+ retServerNonce = gcry_mpi_new(0);
+
+ /* 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;
+ 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;
+ 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;
+ goto error_ctx;
+ }
+
+ /* Skip Session ID */
+ ibuf += 2;
+
+ /* Finally: decrypt client's md5_K(serverNonce+1, passwor, C2SIV) inplace */
+ ctxerror = gcry_cipher_decrypt(ctx, ibuf, 16+256, NULL, 0);
+ if (gcry_err_code(ctxerror) != GPG_ERR_NO_ERROR) {
+ ret = AFPERR_MISC;
+ goto error_ctx;
+ }
+ /* Pull out nonce. Should be serverNonce+1 */
+ 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! */
+ ret = AFPERR_NOTAUTH;
+ goto error_ctx;
+ }
+ ibuf += 16; /* ibuf now point to passwd in cleartext */
+
+ /* ---- Start authentication --- */
+ ret = AFPERR_NOTAUTH;
+
+ p = crypt( ibuf, dhxpwd->pw_passwd );
+ memset(ibuf, 0, 255);
+ if ( strcmp( p, dhxpwd->pw_passwd ) == 0 ) {
+ *uam_pwd = dhxpwd;
+ ret = AFP_OK;
+ }
+
+#ifdef SHADOWPW
+ if (( sp = getspnam( dhxpwd->pw_name )) == NULL ) {
+ LOG(log_info, logtype_uams, "no shadow passwd entry for %s", dhxpwd->pw_name);
+ ret = AFPERR_NOTAUTH;
+ goto exit;
+ }
+
+ /* check for expired password */
+ if (sp && sp->sp_max != -1 && sp->sp_lstchg) {
+ time_t now = time(NULL) / (60*60*24);
+ int32_t expire_days = sp->sp_lstchg - now + sp->sp_max;
+ if ( expire_days < 0 ) {
+ LOG(log_info, logtype_uams, "password for user %s expired", dhxpwd->pw_name);
+ ret = AFPERR_PWDEXPR;
+ goto exit;
+ }
+ }
+#endif /* SHADOWPW */
+
+error_ctx:
+ gcry_cipher_close(ctx);
+error_noctx:
+exit:
+ free(K_MD5hash);
+ K_MD5hash=NULL;
+ gcry_mpi_release(serverNonce);
+ gcry_mpi_release(retServerNonce);
+ return ret;
+}
+
+static int passwd_logincont(void *obj, struct passwd **uam_pwd,
+ char *ibuf, int ibuflen,
+ char *rbuf, int *rbuflen)
+{
+ u_int16_t retID;
+ int ret;
+
+ /* check for session id */
+ retID = ntohs(*(u_int16_t *)ibuf);
+ if (retID == ID)
+ ret = logincont1(obj, uam_pwd, ibuf, ibuflen, rbuf, rbuflen);
+ else if (retID == ID+1)
+ ret = logincont2(obj, uam_pwd, ibuf,ibuflen, rbuf, rbuflen);
+ else {
+ LOG(log_info, logtype_uams, "DHX2: Session ID Mismatch");
+ ret = AFPERR_PARAM;
+ }
+ return ret;
+}
+
+static int uam_setup(const char *path)
+{
+ if (uam_register(UAM_SERVER_LOGIN_EXT, path, "DHX2", passwd_login,
+ passwd_logincont, NULL, passwd_login_ext) < 0)
+ return -1;
+ return 0;
+}
+
+static void uam_cleanup(void)
+{
+ uam_unregister(UAM_SERVER_LOGIN, "DHX2");
+}
+
+
+UAM_MODULE_EXPORT struct uam_export uams_dhx2 = {
+ UAM_MODULE_SERVER,
+ UAM_MODULE_VERSION,
+ uam_setup, uam_cleanup
+};
+
+
+UAM_MODULE_EXPORT struct uam_export uams_dhx2_passwd = {
+ UAM_MODULE_SERVER,
+ UAM_MODULE_VERSION,
+ uam_setup, uam_cleanup
+};
+
+#endif /* UAM_DHX2 */
+
--- /dev/null
+dnl AM_PATH_LIBGCRYPT([MINIMUM-VERSION,
+dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]])
+dnl Test for libgcrypt and define LIBGCRYPT_CFLAGS and LIBGCRYPT_LIBS.
+dnl MINIMUN-VERSION is a string with the version number optionalliy prefixed
+dnl with the API version to also check the API compatibility. Example:
+dnl a MINIMUN-VERSION of 1:1.2.5 won't pass the test unless the installed
+dnl version of libgcrypt is at least 1.2.5 *and* the API number is 1. Using
+dnl this features allows to prevent build against newer versions of libgcrypt
+dnl with a changed API.
+dnl
+AC_DEFUN([AM_PATH_LIBGCRYPT],
+[ AC_ARG_WITH(libgcrypt-dir,
+ AC_HELP_STRING([--with-libgcrypt-dir=PATH],
+ [path where LIBGCRYPT is installed (optional).
+ Must contain lib and include dirs.]),
+ libgcrypt_config_prefix="$withval", libgcrypt_config_prefix="")
+ if test x$libgcrypt_config_prefix != x ; then
+ if test x${LIBGCRYPT_CONFIG+set} != xset ; then
+ LIBGCRYPT_CONFIG=$libgcrypt_config_prefix/bin/libgcrypt-config
+ fi
+ fi
+
+ ok=no
+
+if test x$libgcrypt_config_prefix != xno ; then
+
+ AC_PATH_PROG(LIBGCRYPT_CONFIG, libgcrypt-config, no)
+ tmp=ifelse([$1], ,1:1.2.0,$1)
+ if echo "$tmp" | grep ':' >/dev/null 2>/dev/null ; then
+ req_libgcrypt_api=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\1/'`
+ min_libgcrypt_version=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\2/'`
+ else
+ req_libgcrypt_api=0
+ min_libgcrypt_version="$tmp"
+ fi
+
+ AC_MSG_CHECKING(for LIBGCRYPT - version >= $min_libgcrypt_version)
+ if test "$LIBGCRYPT_CONFIG" != "no" ; then
+ req_major=`echo $min_libgcrypt_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'`
+ req_minor=`echo $min_libgcrypt_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'`
+ req_micro=`echo $min_libgcrypt_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'`
+ libgcrypt_config_version=`$LIBGCRYPT_CONFIG --version`
+ major=`echo $libgcrypt_config_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'`
+ minor=`echo $libgcrypt_config_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'`
+ micro=`echo $libgcrypt_config_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\3/'`
+ if test "$major" -gt "$req_major"; then
+ ok=yes
+ else
+ if test "$major" -eq "$req_major"; then
+ if test "$minor" -gt "$req_minor"; then
+ ok=yes
+ else
+ if test "$minor" -eq "$req_minor"; then
+ if test "$micro" -ge "$req_micro"; then
+ ok=yes
+ fi
+ fi
+ fi
+ fi
+ fi
+ fi
+fi
+ if test $ok = yes; then
+ AC_MSG_RESULT([yes ($libgcrypt_config_version)])
+ else
+ AC_MSG_RESULT(no)
+ fi
+ if test $ok = yes; then
+ # If we have a recent libgcrypt, we should also check that the
+ # API is compatible
+ if test "$req_libgcrypt_api" -gt 0 ; then
+ tmp=`$LIBGCRYPT_CONFIG --api-version 2>/dev/null || echo 0`
+ if test "$tmp" -gt 0 ; then
+ AC_MSG_CHECKING([LIBGCRYPT API version])
+ if test "$req_libgcrypt_api" -eq "$tmp" ; then
+ AC_MSG_RESULT([okay])
+ else
+ ok=no
+ AC_MSG_RESULT([does not match. want=$req_libgcrypt_api got=$tmp])
+ fi
+ fi
+ fi
+ fi
+ if test $ok = yes; then
+ LIBGCRYPT_CFLAGS=`$LIBGCRYPT_CONFIG --cflags`
+ LIBGCRYPT_LIBS=`$LIBGCRYPT_CONFIG --libs`
+ ifelse([$2], , :, [$2])
+ else
+ LIBGCRYPT_CFLAGS=""
+ LIBGCRYPT_LIBS=""
+ ifelse([$3], , :, [$3])
+ fi
+ AC_SUBST(LIBGCRYPT_CFLAGS)
+ AC_SUBST(LIBGCRYPT_LIBS)
+])
\ No newline at end of file
-dnl $Id: ssl-check.m4,v 1.8.6.4 2004-08-11 03:03:50 bfernhomberg Exp $
+dnl $Id: ssl-check.m4,v 1.8.6.4.2.1 2008-12-02 03:11:59 didg Exp $
dnl Autoconf macro to check for SSL or OpenSSL
AC_DEFUN([AC_CRYPT], [
SSL_LIBS=""
saved_LIBS=$LIBS
saved_CFLAGS=$CFLAGS
- compile_ssl=no
+ neta_cv_have_openssl=no
+dnl compile_ssl=no
dnl make sure atalk_libname is defined beforehand
[[ -n "$atalk_libname" ]] || AC_MSG_ERROR([internal error, atalk_libname undefined])
AC_DEFINE(OPENSSL_DHX, 1, [Define if the OpenSSL DHX modules should be built])
AC_DEFINE(UAM_DHX, 1, [Define if the DHX UAM modules should be compiled])
- compile_ssl=yes
+ neta_cv_have_openssl=yes
+ neta_cv_compile_dhx=yes
CFLAGS=$saved_CFLAGS
LIBS=$saved_LIBS
break
fi
done
- if test "x$compile_ssl" = "xno"; then
+ if test "x$neta_cv_have_openssl" = "xno"; then
AC_MSG_RESULT([no])
fi
fi
-dnl $Id: summary.m4,v 1.1.2.5.2.1 2004-12-07 18:47:28 bfernhomberg Exp $
+dnl $Id: summary.m4,v 1.1.2.5.2.2 2008-12-02 03:11:59 didg Exp $
dnl Autoconf macros, display configure summary
AC_DEFUN([AC_NETATALK_CONFIG_SUMMARY], [
if test "x$netatalk_cv_use_shadowpw" = "xyes"; then
uams_using_options="$uams_using_options SHADOW"
fi
- if test "x$compile_ssl" = "xyes"; then
+ if test "x$neta_cv_compile_dhx" = "xyes"; then
AC_MSG_RESULT([ DHX ($uams_using_options)])
+ fi
+ if test "x$neta_cv_compile_dhx2" = "xyes"; then
+ AC_MSG_RESULT([ DHX2 ($uams_using_options)])
+ fi
+ if test "x$neta_cv_have_openssl" = "xyes"; then
AC_MSG_RESULT([ RANDNUM ($uams_using_options)])
fi
if test x"$netatalk_cv_build_krb5_uam" = x"yes"; then
AC_MSG_RESULT([Using libraries:])
AC_MSG_RESULT([ LIBS = $LIBS])
AC_MSG_RESULT([ CFLAGS = $CFLAGS])
- if test x"$compile_ssl" = x"yes"; then
+ if test x"$neta_cv_have_openssl" = x"yes"; then
AC_MSG_RESULT([ SSL:])
AC_MSG_RESULT([ LIBS = $SSL_LIBS])
AC_MSG_RESULT([ CFLAGS = $SSL_CFLAGS])
fi
+ if test x"$neta_cv_have_libgcrypt" = x"yes"; then
+ AC_MSG_RESULT([ LIBGCRYPT:])
+ AC_MSG_RESULT([ LIBS = $LIBGCRYPT_LIBS])
+ AC_MSG_RESULT([ CFLAGS = $LIBGCRYPT_CFLAGS])
+ fi
if test x"$netatalk_cv_use_pam" = x"yes"; then
AC_MSG_RESULT([ PAM:])
AC_MSG_RESULT([ LIBS = $PAM_LIBS])