2 * This program is is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or (at
5 * your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 * @file auth_wbclient.c
20 * @brief NTLM authentication against the wbclient library
22 * @copyright 2015 Matthew Newton
27 #include <freeradius-devel/radiusd.h>
28 #include <freeradius-devel/rad_assert.h>
30 #include <core/ntstatus.h>
32 #include "rlm_mschap.h"
34 #include "auth_wbclient.h"
39 * Check NTLM authentication direct to winbind via
40 * Samba's libwbclient library
45 * -648 password expired
47 int do_auth_wbclient(rlm_mschap_t *inst, REQUEST *request,
48 uint8_t const *challenge, uint8_t const *response,
49 uint8_t nthashhash[NT_DIGEST_LENGTH])
52 struct wbcContext *wb_ctx;
53 struct wbcAuthUserParams authparams;
56 struct wbcAuthUserInfo *info = NULL;
57 struct wbcAuthErrorInfo *error = NULL;
58 char user_name_buf[500];
59 char domain_name_buf[500];
60 uint8_t resp[NT_LENGTH];
63 * Clear the auth parameters - this is important, as
64 * there are options that will cause wbcAuthenticateUserEx
65 * to bomb out if not zero.
67 memset(&authparams, 0, sizeof(authparams));
70 * wb_username must be set for this function to be called
72 rad_assert(inst->wb_username);
75 * Get the username and domain from the configuration
77 len = tmpl_expand(&authparams.account_name, user_name_buf, sizeof(user_name_buf),
78 request, inst->wb_username, NULL, NULL);
80 REDEBUG2("Unable to expand winbind_username");
84 if (inst->wb_domain) {
85 len = tmpl_expand(&authparams.domain_name, domain_name_buf, sizeof(domain_name_buf),
86 request, inst->wb_domain, NULL, NULL);
88 REDEBUG2("Unable to expand winbind_domain");
92 RWDEBUG2("No domain specified; authentication may fail because of this");
97 * Build the wbcAuthUserParams structure with what we know
99 authparams.level = WBC_AUTH_USER_LEVEL_RESPONSE;
100 authparams.password.response.nt_length = NT_LENGTH;
102 memcpy(resp, response, NT_LENGTH);
103 authparams.password.response.nt_data = resp;
105 memcpy(authparams.password.response.challenge, challenge,
106 sizeof(authparams.password.response.challenge));
108 if (inst->winbind_allow_mschapv2)
109 authparams.parameter_control |= WBC_MSV1_0_ALLOW_MSVCHAPV2;
113 * Send auth request across to winbind
115 wb_ctx = fr_connection_get(inst->wb_pool);
116 if (wb_ctx == NULL) {
117 RERROR("Unable to get winbind connection from pool");
121 RDEBUG2("sending authentication request user='%s' domain='%s'", authparams.account_name,
122 authparams.domain_name);
124 err = wbcCtxAuthenticateUserEx(wb_ctx, &authparams, &info, &error);
126 fr_connection_release(inst->wb_pool, wb_ctx);
130 * Try and give some useful feedback on what happened. There are only
131 * a few errors that can actually be returned from wbcCtxAuthenticateUserEx.
134 case WBC_ERR_SUCCESS:
136 RDEBUG2("Authenticated successfully");
137 /* Grab the nthashhash from the result */
138 memcpy(nthashhash, info->user_session_key, NT_DIGEST_LENGTH);
140 case WBC_ERR_WINBIND_NOT_AVAILABLE:
141 RERROR("Unable to contact winbind!");
142 RDEBUG2("Check that winbind is running and that FreeRADIUS has");
143 RDEBUG2("permission to connect to the winbind privileged socket.");
145 case WBC_ERR_DOMAIN_NOT_FOUND:
146 REDEBUG2("Domain not found");
148 case WBC_ERR_AUTH_ERROR:
150 REDEBUG2("Authentication failed");
155 * The password needs to be changed, so set rcode appropriately.
157 if (error->nt_status & NT_STATUS_PASSWORD_EXPIRED ||
158 error->nt_status & NT_STATUS_PASSWORD_MUST_CHANGE) {
163 * Return the NT_STATUS human readable error string, if there is one.
165 if (error->display_string) {
166 REDEBUG2("%s [0x%X]", error->display_string, error->nt_status);
168 REDEBUG2("Authentication failed [0x%X]", error->nt_status);
173 * Only errors left are
174 * WBC_ERR_INVALID_PARAM
176 * neither of which are particularly likely.
178 if (error && error->display_string) {
179 REDEBUG2("libwbclient error: wbcErr %d (%s)", err, error->display_string);
181 REDEBUG2("libwbclient error: wbcErr %d", err);
188 if (info) wbcFreeMemory(info);
189 if (error) wbcFreeMemory(error);