X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=etc%2Fuams%2Fuams_dhx_pam.c;h=b3bd931052c54b424cd328579be35f67531b7813;hb=b35812db1e932c31154b7da72c564dabe95fd03d;hp=cdc5a86f13578638c93d126fae7df2388eae7183;hpb=7a835e5385d2cb11bf068d29ed055d59946389ec;p=netatalk.git diff --git a/etc/uams/uams_dhx_pam.c b/etc/uams/uams_dhx_pam.c index cdc5a86f..b3bd9310 100644 --- a/etc/uams/uams_dhx_pam.c +++ b/etc/uams/uams_dhx_pam.c @@ -1,4 +1,6 @@ /* + * $Id: uams_dhx_pam.c,v 1.33 2010-03-30 10:25:49 franklahm 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. @@ -6,25 +8,39 @@ #ifdef HAVE_CONFIG_H #include "config.h" -#endif +#endif /* HAVE_CONFIG_H */ #if defined(USE_PAM) && defined(UAM_DHX) #include #include #include -#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif /* HAVE_UNISTD_H */ +#include +#ifdef HAVE_SECURITY_PAM_APPL_H #include +#endif +#ifdef HAVE_PAM_PAM_APPL_H +#include +#endif -#ifdef OPENSSL_DHX + +#if defined(GNUTLS_DHX) +#include +#elif defined(OPENSSL_DHX) #include #include #include -#else +#include +#else /* OPENSSL_DHX */ #include #include #include -#endif +#include +#endif /* OPENSSL_DHX */ #include #include @@ -66,55 +82,66 @@ static char *PAM_password; static int PAM_conv (int num_msg, const struct pam_message **msg, struct pam_response **resp, - void *appdata_ptr) { + void *appdata_ptr _U_) { int count = 0; struct pam_response *reply; #define COPY_STRING(s) (s) ? strdup(s) : NULL - if (num_msg < 1) + errno = 0; + + if (num_msg < 1) { /* Log Entry */ - syslog(LOG_INFO, "uams_dhx_pam.c :PAM DHX Conversation Err -- %m"); + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM DHX Conversation Err -- %s", + strerror(errno)); /* Log Entry */ return PAM_CONV_ERR; + } reply = (struct pam_response *) calloc(num_msg, sizeof(struct pam_response)); - if (!reply) + if (!reply) { /* Log Entry */ - syslog(LOG_INFO, "uams_dhx_pam.c :PAM DHX Conversation Err -- %m"); + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM DHX 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))) + if (!(string = COPY_STRING(PAM_username))) { /* Log Entry */ - syslog(LOG_INFO, "uams_dhx_pam.c :PAM: username failure -- %m"); + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: username failure -- %s", + strerror(errno)); /* Log Entry */ goto pam_fail_conv; + } break; case PAM_PROMPT_ECHO_OFF: - if (!(string = COPY_STRING(PAM_password))) + if (!(string = COPY_STRING(PAM_password))) { /* Log Entry */ - syslog(LOG_INFO, "uams_dhx_pam.c :PAM: passwd failure: --: %m"); + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: 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 +#endif /* PAM_BINARY_PROMPT */ /* ignore it... */ break; case PAM_ERROR_MSG: default: /* Log Entry */ - syslog(LOG_INFO, "uams_dhx_pam.c :PAM: Binary_Prompt -- %m"); + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: Binary_Prompt -- %s", + strerror(errno)); /* Log Entry */ goto pam_fail_conv; } @@ -128,7 +155,7 @@ static int PAM_conv (int num_msg, *resp = reply; /* Log Entry */ - syslog(LOG_INFO, "uams_dhx_pam.c :PAM: PAM Success -- %m"); + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: PAM Success"); /* Log Entry */ return PAM_SUCCESS; @@ -145,7 +172,8 @@ pam_fail_conv: } free(reply); /* Log Entry */ - syslog(LOG_INFO, "uams_dhx_pam.c :PAM DHX Conversation Err -- %m"); + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM DHX Conversation Err -- %s", + strerror(errno)); /* Log Entry */ return PAM_CONV_ERR; } @@ -156,27 +184,40 @@ static struct pam_conv PAM_conversation = { }; -static int dhx_setup(void *obj, char *ibuf, int ibuflen, - char *rbuf, int *rbuflen) +static int dhx_setup(void *obj, char *ibuf, size_t ibuflen _U_, + char *rbuf, size_t *rbuflen) { u_int16_t sessid; - int i; + size_t i; BIGNUM *bn, *gbn, *pbn; DH *dh; /* get the client's public key */ - if (!(bn = BN_bin2bn(ibuf, KEYSIZE, NULL))) + if (!(bn = BN_bin2bn(ibuf, KEYSIZE, NULL))) { + /* Log Entry */ + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM No Public Key -- %s", + strerror(errno)); + /* Log Entry */ return AFPERR_PARAM; + } /* get our primes */ if (!(gbn = BN_bin2bn(&g, sizeof(g), NULL))) { BN_clear_free(bn); + /* Log Entry */ + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM No Primes: GBN -- %s", + strerror(errno)); + /* Log Entry */ return AFPERR_PARAM; } if (!(pbn = BN_bin2bn(p, sizeof(p), NULL))) { BN_free(gbn); BN_clear_free(bn); + /* Log Entry */ + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM No Primes: PBN -- %s", + strerror(errno)); + /* Log Entry */ return AFPERR_PARAM; } @@ -185,17 +226,32 @@ static int dhx_setup(void *obj, char *ibuf, int ibuflen, BN_free(pbn); BN_free(gbn); BN_clear_free(bn); + /* Log Entry */ + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM DH was equal to DH_New... Go figure... -- %s", + strerror(errno)); + /* Log Entry */ return AFPERR_PARAM; } /* generate key and make sure that we have enough space */ dh->p = pbn; dh->g = gbn; - if (!DH_generate_key(dh) || (BN_num_bytes(dh->pub_key) > KEYSIZE)) { - /* Log Entry */ - syslog(LOG_INFO, "uams_dhx_pam.c :PAM: Err Generating Key -- Not enough Space? -- %m"); - /* Log Entry */ - goto pam_fail; + if (DH_generate_key(dh) == 0) { + unsigned long dherror; + char errbuf[256]; + + ERR_load_crypto_strings(); + dherror = ERR_get_error(); + ERR_error_string_n(dherror, errbuf, 256); + + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: Err Generating Key (OpenSSL error code: %u, %s)", dherror, errbuf); + + ERR_free_strings(); + goto pam_fail; + } + if (BN_num_bytes(dh->pub_key) > KEYSIZE) { + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: Err Generating Key -- Not enough Space? -- %s", strerror(errno)); + goto pam_fail; } /* figure out the key. store the key in rbuf for now. */ @@ -221,7 +277,8 @@ static int dhx_setup(void *obj, char *ibuf, int ibuflen, &i) < 0) { *rbuflen = 0; /* Log Entry */ - syslog(LOG_INFO, "uams_dhx_pam.c :PAM: Buffer Encryption Err. -- %m"); + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: Buffer Encryption Err. -- %s", + strerror(errno)); /* Log Entry */ goto pam_fail; } @@ -233,14 +290,15 @@ static int dhx_setup(void *obj, char *ibuf, int ibuflen, (void *) &buf, NULL) < 0) { *rbuflen = 0; /* Log Entry */ - syslog(LOG_INFO, "uams_dhx_pam.c :PAM: Signature Retieval Failure -- %m"); + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: Signature Retieval Failure -- %s", + strerror(errno)); /* Log Entry */ goto pam_fail; } memcpy(rbuf + KEYSIZE, buf, KEYSIZE); -#else +#else /* 0 */ memset(rbuf + KEYSIZE, 0, KEYSIZE); -#endif +#endif /* 0 */ /* encrypt using cast */ CAST_cbc_encrypt(rbuf, rbuf, CRYPTBUFLEN, &castkey, msg2_iv, @@ -253,52 +311,106 @@ static int dhx_setup(void *obj, char *ibuf, int ibuflen, pam_fail: BN_free(bn); DH_free(dh); + /* Log Entry */ + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: Fail - Cast Encryption -- %s", + strerror(errno)); + /* Log Entry */ return AFPERR_PARAM; } +/* -------------------------------- */ +static int login(void *obj, char *username, int ulen, struct passwd **uam_pwd _U_, + char *ibuf, size_t ibuflen, + char *rbuf, size_t *rbuflen) +{ + if (( dhxpwd = uam_getname(obj, username, ulen)) == NULL ) { + LOG(log_info, logtype_uams, "uams_dhx_pam.c: unknown username [%s]", username); + return AFPERR_NOTAUTH; + } + PAM_username = username; + LOG(log_info, logtype_uams, "dhx login: %s", username); + return dhx_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 *ibuf, size_t ibuflen, + char *rbuf, size_t *rbuflen) { - char *buf; - int len, i; + char *username; + size_t len, ulen; *rbuflen = 0; /* grab some of the options */ - if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, (void *) &buf, - &i) < 0) - return AFPERR_PARAM; + if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, (void *) &username, &ulen) < 0) { + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: uam_afpserver_option didn't meet uam_option_username -- %s", + strerror(errno)); + return AFPERR_PARAM; + } len = (unsigned char) *ibuf++; - if ( len > i ) { - return( AFPERR_PARAM ); + if ( len > ulen ) { + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: Signature Retieval Failure -- %s", + strerror(errno)); + return AFPERR_PARAM; } - memcpy(buf, ibuf, len ); + memcpy(username, ibuf, len ); ibuf += len; - buf[ len ] = '\0'; + username[ len ] = '\0'; + if ((unsigned long) ibuf & 1) /* pad to even boundary */ ++ibuf; - if (( dhxpwd = uam_getname(buf, i)) == NULL ) { + 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, size_t ibuflen, + char *rbuf, size_t *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, "uams_dhx_pam.c :PAM: 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, "uams_dhx_pam.c :PAM: Signature Retrieval Failure -- %s", + strerror(errno)); return AFPERR_PARAM; } + memcpy(username, uname +2, len ); + username[ len ] = '\0'; - PAM_username = buf; - syslog( LOG_INFO, "dhx login: %s", buf); - return dhx_setup(obj, ibuf, ibuflen, rbuf, rbuflen); + return (login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen)); } +/* -------------------------------- */ static int pam_logincont(void *obj, struct passwd **uam_pwd, - char *ibuf, int ibuflen, - char *rbuf, int *rbuflen) + char *ibuf, size_t ibuflen _U_, + char *rbuf, size_t *rbuflen) { - char *hostname; + const char *hostname; BIGNUM *bn1, *bn2, *bn3; u_int16_t sessid; int err, PAM_error; @@ -307,13 +419,21 @@ static int pam_logincont(void *obj, struct passwd **uam_pwd, /* check for session id */ memcpy(&sessid, ibuf, sizeof(sessid)); - if (sessid != dhxhash(obj)) + if (sessid != dhxhash(obj)) { + /* Log Entry */ + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM Session ID - DHXHash Mismatch -- %s", + strerror(errno)); + /* Log Entry */ return AFPERR_PARAM; + } ibuf += sizeof(sessid); - if (uam_afpserver_option(obj, UAM_OPTION_HOSTNAME, + if (uam_afpserver_option(obj, UAM_OPTION_CLIENTNAME, (void *) &hostname, NULL) < 0) - return AFPERR_MISC; + { + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: unable to retrieve client hostname"); + hostname = NULL; + } CAST_cbc_encrypt(ibuf, rbuf, CRYPT2BUFLEN, &castkey, msg3_iv, CAST_DECRYPT); @@ -358,11 +478,13 @@ static int pam_logincont(void *obj, struct passwd **uam_pwd, err = AFPERR_NOTAUTH; PAM_error = pam_start("netatalk", PAM_username, &PAM_conversation, &pamh); - if (PAM_error != PAM_SUCCESS) + if (PAM_error != PAM_SUCCESS) { /* Log Entry */ - syslog(LOG_INFO, "uams_dhx_pam.c :PAM: PAM_Error: %s -- %m", PAM_error); + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: PAM_Error: %s", + pam_strerror(pamh,PAM_error)); /* Log Entry */ goto logincont_err; + } /* solaris craps out if PAM_TTY and PAM_RHOST aren't set. */ pam_set_item(pamh, PAM_TTY, "afpd"); @@ -372,47 +494,56 @@ static int pam_logincont(void *obj, struct passwd **uam_pwd, if (PAM_error == PAM_MAXTRIES) err = AFPERR_PWDEXPR; /* Log Entry */ - syslog(LOG_INFO, "uams_dhx_pam.c :PAM: PAM_Error: %s -- %m", PAM_error); + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: PAM_Error: %s", + pam_strerror(pamh, PAM_error)); /* Log Entry */ goto logincont_err; } PAM_error = pam_acct_mgmt(pamh, 0); - if (PAM_error != PAM_SUCCESS) { - if (PAM_error == PAM_ACCT_EXPIRED) + if (PAM_error != PAM_SUCCESS ) { + /* Log Entry */ + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: PAM_Error: %s", + pam_strerror(pamh, PAM_error)); + /* Log Entry */ + if (PAM_error == PAM_NEW_AUTHTOK_REQD) /* password expired */ err = AFPERR_PWDEXPR; #ifdef PAM_AUTHTOKEN_REQD else if (PAM_error == PAM_AUTHTOKEN_REQD) err = AFPERR_PWDCHNG; #endif - /* Log Entry */ - syslog(LOG_INFO, "uams_dhx_pam.c :PAM: PAM_Error: %s -- %m", PAM_error); - /* Log Entry */ - goto logincont_err; + else + goto logincont_err; } #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) + if (PAM_error != PAM_SUCCESS) { /* Log Entry */ - syslog(LOG_INFO, "uams_dhx_pam.c :PAM: PAM_Error: %s -- %m", PAM_error); + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: PAM_Error: %s", + pam_strerror(pamh, PAM_error)); /* Log Entry */ goto logincont_err; + } PAM_error = pam_open_session(pamh, 0); - if (PAM_error != PAM_SUCCESS) + if (PAM_error != PAM_SUCCESS) { /* Log Entry */ - syslog(LOG_INFO, "uams_dhx_pam.c :PAM: PAM_Error: %s -- %m", PAM_error); + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: PAM_Error: %s", + pam_strerror(pamh, PAM_error)); /* Log Entry */ goto logincont_err; + } memset(rbuf, 0, PASSWDLEN); /* zero out the password */ *uam_pwd = dhxpwd; /* Log Entry */ - syslog(LOG_INFO, "uams_dhx_pam.c :PAM: PAM Auth OK!: %s -- %m", AFP_OK); + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: PAM Auth OK!"); /* Log Entry */ + if ( err == AFPERR_PWDEXPR) + return err; return AFP_OK; logincont_err: @@ -423,7 +554,7 @@ logincont_err: } /* logout */ -static void pam_logout() { +static void pam_logout(void) { pam_close_session(pamh, 0); pam_end(pamh, 0); pamh = NULL; @@ -433,8 +564,8 @@ static void pam_logout() { /* change pw for dhx needs a couple passes to get everything all * right. basically, it's like the login/logincont sequence */ static int pam_changepw(void *obj, char *username, - struct passwd *pwd, char *ibuf, int ibuflen, - char *rbuf, int *rbuflen) + struct passwd *pwd _U_, char *ibuf, size_t ibuflen, + char *rbuf, size_t *rbuflen) { BIGNUM *bn1, *bn2, *bn3; @@ -444,6 +575,10 @@ static int pam_changepw(void *obj, char *username, u_int16_t sessid; int PAM_error; + if (ibuflen < sizeof(sessid)) { + return AFPERR_PARAM; + } + /* grab the id */ memcpy(&sessid, ibuf, sizeof(sessid)); ibuf += sizeof(sessid); @@ -458,19 +593,23 @@ static int pam_changepw(void *obj, char *username, /* otherwise, it's like logincont but different. */ /* check out the session id */ - if (sessid != dhxhash(obj)) + if (sessid != dhxhash(obj)) { /* Log Entry */ - syslog(LOG_INFO, "uams_dhx_pam.c :PAM: Session ID not Equal to DHX Hash -- %m",); + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: Session ID not Equal to DHX Hash -- %s", + strerror(errno)); /* Log Entry */ return AFPERR_PARAM; + } /* we need this for pam */ if (uam_afpserver_option(obj, UAM_OPTION_HOSTNAME, - (void *) &hostname, NULL) < 0) + (void *) &hostname, NULL) < 0) { /* Log Entry */ - syslog(LOG_INFO, "uams_dhx_pam.c :PAM: Hostname Null?? -- %m",); + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: Hostname Null?? -- %s", + strerror(errno)); /* Log Entry */ return AFPERR_MISC; + } /* grab the client's nonce, old password, and new password. */ CAST_cbc_encrypt(ibuf, ibuf, CHANGEPWBUFLEN, &castkey, @@ -479,16 +618,19 @@ static int pam_changepw(void *obj, char *username, /* check to make sure that the random number is the same. we * get sent back an incremented random number. */ - if (!(bn1 = BN_bin2bn(ibuf, KEYSIZE, NULL))) + if (!(bn1 = BN_bin2bn(ibuf, KEYSIZE, NULL))) { /* Log Entry */ - syslog(LOG_INFO, "uams_dhx_pam.c :PAM: Random Number Not the same or not incremented-- %m",); + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: Random Number Not the same or not incremented-- %s", + strerror(errno)); /* Log Entry */ return AFPERR_PARAM; + } if (!(bn2 = BN_bin2bn(randbuf, sizeof(randbuf), NULL))) { BN_free(bn1); /* Log Entry */ - syslog(LOG_INFO, "uams_dhx_pam.c :PAM: Random Number Not the same or not incremented -- %m",); + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: Random Number Not the same or not incremented -- %s", + strerror(errno)); /* Log Entry */ return AFPERR_PARAM; } @@ -501,7 +643,8 @@ static int pam_changepw(void *obj, char *username, BN_free(bn2); BN_free(bn1); /* Log Entry */ - syslog(LOG_INFO, "uams_dhx_pam.c :PAM: Random Number did not Zero -- %m",); + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: Random Number did not Zero -- %s", + strerror(errno)); /* Log Entry */ return AFPERR_PARAM; } @@ -515,7 +658,8 @@ static int pam_changepw(void *obj, char *username, if (!BN_is_one(bn3)) { BN_free(bn3); /* Log Entry */ - syslog(LOG_INFO, "uams_dhx_pam.c :PAM: After Random Number not Zero, is it one more? -- %m",); + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: After Random Number not Zero, is it one more? -- %s", + strerror(errno)); /* Log Entry */ return AFPERR_PARAM; } @@ -530,11 +674,13 @@ static int pam_changepw(void *obj, char *username, PAM_error = pam_start("netatalk", username, &PAM_conversation, &lpamh); - if (PAM_error != PAM_SUCCESS) + if (PAM_error != PAM_SUCCESS) { /* Log Entry */ - syslog(LOG_INFO, "uams_dhx_pam.c :PAM: Needless to say, PAM_error is != to PAM_SUCCESS -- %m",); + LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: Needless to say, PAM_error is != to PAM_SUCCESS -- %s", + strerror(errno)); /* Log Entry */ return AFPERR_PARAM; + } pam_set_item(lpamh, PAM_TTY, "afpd"); pam_set_item(lpamh, PAM_RHOST, hostname); @@ -571,8 +717,8 @@ static int pam_changepw(void *obj, char *username, static int uam_setup(const char *path) { - if (uam_register(UAM_SERVER_LOGIN, path, "DHCAST128", pam_login, - pam_logincont, pam_logout) < 0) + if (uam_register(UAM_SERVER_LOGIN_EXT, path, "DHCAST128", pam_login, + pam_logincont, pam_logout, pam_login_ext) < 0) return -1; if (uam_register(UAM_SERVER_CHANGEPW, path, "DHCAST128", @@ -600,5 +746,11 @@ UAM_MODULE_EXPORT struct uam_export uams_dhx = { uam_setup, uam_cleanup }; +UAM_MODULE_EXPORT struct uam_export uams_dhx_pam = { + UAM_MODULE_SERVER, + UAM_MODULE_VERSION, + uam_setup, uam_cleanup +}; + #endif /* USE_PAM && UAM_DHX */ - \ No newline at end of file +