From 9d27ded946daaa7d484f8b93921bac961ea2e071 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 24 Jan 2008 14:05:59 +0100 Subject: libwbclient: add wbcAuthenticateUserEx() function This function will be used by auth_winbind.c. metze (This used to be commit 72af96a320a97ce1a730d6e33d01950123d6a97c) --- source3/nsswitch/libwbclient/wbc_pam.c | 300 ++++++++++++++++++++++++++++++++ source3/nsswitch/libwbclient/wbclient.c | 2 + source3/nsswitch/libwbclient/wbclient.h | 159 ++++++++++++++++- 3 files changed, 460 insertions(+), 1 deletion(-) (limited to 'source3') diff --git a/source3/nsswitch/libwbclient/wbc_pam.c b/source3/nsswitch/libwbclient/wbc_pam.c index 7f7c7b8140..e7bcdfe20d 100644 --- a/source3/nsswitch/libwbclient/wbc_pam.c +++ b/source3/nsswitch/libwbclient/wbc_pam.c @@ -63,3 +63,303 @@ wbcErr wbcAuthenticateUser(const char *username, done: return wbc_status; } + +static wbcErr wbc_create_auth_info(TALLOC_CTX *mem_ctx, + const struct winbindd_response *resp, + struct wbcAuthUserInfo **_i) +{ + wbcErr wbc_status = WBC_ERR_SUCCESS; + struct wbcAuthUserInfo *i; + struct wbcDomainSid domain_sid; + char *p; + uint32_t sn = 0; + uint32_t j; + + i = talloc(mem_ctx, struct wbcAuthUserInfo); + BAIL_ON_PTR_ERROR(i, wbc_status); + + i->user_flags = resp->data.auth.info3.user_flgs; + + i->account_name = talloc_strdup(i, resp->data.auth.info3.user_name); + BAIL_ON_PTR_ERROR(i->account_name, wbc_status); + i->user_principal= NULL; + i->full_name = talloc_strdup(i, resp->data.auth.info3.full_name); + BAIL_ON_PTR_ERROR(i->full_name, wbc_status); + i->domain_name = talloc_strdup(i, resp->data.auth.info3.logon_dom); + BAIL_ON_PTR_ERROR(i->domain_name, wbc_status); + i->dns_domain_name= NULL; + + i->acct_flags = resp->data.auth.info3.acct_flags; + memcpy(i->user_session_key, + resp->data.auth.user_session_key, + sizeof(i->user_session_key)); + memcpy(i->lm_session_key, + resp->data.auth.first_8_lm_hash, + sizeof(i->lm_session_key)); + + i->logon_count = resp->data.auth.info3.logon_count; + i->bad_password_count = resp->data.auth.info3.bad_pw_count; + + i->logon_time = resp->data.auth.info3.logon_time; + i->logoff_time = resp->data.auth.info3.logoff_time; + i->kickoff_time = resp->data.auth.info3.kickoff_time; + i->pass_last_set_time = resp->data.auth.info3.pass_last_set_time; + i->pass_can_change_time = resp->data.auth.info3.pass_can_change_time; + i->pass_must_change_time= resp->data.auth.info3.pass_must_change_time; + + i->logon_server = talloc_strdup(i, resp->data.auth.info3.logon_srv); + BAIL_ON_PTR_ERROR(i->logon_server, wbc_status); + i->logon_script = talloc_strdup(i, resp->data.auth.info3.logon_script); + BAIL_ON_PTR_ERROR(i->logon_script, wbc_status); + i->profile_path = talloc_strdup(i, resp->data.auth.info3.profile_path); + BAIL_ON_PTR_ERROR(i->profile_path, wbc_status); + i->home_directory= talloc_strdup(i, resp->data.auth.info3.home_dir); + BAIL_ON_PTR_ERROR(i->home_directory, wbc_status); + i->home_drive = talloc_strdup(i, resp->data.auth.info3.dir_drive); + BAIL_ON_PTR_ERROR(i->home_drive, wbc_status); + + i->num_sids = 2; + i->num_sids += resp->data.auth.info3.num_groups; + i->num_sids += resp->data.auth.info3.num_other_sids; + + i->sids = talloc_array(i, struct wbcSidWithAttr, i->num_sids); + BAIL_ON_PTR_ERROR(i->sids, wbc_status); + + wbc_status = wbcStringToSid(resp->data.auth.info3.dom_sid, + &domain_sid); + BAIL_ON_WBC_ERROR(wbc_status); + +#define _SID_COMPOSE(s, d, r, a) { \ + (s).sid = d; \ + if ((s).sid.num_auths < MAXSUBAUTHS) { \ + (s).sid.sub_auths[(s).sid.num_auths++] = r; \ + } else { \ + wbc_status = WBC_ERR_INVALID_SID; \ + BAIL_ON_WBC_ERROR(wbc_status); \ + } \ + (s).attributes = a; \ +} while (0) + + sn = 0; + _SID_COMPOSE(i->sids[sn], domain_sid, + resp->data.auth.info3.user_rid, + 0); + sn++; + _SID_COMPOSE(i->sids[sn], domain_sid, + resp->data.auth.info3.group_rid, + 0); + sn++; + + p = resp->extra_data.data; + if (!p) { + wbc_status = WBC_INVALID_RESPONSE; + BAIL_ON_WBC_ERROR(wbc_status); + } + + for (j=0; j < resp->data.auth.info3.num_groups; j++) { + uint32_t rid; + uint32_t attrs; + int ret; + char *s = p; + char *e = strchr(p, '\n'); + if (!e) { + wbc_status = WBC_INVALID_RESPONSE; + BAIL_ON_WBC_ERROR(wbc_status); + } + e[0] = '\0'; + p = &e[1]; + + ret = sscanf(s, "0x%08X:0x%08X", &rid, &attrs); + if (ret != 2) { + wbc_status = WBC_INVALID_RESPONSE; + BAIL_ON_WBC_ERROR(wbc_status); + } + + _SID_COMPOSE(i->sids[sn], domain_sid, + rid, attrs); + sn++; + } + + for (j=0; j < resp->data.auth.info3.num_other_sids; j++) { + uint32_t attrs; + int ret; + char *s = p; + char *a; + char *e = strchr(p, '\n'); + if (!e) { + wbc_status = WBC_INVALID_RESPONSE; + BAIL_ON_WBC_ERROR(wbc_status); + } + e[0] = '\0'; + p = &e[1]; + + e = strchr(s, ':'); + if (!e) { + wbc_status = WBC_INVALID_RESPONSE; + BAIL_ON_WBC_ERROR(wbc_status); + } + e[0] = '\0'; + a = &e[1]; + + ret = sscanf(a, "0x%08X", + &attrs); + if (ret != 1) { + wbc_status = WBC_INVALID_RESPONSE; + BAIL_ON_WBC_ERROR(wbc_status); + } + + wbc_status = wbcStringToSid(s, &i->sids[sn].sid); + BAIL_ON_WBC_ERROR(wbc_status); + + i->sids[sn].attributes = attrs; + sn++; + } + + i->num_sids = sn; + + *_i = i; + i = NULL; +done: + talloc_free(i); + return wbc_status; +} + +static wbcErr wbc_create_error_info(TALLOC_CTX *mem_ctx, + const struct winbindd_response *resp, + struct wbcAuthErrorInfo **_e) +{ + wbcErr wbc_status = WBC_ERR_SUCCESS; + struct wbcAuthErrorInfo *e; + + e = talloc(mem_ctx, struct wbcAuthErrorInfo); + BAIL_ON_PTR_ERROR(e, wbc_status); + + e->nt_status = resp->data.auth.nt_status; + e->pam_error = resp->data.auth.pam_error; + e->nt_string = talloc_strdup(e, resp->data.auth.nt_status_string); + BAIL_ON_PTR_ERROR(e->nt_string, wbc_status); + + e->display_string = talloc_strdup(e, resp->data.auth.error_string); + BAIL_ON_PTR_ERROR(e->display_string, wbc_status); + + *_e = e; + e = NULL; + +done: + talloc_free(e); + return wbc_status; +} + +/** @brief Authenticate with more detailed information + * + * @param params Input parameters, only WBC_AUTH_USER_LEVEL_RESPONSE + * is supported yet + * @param info Output details on WBC_ERR_SUCCESS + * @param error Output details on WBC_ERR_AUTH_ERROR + * + * @return #wbcErr + **/ + +wbcErr wbcAuthenticateUserEx(const struct wbcAuthUserParams *params, + struct wbcAuthUserInfo **info, + struct wbcAuthErrorInfo **error) +{ + wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + int cmd; + struct winbindd_request request; + struct winbindd_response response; + + + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + if (error) { + *error = NULL; + } + + if (!params) { + wbc_status = WBC_ERR_INVALID_PARAM; + BAIL_ON_WBC_ERROR(wbc_status); + } + + /* Initialize request */ + + switch (params->level) { + case WBC_AUTH_USER_LEVEL_PLAIN: + wbc_status = WBC_ERR_NOT_IMPLEMENTED; + BAIL_ON_WBC_ERROR(wbc_status); + break; + + case WBC_AUTH_USER_LEVEL_HASH: + wbc_status = WBC_ERR_NOT_IMPLEMENTED; + BAIL_ON_WBC_ERROR(wbc_status); + break; + + case WBC_AUTH_USER_LEVEL_RESPONSE: + cmd = WINBINDD_PAM_AUTH_CRAP; + request.flags = WBFLAG_PAM_INFO3_TEXT | + WBFLAG_PAM_USER_SESSION_KEY | + WBFLAG_PAM_LMKEY; + + strncpy(request.data.auth_crap.user, + params->account_name, + sizeof(request.data.auth_crap.user)-1); + strncpy(request.data.auth_crap.domain, + params->domain_name, + sizeof(request.data.auth_crap.domain)-1); + if (params->workstation_name) { + strncpy(request.data.auth_crap.workstation, + params->workstation_name, + sizeof(request.data.auth_crap.workstation)-1); + } + + request.data.auth_crap.logon_parameters = + params->parameter_control; + + memcpy(request.data.auth_crap.chal, + params->password.response.challenge, + sizeof(request.data.auth_crap.chal)); + + request.data.auth_crap.lm_resp_len = + MIN(params->password.response.lm_length, + sizeof(request.data.auth_crap.lm_resp)); + request.data.auth_crap.nt_resp_len = + MIN(params->password.response.nt_length, + sizeof(request.data.auth_crap.nt_resp)); + memcpy(request.data.auth_crap.lm_resp, + params->password.response.lm_data, + request.data.auth_crap.lm_resp_len); + memcpy(request.data.auth_crap.nt_resp, + params->password.response.nt_data, + request.data.auth_crap.nt_resp_len); + + break; + } + + wbc_status = wbcRequestResponse(cmd, + &request, + &response); + if (response.data.auth.nt_status != 0) { + if (error) { + wbc_status = wbc_create_error_info(NULL, + &response, + error); + BAIL_ON_WBC_ERROR(wbc_status); + } + + wbc_status = WBC_ERR_AUTH_ERROR; + BAIL_ON_WBC_ERROR(wbc_status); + } + BAIL_ON_WBC_ERROR(wbc_status); + + if (info) { + wbc_status = wbc_create_auth_info(NULL, + &response, + info); + BAIL_ON_WBC_ERROR(wbc_status); + } + +done: + + return wbc_status; +} diff --git a/source3/nsswitch/libwbclient/wbclient.c b/source3/nsswitch/libwbclient/wbclient.c index 5aad378ad0..e17296283f 100644 --- a/source3/nsswitch/libwbclient/wbclient.c +++ b/source3/nsswitch/libwbclient/wbclient.c @@ -110,6 +110,8 @@ const char *wbcErrorString(wbcErr error) return "WBC_INVALID_RESPONSE"; case WBC_ERR_NSS_ERROR: return "WBC_ERR_NSS_ERROR"; + case WBC_ERR_AUTH_ERROR: + return "WBC_ERR_AUTH_ERROR"; } return "unknown wbcErr value"; diff --git a/source3/nsswitch/libwbclient/wbclient.h b/source3/nsswitch/libwbclient/wbclient.h index ef9e3557da..c01db9618d 100644 --- a/source3/nsswitch/libwbclient/wbclient.h +++ b/source3/nsswitch/libwbclient/wbclient.h @@ -41,7 +41,8 @@ enum _wbcErrType { WBC_ERR_WINBIND_NOT_AVAILABLE, /**< Winbind daemon is not available **/ WBC_ERR_DOMAIN_NOT_FOUND, /**< Domain is not trusted or cannot be found **/ WBC_INVALID_RESPONSE, /**< Winbind returned an invalid response **/ - WBC_ERR_NSS_ERROR /**< NSS_STATUS error **/ + WBC_ERR_NSS_ERROR, /**< NSS_STATUS error **/ + WBC_ERR_AUTH_ERROR /**< Authentication failed **/ }; typedef enum _wbcErrType wbcErr; @@ -87,6 +88,25 @@ enum wbcSidType { WBC_SID_NAME_COMPUTER=9 }; +/** + * @brief Security Identifier with attributes + **/ + +struct wbcSidWithAttr { + struct wbcDomainSid sid; + uint32_t attributes; +}; + +/* wbcSidWithAttr->attributes */ + +#define WBC_SID_ATTR_GROUP_MANDATORY 0x00000001 +#define WBC_SID_ATTR_GROUP_ENABLED_BY_DEFAULT 0x00000002 +#define WBC_SID_ATTR_GROUP_ENABLED 0x00000004 +#define WBC_SID_ATTR_GROUP_OWNER 0x00000008 +#define WBC_SID_ATTR_GROUP_USEFOR_DENY_ONLY 0x00000010 +#define WBC_SID_ATTR_GROUP_RESOURCE 0x20000000 +#define WBC_SID_ATTR_GROUP_LOGON_ID 0xC0000000 + /** * @brief Domain Information **/ @@ -104,6 +124,140 @@ struct wbcDomainInfo { #define WBC_DOMINFO_AD 0x00000002 #define WBC_DOMINFO_PRIMARY 0x00000004 +/** + * @brief Auth User Parameters + **/ + +struct wbcAuthUserParams { + const char *account_name; + const char *domain_name; + const char *workstation_name; + + uint32_t flags; + + uint32_t parameter_control; + + enum wbcAuthUserLevel { + WBC_AUTH_USER_LEVEL_PLAIN = 1, + WBC_AUTH_USER_LEVEL_HASH = 2, + WBC_AUTH_USER_LEVEL_RESPONSE = 3 + } level; + union { + const char *plaintext; + struct { + uint8_t nt_hash[16]; + uint8_t lm_hash[16]; + } hash; + struct { + uint8_t challenge[8]; + uint32_t nt_length; + uint8_t *nt_data; + uint32_t lm_length; + uint8_t *lm_data; + } response; + } password; +}; + +/* wbcAuthUserParams->parameter_control */ + +#define WBC_MSV1_0_CLEARTEXT_PASSWORD_ALLOWED 0x00000002 +#define WBC_MSV1_0_UPDATE_LOGON_STATISTICS 0x00000004 +#define WBC_MSV1_0_RETURN_USER_PARAMETERS 0x00000008 +#define WBC_MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT 0x00000020 +#define WBC_MSV1_0_RETURN_PROFILE_PATH 0x00000200 +#define WBC_MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT 0x00000800 + +/* wbcAuthUserParams->flags */ + +#define WBC_AUTH_PARAM_FLAGS_INTERACTIVE_LOGON 0x00000001 + +/** + * @brief Auth User Information + * + * Some of the strings are maybe NULL + **/ + +struct wbcAuthUserInfo { + uint32_t user_flags; + + char *account_name; + char *user_principal; + char *full_name; + char *domain_name; + char *dns_domain_name; + + uint32_t acct_flags; + uint8_t user_session_key[16]; + uint8_t lm_session_key[8]; + + uint16_t logon_count; + uint16_t bad_password_count; + + uint64_t logon_time; + uint64_t logoff_time; + uint64_t kickoff_time; + uint64_t pass_last_set_time; + uint64_t pass_can_change_time; + uint64_t pass_must_change_time; + + char *logon_server; + char *logon_script; + char *profile_path; + char *home_directory; + char *home_drive; + + /* + * the 1st one is the account sid + * the 2nd one is the primary_group sid + * followed by the rest of the groups + */ + uint32_t num_sids; + struct wbcSidWithAttr *sids; +}; + +/* wbcAuthUserInfo->user_flags */ + +#define WBC_AUTH_USER_INFO_GUEST 0x00000001 +#define WBC_AUTH_USER_INFO_NOENCRYPTION 0x00000002 +#define WBC_AUTH_USER_INFO_CACHED_ACCOUNT 0x00000004 +#define WBC_AUTH_USER_INFO_USED_LM_PASSWORD 0x00000008 +#define WBC_AUTH_USER_INFO_EXTRA_SIDS 0x00000020 +#define WBC_AUTH_USER_INFO_SUBAUTH_SESSION_KEY 0x00000040 +#define WBC_AUTH_USER_INFO_SERVER_TRUST_ACCOUNT 0x00000080 +#define WBC_AUTH_USER_INFO_NTLMV2_ENABLED 0x00000100 +#define WBC_AUTH_USER_INFO_RESOURCE_GROUPS 0x00000200 +#define WBC_AUTH_USER_INFO_PROFILE_PATH_RETURNED 0x00000400 +#define WBC_AUTH_USER_INFO_GRACE_LOGON 0x01000000 + +/* wbcAuthUserInfo->acct_flags */ + +#define WBC_ACB_DISABLED 0x00000001 /* 1 User account disabled */ +#define WBC_ACB_HOMDIRREQ 0x00000002 /* 1 Home directory required */ +#define WBC_ACB_PWNOTREQ 0x00000004 /* 1 User password not required */ +#define WBC_ACB_TEMPDUP 0x00000008 /* 1 Temporary duplicate account */ +#define WBC_ACB_NORMAL 0x00000010 /* 1 Normal user account */ +#define WBC_ACB_MNS 0x00000020 /* 1 MNS logon user account */ +#define WBC_ACB_DOMTRUST 0x00000040 /* 1 Interdomain trust account */ +#define WBC_ACB_WSTRUST 0x00000080 /* 1 Workstation trust account */ +#define WBC_ACB_SVRTRUST 0x00000100 /* 1 Server trust account */ +#define WBC_ACB_PWNOEXP 0x00000200 /* 1 User password does not expire */ +#define WBC_ACB_AUTOLOCK 0x00000400 /* 1 Account auto locked */ +#define WBC_ACB_ENC_TXT_PWD_ALLOWED 0x00000800 /* 1 Encryped text password is allowed */ +#define WBC_ACB_SMARTCARD_REQUIRED 0x00001000 /* 1 Smart Card required */ +#define WBC_ACB_TRUSTED_FOR_DELEGATION 0x00002000 /* 1 Trusted for Delegation */ +#define WBC_ACB_NOT_DELEGATED 0x00004000 /* 1 Not delegated */ +#define WBC_ACB_USE_DES_KEY_ONLY 0x00008000 /* 1 Use DES key only */ +#define WBC_ACB_DONT_REQUIRE_PREAUTH 0x00010000 /* 1 Preauth not required */ +#define WBC_ACB_PW_EXPIRED 0x00020000 /* 1 Password Expired */ +#define WBC_ACB_NO_AUTH_DATA_REQD 0x00080000 /* 1 = No authorization data required */ + +struct wbcAuthErrorInfo { + uint32_t nt_status; + char *nt_string; + int32_t pam_error; + char *display_string; +}; + /* * Memory Management */ @@ -205,5 +359,8 @@ wbcErr wbcDomainSequenceNumbers(void); wbcErr wbcAuthenticateUser(const char *username, const char *password); +wbcErr wbcAuthenticateUserEx(const struct wbcAuthUserParams *params, + struct wbcAuthUserInfo **info, + struct wbcAuthErrorInfo **error); #endif /* _WBCLIENT_H */ -- cgit