All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
auth_wbclient.c
Go to the documentation of this file.
1 /*
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.
6  *
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.
11  *
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
15  */
16 
17 /**
18  * $Id: f62e2d5d008048d068caef16790d78b0f883eb9f $
19  * @file auth_wbclient.c
20  * @brief NTLM authentication against the wbclient library
21  *
22  * @copyright 2015 Matthew Newton
23  */
24 
25 RCSID("$Id: f62e2d5d008048d068caef16790d78b0f883eb9f $")
26 
27 #include <freeradius-devel/radiusd.h>
28 #include <freeradius-devel/rad_assert.h>
29 
30 #include <wbclient.h>
31 #include <core/ntstatus.h>
32 
33 #include "rlm_mschap.h"
34 #include "mschap.h"
35 #include "auth_wbclient.h"
36 
37 #define NT_LENGTH 24
38 
39 /*
40  * Check NTLM authentication direct to winbind via
41  * Samba's libwbclient library
42  *
43  * Returns:
44  * 0 success
45  * -1 auth failure
46  * -648 password expired
47  */
49  uint8_t const *challenge, uint8_t const *response,
50  uint8_t nthashhash[NT_DIGEST_LENGTH])
51 {
52  int rcode = -1;
53  struct wbcContext *wb_ctx;
54  struct wbcAuthUserParams authparams;
55  wbcErr err;
56  int len;
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];
62 
63  /*
64  * Clear the auth parameters - this is important, as
65  * there are options that will cause wbcAuthenticateUserEx
66  * to bomb out if not zero.
67  */
68  memset(&authparams, 0, sizeof(authparams));
69 
70  /*
71  * wb_username must be set for this function to be called
72  */
73  rad_assert(inst->wb_username);
74 
75  /*
76  * Get the username and domain from the configuration
77  */
78  len = tmpl_expand(&authparams.account_name, user_name_buf, sizeof(user_name_buf),
79  request, inst->wb_username, NULL, NULL);
80  if (len < 0) {
81  REDEBUG2("Unable to expand winbind_username");
82  goto done;
83  }
84 
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);
88  if (len < 0) {
89  REDEBUG2("Unable to expand winbind_domain");
90  goto done;
91  }
92  } else {
93  RWDEBUG2("No domain specified; authentication may fail because of this");
94  }
95 
96 
97  /*
98  * Build the wbcAuthUserParams structure with what we know
99  */
100  authparams.level = WBC_AUTH_USER_LEVEL_RESPONSE;
101  authparams.password.response.nt_length = NT_LENGTH;
102 
103  memcpy(resp, response, NT_LENGTH);
104  authparams.password.response.nt_data = resp;
105 
106  memcpy(authparams.password.response.challenge, challenge,
107  sizeof(authparams.password.response.challenge));
108 
109 
110  /*
111  * Send auth request across to winbind
112  */
113  wb_ctx = fr_connection_get(inst->wb_pool);
114  if (wb_ctx == NULL) {
115  RERROR("Unable to get winbind connection from pool");
116  goto done;
117  }
118 
119  RDEBUG2("sending authentication request user='%s' domain='%s'", authparams.account_name,
120  authparams.domain_name);
121 
122  err = wbcCtxAuthenticateUserEx(wb_ctx, &authparams, &info, &error);
123 
124  fr_connection_release(inst->wb_pool, wb_ctx);
125 
126 
127  /*
128  * Try and give some useful feedback on what happened. There are only
129  * a few errors that can actually be returned from wbcCtxAuthenticateUserEx.
130  */
131  switch (err) {
132  case WBC_ERR_SUCCESS:
133  rcode = 0;
134  RDEBUG2("Authenticated successfully");
135  /* Grab the nthashhash from the result */
136  memcpy(nthashhash, info->user_session_key, NT_DIGEST_LENGTH);
137  break;
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.");
142  break;
143  case WBC_ERR_DOMAIN_NOT_FOUND:
144  REDEBUG2("Domain not found");
145  break;
146  case WBC_ERR_AUTH_ERROR:
147  if (!error) {
148  REDEBUG2("Authentication failed");
149  break;
150  }
151 
152  /*
153  * The password needs to be changed, so set rcode appropriately.
154  */
155  if (error->nt_status & NT_STATUS_PASSWORD_EXPIRED ||
156  error->nt_status & NT_STATUS_PASSWORD_MUST_CHANGE) {
157  rcode = -648;
158  }
159 
160  /*
161  * Return the NT_STATUS human readable error string, if there is one.
162  */
163  if (error->display_string) {
164  REDEBUG2("%s [0x%X]", error->display_string, error->nt_status);
165  } else {
166  REDEBUG2("Authentication failed [0x%X]", error->nt_status);
167  }
168  break;
169  default:
170  /*
171  * Only errors left are
172  * WBC_ERR_INVALID_PARAM
173  * WBC_ERR_NO_MEMORY
174  * neither of which are particularly likely.
175  */
176  if (error && error->display_string) {
177  REDEBUG2("libwbclient error: wbcErr %d (%s)", err, error->display_string);
178  } else {
179  REDEBUG2("libwbclient error: wbcErr %d", err);
180  }
181  break;
182  }
183 
184 
185 done:
186  if (info) wbcFreeMemory(info);
187  if (error) wbcFreeMemory(error);
188 
189  return rcode;
190 }
191 
ssize_t tmpl_expand(char const **out, char *buff, size_t outlen, REQUEST *request, vp_tmpl_t const *vpt, xlat_escape_t escape, void *escape_ctx)
Expand a vp_tmpl_t to a string writing the result to a buffer.
Definition: tmpl.c:1479
fr_connection_pool_t * wb_pool
Definition: rlm_mschap.h:41
#define RERROR(fmt,...)
Definition: log.h:207
#define REDEBUG2(fmt,...)
Definition: log.h:255
#define NT_DIGEST_LENGTH
Definition: mschap.h:8
#define inst
#define rad_assert(expr)
Definition: rad_assert.h:38
static bool done
Definition: radclient.c:53
vp_tmpl_t * wb_domain
Definition: rlm_mschap.h:40
#define RWDEBUG2(fmt,...)
Definition: log.h:252
#define RDEBUG2(fmt,...)
Definition: log.h:244
void * fr_connection_get(fr_connection_pool_t *pool)
Reserve a connection in the connection pool.
Definition: connection.c:1291
void fr_connection_release(fr_connection_pool_t *pool, void *conn)
Release a connection.
Definition: connection.c:1305
vp_tmpl_t * wb_username
Definition: rlm_mschap.h:39
#define RCSID(id)
Definition: build.h:135
#define NT_LENGTH
Definition: auth_wbclient.c:37
int do_auth_wbclient(rlm_mschap_t *inst, REQUEST *request, uint8_t const *challenge, uint8_t const *response, uint8_t nthashhash[NT_DIGEST_LENGTH])
Definition: auth_wbclient.c:48