From: Matthew Newton Date: Mon, 16 Mar 2015 23:33:01 +0000 (+0000) Subject: Add mschap module winbind authentication X-Git-Tag: release_3.0.8~210 X-Git-Url: http://www.project-moonshot.org/gitweb/?a=commitdiff_plain;h=9ab36a19439d63e1c6373c353a27e7f554e9f2f6;p=freeradius.git Add mschap module winbind authentication This allows AD/Samba authentication against winbind via libwbclient without having to use ntlm_auth. --- diff --git a/debian/control b/debian/control index 129a508..ef8729e 100644 --- a/debian/control +++ b/debian/control @@ -21,6 +21,7 @@ Build-Depends: debhelper (>= 7.4), libsqlite3-dev, libssl-dev, libtalloc-dev, + libwbclient-dev, libyubikey-dev, python-dev Section: net diff --git a/raddb/mods-available/mschap b/raddb/mods-available/mschap index 2170df1..15ee91b 100644 --- a/raddb/mods-available/mschap +++ b/raddb/mods-available/mschap @@ -66,6 +66,19 @@ mschap { # # ntlm_auth_timeout = 10 + # An alternative to using ntlm_auth is to connect to the + # winbind daemon directly for authentication. This option + # is likely to be faster and may be useful on busy systems, + # but is less well tested. + # + # Using this option requires libwbclient from Samba 4.2.1 + # or later to be installed. Make sure that ntlm_auth above is + # commented out. + # +# winbind_username = "%{mschap:User-Name}" +# winbind_domain = "%{mschap:NT-Domain}" + + passchange { # This support MS-CHAPv2 (not v1) password change # requests. See doc/mschap.rst for more IMPORTANT diff --git a/src/modules/rlm_mschap/auth_wbclient.c b/src/modules/rlm_mschap/auth_wbclient.c new file mode 100644 index 0000000..71b7ed6 --- /dev/null +++ b/src/modules/rlm_mschap/auth_wbclient.c @@ -0,0 +1,150 @@ +/* + * 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 +#include + +#include + +#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; +} + diff --git a/src/modules/rlm_mschap/auth_wbclient.h b/src/modules/rlm_mschap/auth_wbclient.h new file mode 100644 index 0000000..9ad5a2f --- /dev/null +++ b/src/modules/rlm_mschap/auth_wbclient.h @@ -0,0 +1,12 @@ +/* Copyright 2015 The FreeRADIUS server project */ + +#ifndef _AUTH_WBCLIENT_H +#define _AUTH_WBCLIENT_H + +RCSIDH(auth_wbclient_h, "$Id$") + +int do_auth_wbclient(rlm_mschap_t *inst, REQUEST *request, + uint8_t const *challenge, uint8_t const *response, + uint8_t nthashhash[NT_DIGEST_LENGTH]); + +#endif /*_AUTH_WBCLIENT_H*/ diff --git a/src/modules/rlm_mschap/rlm_mschap.c b/src/modules/rlm_mschap/rlm_mschap.c index cb57604..b08b822 100644 --- a/src/modules/rlm_mschap/rlm_mschap.c +++ b/src/modules/rlm_mschap/rlm_mschap.c @@ -36,6 +36,7 @@ RCSID("$Id$") #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 */ @@ -520,6 +521,8 @@ static const CONF_PARSER module_config[] = { { "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 @@ -557,12 +560,40 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance) /* * 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 } /* @@ -586,6 +617,21 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance) } /* + * 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 */ @@ -1118,6 +1164,13 @@ static int CC_HINT(nonnull (1, 2, 4, 5 ,6)) do_mschap(rlm_mschap_t *inst, REQUES 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); @@ -1904,7 +1957,7 @@ module_t rlm_mschap = { sizeof(rlm_mschap_t), module_config, mod_instantiate, /* instantiation */ - NULL, /* detach */ + mod_detach, /* detach */ { mod_authenticate, /* authenticate */ mod_authorize, /* authorize */ diff --git a/src/modules/rlm_mschap/rlm_mschap.h b/src/modules/rlm_mschap/rlm_mschap.h index 87eb6dd..14463e6 100644 --- a/src/modules/rlm_mschap/rlm_mschap.h +++ b/src/modules/rlm_mschap/rlm_mschap.h @@ -5,10 +5,20 @@ RCSIDH(rlm_mschap_h, "$Id$") +#include "config.h" + +#ifdef HAVE_WBCLIENT_H +#define WITH_AUTH_WINBIND +#include +#endif + /* Method of authentication we are going to use */ typedef enum { AUTH_INTERNAL = 0, AUTH_NTLMAUTH_EXEC = 1 +#ifdef WITH_AUTH_WINBIND + ,AUTH_WBCLIENT = 2 +#endif } MSCHAP_AUTH_METHOD; typedef struct rlm_mschap_t { @@ -27,6 +37,11 @@ typedef struct rlm_mschap_t { bool allow_retry; char const *retry_msg; MSCHAP_AUTH_METHOD method; + vp_tmpl_t *wb_username; + vp_tmpl_t *wb_domain; +#ifdef WITH_AUTH_WINBIND + struct wbcContext *wb_ctx; +#endif #ifdef WITH_OPEN_DIRECTORY bool open_directory; #endif