#define NT_LENGTH 24
+/** Use Winbind to normalise a username
+ *
+ * @param[in] tctx The talloc context where the result is parented from
+ * @param[in] ctx The winbind context
+ * @param[in] dom_name The domain of the user
+ * @param[in] name The username (without the domain) to be normalised
+ * @return The username with the casing according to the Winbind remote server,
+ * or NULL if the username could not be found.
+ */
+static char *wbclient_normalise_username(TALLOC_CTX *tctx, struct wbcContext *ctx, char const *dom_name, char const *name)
+{
+ struct wbcDomainSid sid;
+ enum wbcSidType name_type;
+ wbcErr err;
+ char *res_domain = NULL;
+ char *res_name = NULL;
+ char *res = NULL;
+
+ /* Step 1: Convert a name to a sid */
+ err = wbcCtxLookupName(ctx, dom_name, name, &sid, &name_type);
+ if (!WBC_ERROR_IS_OK(err))
+ return NULL;
+
+ /* Step 2: Convert the sid back to a name */
+ err = wbcCtxLookupSid(ctx, &sid, &res_domain, &res_name, &name_type);
+ if (!WBC_ERROR_IS_OK(err))
+ return NULL;
+
+ MEM(res = talloc_strdup(tctx, res_name));
+
+ wbcFreeMemory(res_domain);
+ wbcFreeMemory(res_name);
+
+ return res;
+}
+
/*
* Check NTLM authentication direct to winbind via
* Samba's libwbclient library
uint8_t nthashhash[NT_DIGEST_LENGTH])
{
int rcode = -1;
- struct wbcContext *wb_ctx;
+ struct wbcContext *wb_ctx = NULL;
struct wbcAuthUserParams authparams;
wbcErr err;
int len;
err = wbcCtxAuthenticateUserEx(wb_ctx, &authparams, &info, &error);
- fr_connection_release(inst->wb_pool, wb_ctx);
+ if (err == WBC_ERR_AUTH_ERROR && inst->wb_retry_with_normalised_username) {
+ VALUE_PAIR *vp_response, *vp_challenge;
+ char *normalised_username = wbclient_normalise_username(request, wb_ctx, authparams.domain_name, authparams.account_name);
+ if (normalised_username) {
+ RDEBUG2("Starting retry, normalised username %s to %s", authparams.account_name, normalised_username);
+ if (strcmp(authparams.account_name, normalised_username) != 0) {
+ authparams.account_name = normalised_username;
+
+ /* Set PW_MS_CHAP_USER_NAME */
+ if (!fr_pair_make(request->packet, &request->packet->vps, "MS-CHAP-User-Name", normalised_username, T_OP_SET)) {
+ RERROR("Failed creating MS-CHAP-User-Name");
+ goto normalised_username_retry_failure;
+ }
+
+ RDEBUG2("retrying authentication request user='%s' domain='%s'", authparams.account_name,
+ authparams.domain_name);
+
+ /* Recalculate hash */
+ if (!(vp_challenge = fr_pair_find_by_num(request->packet->vps, PW_MSCHAP_CHALLENGE, VENDORPEC_MICROSOFT, TAG_ANY))) {
+ RERROR("Unable to get MS-CHAP-Challenge");
+ goto normalised_username_retry_failure;
+ }
+ if (!(vp_response = fr_pair_find_by_num(request->packet->vps, PW_MSCHAP2_RESPONSE, VENDORPEC_MICROSOFT, TAG_ANY))) {
+ RERROR("Unable to get MS-CHAP2-Response");
+ goto normalised_username_retry_failure;
+ }
+ mschap_challenge_hash(vp_response->vp_octets + 2,
+ vp_challenge->vp_octets,
+ normalised_username,
+ authparams.password.response.challenge);
+ err = wbcCtxAuthenticateUserEx(wb_ctx, &authparams, &info, &error);
+ }
+normalised_username_retry_failure:
+ talloc_free(normalised_username);
+ }
+ }
+
+ fr_connection_release(inst->wb_pool, wb_ctx);
/*
* Try and give some useful feedback on what happened. There are only
{ "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 },
+ { "winbind_retry_with_normalised_username", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_mschap_t, wb_retry_with_normalised_username), "no" },
#ifdef __APPLE__
{ "use_open_directory", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_mschap_t, open_directory), "yes" },
#endif
mschap_result, mschap_version, smb_ctrl);
if (rcode != RLM_MODULE_OK) return rcode;
+#ifdef WITH_AUTH_WINBIND
+ if (inst->wb_retry_with_normalised_username) {
+ if ((response_name = fr_pair_find_by_num(request->packet->vps, PW_MS_CHAP_USER_NAME, 0, TAG_ANY))) {
+ if (strcmp(username_string, response_name->vp_strvalue)) {
+ RDEBUG2("Changing username %s to %s", username_string, response_name->vp_strvalue);
+ username_string = response_name->vp_strvalue;
+ }
+ }
+ }
+#endif
+
mschap_auth_response(username_string, /* without the domain */
nthashhash, /* nt-hash-hash */
response->vp_octets + 26, /* peer response */