mirror of
https://github.com/samba-team/samba.git
synced 2025-01-08 21:18:16 +03:00
winbind: Extend wbcAuthenticateUserEx to provide PAC
With this new interface, external applications that have authenticated to an ADS can pass the PAC from the Kerberos ticket to wbcAuthenticateUserEx. winbindd decodes and extracts the info3 information for the external application. If winbindd can verify the PAC signature, the info3 from the PACis also added to the netsamlogon_cache. The info3 data can be used by the external application to get the uid and primary gid. The data in netsamlogon_cache allows to retrieve the complete group list through the NSS function getgrouplist. Signed-off-by: Andrew Bartlett <abartlet@samba.org>
This commit is contained in:
parent
8a6a13ab51
commit
1bc2f28b94
@ -364,7 +364,7 @@ wbcErr wbcAuthenticateUserEx(const struct wbcAuthUserParams *params,
|
||||
BAIL_ON_WBC_ERROR(wbc_status);
|
||||
}
|
||||
|
||||
if (!params->account_name) {
|
||||
if (params->level != WBC_AUTH_USER_LEVEL_PAC && !params->account_name) {
|
||||
wbc_status = WBC_ERR_INVALID_PARAM;
|
||||
BAIL_ON_WBC_ERROR(wbc_status);
|
||||
}
|
||||
@ -491,6 +491,20 @@ wbcErr wbcAuthenticateUserEx(const struct wbcAuthUserParams *params,
|
||||
request.data.auth_crap.nt_resp_len);
|
||||
}
|
||||
break;
|
||||
|
||||
case WBC_AUTH_USER_LEVEL_PAC:
|
||||
cmd = WINBINDD_PAM_AUTH_CRAP;
|
||||
request.flags = WBFLAG_PAM_AUTH_PAC | WBFLAG_PAM_INFO3_TEXT;
|
||||
request.extra_data.data = malloc(params->password.pac.length);
|
||||
if (request.extra_data.data == NULL) {
|
||||
wbc_status = WBC_ERR_NO_MEMORY;
|
||||
BAIL_ON_WBC_ERROR(wbc_status);
|
||||
}
|
||||
memcpy(request.extra_data.data, params->password.pac.data,
|
||||
params->password.pac.length);
|
||||
request.extra_len = params->password.pac.length;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -196,40 +196,6 @@ struct wbcDomainInfo {
|
||||
#define WBC_DOMINFO_TRUSTTYPE_IN_FOREST 0x00000002
|
||||
#define WBC_DOMINFO_TRUSTTYPE_EXTERNAL 0x00000003
|
||||
|
||||
/**
|
||||
* @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;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Generic Blob
|
||||
**/
|
||||
@ -249,6 +215,42 @@ struct wbcNamedBlob {
|
||||
struct wbcBlob blob;
|
||||
};
|
||||
|
||||
/**
|
||||
* @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,
|
||||
WBC_AUTH_USER_LEVEL_PAC = 4
|
||||
} 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;
|
||||
struct wbcBlob pac;
|
||||
} password;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Logon User Parameters
|
||||
**/
|
||||
|
@ -218,6 +218,7 @@ typedef struct winbindd_gr {
|
||||
#define WBFLAG_PAM_FALLBACK_AFTER_KRB5 0x00002000
|
||||
#define WBFLAG_PAM_CACHED_LOGIN 0x00004000
|
||||
#define WBFLAG_PAM_GET_PWD_POLICY 0x00008000
|
||||
#define WBFLAG_PAM_AUTH_PAC 0x00010000
|
||||
|
||||
/* generic request flags */
|
||||
#define WBFLAG_QUERY_ONLY 0x00000020 /* not used */
|
||||
|
@ -38,6 +38,9 @@
|
||||
#include "passdb/machine_sid.h"
|
||||
#include "auth.h"
|
||||
#include "../lib/tsocket/tsocket.h"
|
||||
#include "auth/kerberos/pac_utils.h"
|
||||
#include "auth/gensec/gensec.h"
|
||||
#include "librpc/crypto/gse_krb5.h"
|
||||
|
||||
#undef DBGC_CLASS
|
||||
#define DBGC_CLASS DBGC_WINBIND
|
||||
@ -724,12 +727,12 @@ bool check_request_flags(uint32_t flags)
|
||||
/****************************************************************
|
||||
****************************************************************/
|
||||
|
||||
static NTSTATUS append_auth_data(TALLOC_CTX *mem_ctx,
|
||||
struct winbindd_response *resp,
|
||||
uint32_t request_flags,
|
||||
struct netr_SamInfo3 *info3,
|
||||
const char *name_domain,
|
||||
const char *name_user)
|
||||
NTSTATUS append_auth_data(TALLOC_CTX *mem_ctx,
|
||||
struct winbindd_response *resp,
|
||||
uint32_t request_flags,
|
||||
struct netr_SamInfo3 *info3,
|
||||
const char *name_domain,
|
||||
const char *name_user)
|
||||
{
|
||||
NTSTATUS result;
|
||||
|
||||
@ -2270,3 +2273,116 @@ enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domai
|
||||
|
||||
return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
#ifdef HAVE_KRB5
|
||||
static NTSTATUS extract_pac_vrfy_sigs(TALLOC_CTX *mem_ctx, DATA_BLOB pac_blob,
|
||||
struct PAC_LOGON_INFO **logon_info)
|
||||
{
|
||||
krb5_context krbctx = NULL;
|
||||
krb5_error_code k5ret;
|
||||
krb5_keytab keytab;
|
||||
krb5_kt_cursor cursor;
|
||||
krb5_keytab_entry entry;
|
||||
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
|
||||
|
||||
ZERO_STRUCT(entry);
|
||||
ZERO_STRUCT(cursor);
|
||||
|
||||
k5ret = krb5_init_context(&krbctx);
|
||||
if (k5ret) {
|
||||
DEBUG(1, ("Failed to initialize kerberos context: %s\n",
|
||||
error_message(k5ret)));
|
||||
status = krb5_to_nt_status(k5ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
k5ret = gse_krb5_get_server_keytab(krbctx, &keytab);
|
||||
if (k5ret) {
|
||||
DEBUG(1, ("Failed to get keytab: %s\n",
|
||||
error_message(k5ret)));
|
||||
status = krb5_to_nt_status(k5ret);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
k5ret = krb5_kt_start_seq_get(krbctx, keytab, &cursor);
|
||||
if (k5ret) {
|
||||
DEBUG(1, ("Failed to start seq: %s\n",
|
||||
error_message(k5ret)));
|
||||
status = krb5_to_nt_status(k5ret);
|
||||
goto out_keytab;
|
||||
}
|
||||
|
||||
k5ret = krb5_kt_next_entry(krbctx, keytab, &entry, &cursor);
|
||||
while (k5ret == 0) {
|
||||
status = kerberos_pac_logon_info(mem_ctx, pac_blob,
|
||||
krbctx, NULL,
|
||||
KRB5_KT_KEY(&entry), NULL, 0,
|
||||
logon_info);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
break;
|
||||
}
|
||||
k5ret = smb_krb5_kt_free_entry(krbctx, &entry);
|
||||
k5ret = krb5_kt_next_entry(krbctx, keytab, &entry, &cursor);
|
||||
}
|
||||
|
||||
k5ret = krb5_kt_end_seq_get(krbctx, keytab, &cursor);
|
||||
if (k5ret) {
|
||||
DEBUG(1, ("Failed to end seq: %s\n",
|
||||
error_message(k5ret)));
|
||||
}
|
||||
out_keytab:
|
||||
k5ret = krb5_kt_close(krbctx, keytab);
|
||||
if (k5ret) {
|
||||
DEBUG(1, ("Failed to close keytab: %s\n",
|
||||
error_message(k5ret)));
|
||||
}
|
||||
out_free:
|
||||
krb5_free_context(krbctx);
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS winbindd_pam_auth_pac_send(struct winbindd_cli_state *state,
|
||||
struct netr_SamInfo3 **info3)
|
||||
{
|
||||
struct winbindd_request *req = state->request;
|
||||
DATA_BLOB pac_blob;
|
||||
struct PAC_LOGON_INFO *logon_info = NULL;
|
||||
NTSTATUS result;
|
||||
|
||||
pac_blob = data_blob_const(req->extra_data.data, req->extra_len);
|
||||
result = extract_pac_vrfy_sigs(state->mem_ctx, pac_blob, &logon_info);
|
||||
if (!NT_STATUS_IS_OK(result) &&
|
||||
!NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
|
||||
DEBUG(1, ("Error during PAC signature verification: %s\n",
|
||||
nt_errstr(result)));
|
||||
return result;
|
||||
}
|
||||
|
||||
if (logon_info) {
|
||||
/* Signature verification succeeded, trust the PAC */
|
||||
netsamlogon_cache_store(NULL, &logon_info->info3);
|
||||
|
||||
} else {
|
||||
/* Try without signature verification */
|
||||
result = kerberos_pac_logon_info(state->mem_ctx, pac_blob, NULL,
|
||||
NULL, NULL, NULL, 0,
|
||||
&logon_info);
|
||||
if (!NT_STATUS_IS_OK(result)) {
|
||||
DEBUG(10, ("Could not extract PAC: %s\n",
|
||||
nt_errstr(result)));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
*info3 = &logon_info->info3;
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
#else /* HAVE_KRB5 */
|
||||
NTSTATUS winbindd_pam_auth_pac_send(struct winbindd_cli_state *state,
|
||||
struct netr_SamInfo3 **info3)
|
||||
{
|
||||
return NT_STATUS_NO_SUCH_USER;
|
||||
}
|
||||
#endif /* HAVE_KRB5 */
|
||||
|
@ -22,6 +22,8 @@
|
||||
|
||||
struct winbindd_pam_auth_crap_state {
|
||||
struct winbindd_response *response;
|
||||
struct netr_SamInfo3 *info3;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
static void winbindd_pam_auth_crap_done(struct tevent_req *subreq);
|
||||
@ -42,6 +44,21 @@ struct tevent_req *winbindd_pam_auth_crap_send(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (request->flags & WBFLAG_PAM_AUTH_PAC) {
|
||||
NTSTATUS status;
|
||||
|
||||
state->flags = request->flags;
|
||||
status = winbindd_pam_auth_pac_send(cli, &state->info3);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
/* Defer filling out response to recv */
|
||||
tevent_req_done(req);
|
||||
} else {
|
||||
tevent_req_nterror(req, status);
|
||||
}
|
||||
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
|
||||
/* Ensure null termination */
|
||||
request->data.auth_crap.user[
|
||||
sizeof(request->data.auth_crap.user)-1] = '\0';
|
||||
@ -114,6 +131,12 @@ NTSTATUS winbindd_pam_auth_crap_recv(struct tevent_req *req,
|
||||
set_auth_errors(response, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (state->flags & WBFLAG_PAM_AUTH_PAC) {
|
||||
return append_auth_data(response, response, state->flags,
|
||||
state->info3, NULL, NULL);
|
||||
}
|
||||
|
||||
*response = *state->response;
|
||||
response->result = WINBINDD_PENDING;
|
||||
state->response = talloc_move(response, &state->response);
|
||||
|
@ -353,6 +353,12 @@ void ndr_print_winbindd_domain(struct ndr_print *ndr,
|
||||
/* The following definitions come from winbindd/winbindd_pam.c */
|
||||
|
||||
bool check_request_flags(uint32_t flags);
|
||||
NTSTATUS append_auth_data(TALLOC_CTX *mem_ctx,
|
||||
struct winbindd_response *resp,
|
||||
uint32_t request_flags,
|
||||
struct netr_SamInfo3 *info3,
|
||||
const char *name_domain,
|
||||
const char *name_user);
|
||||
uid_t get_uid_from_request(struct winbindd_request *request);
|
||||
struct winbindd_domain *find_auth_domain(uint8_t flags,
|
||||
const char *domain_name);
|
||||
@ -365,6 +371,8 @@ enum winbindd_result winbindd_dual_pam_chauthtok(struct winbindd_domain *contact
|
||||
enum winbindd_result winbindd_dual_pam_logoff(struct winbindd_domain *domain,
|
||||
struct winbindd_cli_state *state) ;
|
||||
enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domain *domainSt, struct winbindd_cli_state *state);
|
||||
NTSTATUS winbindd_pam_auth_pac_send(struct winbindd_cli_state *state,
|
||||
struct netr_SamInfo3 **info3);
|
||||
|
||||
/* The following definitions come from winbindd/winbindd_util.c */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user