--- /dev/null
+/*
+ * This program is is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ * @file auth_wbclient.c
+ * @brief NTLM authentication against the wbclient library
+ *
+ * @copyright 2015 Matthew Newton
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <wbclient.h>
+
+#include "rlm_mschap.h"
+#include "mschap.h"
+#include "auth_wbclient.h"
+
+#define NT_LENGTH 24
+
+/*
+ * Check NTLM authentication direct to winbind via
+ * Samba's libwbclient library
+ *
+ * Returns -1 for failure and 0 on auth success
+ */
+int do_auth_wbclient(rlm_mschap_t *inst, REQUEST *request,
+ uint8_t const *challenge, uint8_t const *response,
+ uint8_t nthashhash[NT_DIGEST_LENGTH])
+{
+ int rcode = -1;
+ struct wbcAuthUserParams authparams;
+ wbcErr err;
+ int len;
+ struct wbcAuthUserInfo *info = NULL;
+ struct wbcAuthErrorInfo *error = NULL;
+ char user_name_buf[500];
+ char domain_name_buf[500];
+ uint8_t resp[NT_LENGTH];
+
+ /*
+ * Clear the auth parameters - this is important, as
+ * there are options that will cause wbcAuthenticateUserEx
+ * to bomb out if not zero.
+ */
+ memset(&authparams, 0, sizeof(authparams));
+
+ /*
+ * wb_username must be set for this function to be called
+ */
+ rad_assert(inst->wb_username);
+
+ /*
+ * Get the username and domain from the configuration
+ */
+ len = tmpl_expand(&authparams.account_name, user_name_buf, sizeof(user_name_buf),
+ request, inst->wb_username, NULL, NULL);
+ if (len < 0) {
+ REDEBUG2("Unable to expand winbind_username");
+ goto done;
+ }
+
+ if (inst->wb_domain) {
+ len = tmpl_expand(&authparams.domain_name, domain_name_buf, sizeof(domain_name_buf),
+ request, inst->wb_domain, NULL, NULL);
+ if (len < 0) {
+ REDEBUG2("Unable to expand winbind_domain");
+ goto done;
+ }
+ } else {
+ RWDEBUG2("No domain specified; authentication may fail because of this");
+ }
+
+
+ /*
+ * Build the wbcAuthUserParams structure with what we know
+ */
+ authparams.level = WBC_AUTH_USER_LEVEL_RESPONSE;
+ authparams.password.response.nt_length = NT_LENGTH;
+
+ memcpy(resp, response, NT_LENGTH);
+ authparams.password.response.nt_data = resp;
+
+ memcpy(authparams.password.response.challenge, challenge,
+ sizeof(authparams.password.response.challenge));
+
+
+ /*
+ * Send auth request across to winbind
+ */
+ RDEBUG2("sending authentication request user='%s' domain='%s'", authparams.account_name,
+ authparams.domain_name);
+
+ err = wbcCtxAuthenticateUserEx(inst->wb_ctx, &authparams, &info, &error);
+
+
+ /*
+ * Try and give some useful feedback on what happened
+ */
+ switch (err) {
+ case WBC_ERR_SUCCESS:
+ rcode = 0;
+ RDEBUG2("Authenticated successfully");
+ /* Grab the nthashhash from the result */
+ memcpy(nthashhash, info->user_session_key, NT_DIGEST_LENGTH);
+ break;
+ case WBC_ERR_WINBIND_NOT_AVAILABLE:
+ RERROR("Unable to contact winbind!");
+ RERROR("Check that winbind is running and that FreeRADIUS");
+ RERROR("has permission to connect to the winbind socket.");
+ break;
+ case WBC_ERR_DOMAIN_NOT_FOUND:
+ REDEBUG2("Authentication failed: domain not found");
+ break;
+ case WBC_ERR_AUTH_ERROR:
+ REDEBUG2("Authentication failed (check domain is correct)");
+ break;
+ default:
+ REDEBUG2("Authentication failed: wbcErr %d", err);
+ if (error && error->display_string) {
+ REDEBUG2("wbcErr %s", error->display_string);
+ }
+ break;
+ }
+
+
+done:
+ if (info) wbcFreeMemory(info);
+ if (error) wbcFreeMemory(error);
+
+ return rcode;
+}
+
#include "rlm_mschap.h"
#include "mschap.h"
#include "smbdes.h"
+#include "auth_wbclient.h"
#ifdef HAVE_OPENSSL_CRYPTO_H
USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
{ "passchange", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) passchange_config },
{ "allow_retry", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_mschap_t, allow_retry), "yes" },
{ "retry_msg", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_mschap_t, retry_msg), NULL },
+ { "winbind_username", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_TMPL, rlm_mschap_t, wb_username), NULL },
+ { "winbind_domain", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_TMPL, rlm_mschap_t, wb_domain), NULL },
#ifdef WITH_OPEN_DIRECTORY
{ "use_open_directory", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_mschap_t, open_directory), "yes" },
#endif
/*
* Set auth method
*/
+ inst->method = AUTH_INTERNAL;
+
+ if (inst->wb_username) {
+#ifdef WITH_AUTH_WINBIND
+ inst->method = AUTH_WBCLIENT;
+
+ inst->wb_ctx = wbcCtxCreate();
+ if (!inst->wb_ctx) {
+ ERROR("rlm_mschap (%s): failed to create winbind context", name);
+ return -1;
+ }
+#else
+ ERROR("rlm_mschap (%s): 'winbind' auth not enabled at compiled time", name);
+ return -1;
+#endif
+ }
+
+ /* preserve existing behaviour: this option overrides all */
if (inst->ntlm_auth) {
- DEBUG("rlm_mschap (%s): authenticating by calling 'ntlm_auth'", name);
inst->method = AUTH_NTLMAUTH_EXEC;
- } else {
+ }
+
+ switch (inst->method) {
+ case AUTH_INTERNAL:
DEBUG("rlm_mschap (%s): using internal authentication", name);
- inst->method = AUTH_INTERNAL;
+ break;
+ case AUTH_NTLMAUTH_EXEC:
+ DEBUG("rlm_mschap (%s): authenticating by calling 'ntlm_auth'", name);
+ break;
+#ifdef WITH_AUTH_WINBIND
+ case AUTH_WBCLIENT:
+ DEBUG("rlm_mschap (%s): authenticating directly to winbind", name);
+ break;
+#endif
}
/*
}
/*
+ * Tidy up instance
+ */
+static int mod_detach(UNUSED void *instance)
+{
+#ifdef WITH_AUTH_WINBIND
+ rlm_mschap_t *inst = instance;
+
+ wbcCtxFree(inst->wb_ctx);
+#endif
+
+ return 0;
+}
+
+
+/*
* add_reply() adds either MS-CHAP2-Success or MS-CHAP-Error
* attribute to reply packet
*/
break;
}
+#ifdef WITH_AUTH_WINBIND
+ case AUTH_WBCLIENT:
+ /*
+ * Process auth via the wbclient library
+ */
+ return do_auth_wbclient(inst, request, challenge, response, nthashhash);
+#endif
default:
/* We should never reach this line */
RERROR("Internal error: Unknown mschap auth method (%d)", method);
sizeof(rlm_mschap_t),
module_config,
mod_instantiate, /* instantiation */
- NULL, /* detach */
+ mod_detach, /* detach */
{
mod_authenticate, /* authenticate */
mod_authorize, /* authorize */