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>
31 #include <core/ntstatus.h>
33 #include "rlm_mschap.h"
35 #include "auth_wbclient.h"
40 * Check NTLM authentication direct to winbind via
41 * Samba's libwbclient library
46 * -648 password expired
48 int do_auth_wbclient(rlm_mschap_t *inst, REQUEST *request,
49 uint8_t const *challenge, uint8_t const *response,
50 uint8_t nthashhash[NT_DIGEST_LENGTH])
53 struct wbcContext *wb_ctx;
54 struct wbcAuthUserParams authparams;
57 struct wbcAuthUserInfo *info = NULL;
58 struct wbcAuthErrorInfo *error = NULL;
59 char user_name_buf[500];
60 char domain_name_buf[500];
61 uint8_t resp[NT_LENGTH];
64 * Clear the auth parameters - this is important, as
65 * there are options that will cause wbcAuthenticateUserEx
66 * to bomb out if not zero.
68 memset(&authparams, 0, sizeof(authparams));
71 * wb_username must be set for this function to be called
73 rad_assert(inst->wb_username);
76 * Get the username and domain from the configuration
78 len = tmpl_expand(&authparams.account_name, user_name_buf, sizeof(user_name_buf),
79 request, inst->wb_username, NULL, NULL);
81 REDEBUG2("Unable to expand winbind_username");
85 if (inst->wb_domain) {
86 len = tmpl_expand(&authparams.domain_name, domain_name_buf, sizeof(domain_name_buf),
87 request, inst->wb_domain, NULL, NULL);
89 REDEBUG2("Unable to expand winbind_domain");
93 RWDEBUG2("No domain specified; authentication may fail because of this");
98 * Build the wbcAuthUserParams structure with what we know
100 authparams.level = WBC_AUTH_USER_LEVEL_RESPONSE;
101 authparams.password.response.nt_length = NT_LENGTH;
103 memcpy(resp, response, NT_LENGTH);
104 authparams.password.response.nt_data = resp;
106 memcpy(authparams.password.response.challenge, challenge,
107 sizeof(authparams.password.response.challenge));
111 * Send auth request across to winbind
113 wb_ctx = fr_connection_get(inst->wb_pool);
114 if (wb_ctx == NULL) {
115 RERROR("Unable to get winbind connection from pool");
119 RDEBUG2("sending authentication request user='%s' domain='%s'", authparams.account_name,
120 authparams.domain_name);
122 err = wbcCtxAuthenticateUserEx(wb_ctx, &authparams, &info, &error);
124 fr_connection_release(inst->wb_pool, wb_ctx);
128 * Try and give some useful feedback on what happened. There are only
129 * a few errors that can actually be returned from wbcCtxAuthenticateUserEx.
132 case WBC_ERR_SUCCESS:
134 RDEBUG2("Authenticated successfully");
135 /* Grab the nthashhash from the result */
136 memcpy(nthashhash, info->user_session_key, NT_DIGEST_LENGTH);
138 case WBC_ERR_WINBIND_NOT_AVAILABLE:
139 RERROR("Unable to contact winbind!");
140 RDEBUG2("Check that winbind is running and that FreeRADIUS has");
141 RDEBUG2("permission to connect to the winbind privileged socket.");
143 case WBC_ERR_DOMAIN_NOT_FOUND:
144 REDEBUG2("Domain not found");
146 case WBC_ERR_AUTH_ERROR:
148 REDEBUG2("Authentication failed");
153 * The password needs to be changed, so set rcode appropriately.
155 if (error->nt_status & NT_STATUS_PASSWORD_EXPIRED ||
156 error->nt_status & NT_STATUS_PASSWORD_MUST_CHANGE) {
161 * Return the NT_STATUS human readable error string, if there is one.
163 if (error->display_string) {
164 REDEBUG2("%s [0x%X]", error->display_string, error->nt_status);
166 REDEBUG2("Authentication failed [0x%X]", error->nt_status);
171 * Only errors left are
172 * WBC_ERR_INVALID_PARAM
174 * neither of which are particularly likely.
176 if (error && error->display_string) {
177 REDEBUG2("libwbclient error: wbcErr %d (%s)", err, error->display_string);
179 REDEBUG2("libwbclient error: wbcErr %d", err);
186 if (info) wbcFreeMemory(info);
187 if (error) wbcFreeMemory(error);