mirror of
https://github.com/samba-team/samba.git
synced 2024-12-24 21:34:56 +03:00
r6727: One more step down the long march to the 'Kerberos domain join'.
This patch allows a suitably patched Heimdal GSSAPI library (detected
in configure) to supply to us the session keys, and further compleats
the gensec_gssapi module. This is tested for CIFS, but fails for LDAP
at this point (that is what I'll work on next).
We currently fill out the 'session info' from the SAM, like
gensec_krb5 does, but both will need to use the PAC extraction
functions in the near future.
Andrew Bartlett
(This used to be commit 937ee36161
)
This commit is contained in:
parent
49304e965f
commit
8b2eb02d15
@ -14,7 +14,8 @@ REQUIRED_SUBSYSTEMS = \
|
||||
SUBSYSTEM = GENSEC
|
||||
INIT_FUNCTION = gensec_krb5_init
|
||||
INIT_OBJ_FILES = auth/gensec/gensec_krb5.o
|
||||
REQUIRED_SUBSYSTEMS = NDR_KRB5PAC KERBEROS EXT_LIB_KRB5
|
||||
REQUIRED_SUBSYSTEMS = NDR_KRB5PAC KERBEROS EXT_LIB_KRB5 REQUIRED_SUBSYSTEMS = AUTH
|
||||
|
||||
# End MODULE gensec_krb5
|
||||
################################################
|
||||
|
||||
@ -24,7 +25,7 @@ REQUIRED_SUBSYSTEMS = NDR_KRB5PAC KERBEROS EXT_LIB_KRB5
|
||||
SUBSYSTEM = GENSEC
|
||||
INIT_FUNCTION = gensec_gssapi_init
|
||||
INIT_OBJ_FILES = auth/gensec/gensec_gssapi.o
|
||||
REQUIRED_SUBSYSTEMS = EXT_LIB_KRB5
|
||||
REQUIRED_SUBSYSTEMS = EXT_LIB_KRB5 AUTH
|
||||
# End MODULE gensec_gssapi
|
||||
################################################
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
Kerberos backend for GENSEC
|
||||
|
||||
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
|
||||
Copyright (C) Stefan Metzmacher <metze@samba.org> 2005
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -23,11 +24,19 @@
|
||||
|
||||
#include "includes.h"
|
||||
#include "system/kerberos.h"
|
||||
#include "auth/kerberos/kerberos.h"
|
||||
#include "librpc/gen_ndr/ndr_krb5pac.h"
|
||||
#include "auth/auth.h"
|
||||
|
||||
#undef DBGC_CLASS
|
||||
#define DBGC_CLASS DBGC_AUTH
|
||||
|
||||
static const gss_OID_desc gensec_gss_krb5_mechanism_oid_desc =
|
||||
{9, (void *)discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02")};
|
||||
|
||||
static const gss_OID_desc gensec_gss_spnego_mechanism_oid_desc =
|
||||
{6, (void *)discard_const_p(char, "\x2b\x06\x01\x05\x05\x02")};
|
||||
|
||||
struct gensec_gssapi_state {
|
||||
gss_ctx_id_t gssapi_context;
|
||||
struct gss_channel_bindings_struct *input_chan_bindings;
|
||||
@ -35,6 +44,9 @@ struct gensec_gssapi_state {
|
||||
gss_name_t client_name;
|
||||
OM_uint32 want_flags, got_flags;
|
||||
const gss_OID_desc *gss_oid;
|
||||
|
||||
DATA_BLOB session_key;
|
||||
DATA_BLOB pac;
|
||||
};
|
||||
static int gensec_gssapi_destory(void *ptr)
|
||||
{
|
||||
@ -79,9 +91,14 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
|
||||
gensec_gssapi_state->want_flags = 0;
|
||||
gensec_gssapi_state->got_flags = 0;
|
||||
|
||||
gensec_gssapi_state->session_key = data_blob(NULL, 0);
|
||||
gensec_gssapi_state->pac = data_blob(NULL, 0);
|
||||
|
||||
if (gensec_security->want_features & GENSEC_FEATURE_SESSION_KEY) {
|
||||
/* GSSAPI won't give us the session keys */
|
||||
#ifndef HAVE_GSSKRB5_GET_INITIATOR_SUBKEY
|
||||
/* GSSAPI won't give us the session keys, without the right hook */
|
||||
return NT_STATUS_INVALID_PARAMETER;
|
||||
#endif
|
||||
}
|
||||
if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
|
||||
gensec_gssapi_state->want_flags |= GSS_C_INTEG_FLAG;
|
||||
@ -89,17 +106,17 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
|
||||
if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
|
||||
gensec_gssapi_state->want_flags |= GSS_C_CONF_FLAG;
|
||||
}
|
||||
if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) {
|
||||
gensec_gssapi_state->want_flags |= GSS_C_DCE_STYLE;
|
||||
}
|
||||
|
||||
if (strcmp(gensec_security->ops->oid, GENSEC_OID_KERBEROS5) == 0) {
|
||||
static const gss_OID_desc gensec_gss_krb5_mechanism_oid_desc =
|
||||
{9, (void *)discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02")};
|
||||
|
||||
gensec_gssapi_state->gss_oid = &gensec_gss_krb5_mechanism_oid_desc;
|
||||
} else if (strcmp(gensec_security->ops->oid, GENSEC_OID_SPNEGO) == 0) {
|
||||
static const gss_OID_desc gensec_gss_spnego_mechanism_oid_desc =
|
||||
{6, (void *)discard_const_p(char, "\x2b\x06\x01\x05\x05\x02")};
|
||||
gensec_gssapi_state->gss_oid = &gensec_gss_spnego_mechanism_oid_desc;
|
||||
} else {
|
||||
DEBUG(1, ("gensec_gssapi incorrectly configured - cannot determine gss OID from %s\n",
|
||||
gensec_security->ops->oid));
|
||||
return NT_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
@ -313,6 +330,198 @@ static NTSTATUS gensec_gssapi_unwrap(struct gensec_security *gensec_security,
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security)
|
||||
{
|
||||
/* not const but work for DCERPC packets and arcfour */
|
||||
return 45;
|
||||
}
|
||||
|
||||
static NTSTATUS gensec_gssapi_seal_packet(struct gensec_security *gensec_security,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
uint8_t *data, size_t length,
|
||||
const uint8_t *whole_pdu, size_t pdu_length,
|
||||
DATA_BLOB *sig)
|
||||
{
|
||||
struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
|
||||
OM_uint32 maj_stat, min_stat;
|
||||
gss_buffer_desc input_token, output_token;
|
||||
int conf_state;
|
||||
ssize_t sig_length = 0;
|
||||
|
||||
input_token.length = length;
|
||||
input_token.value = data;
|
||||
|
||||
maj_stat = gss_wrap(&min_stat,
|
||||
gensec_gssapi_state->gssapi_context,
|
||||
gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
|
||||
GSS_C_QOP_DEFAULT,
|
||||
&input_token,
|
||||
&conf_state,
|
||||
&output_token);
|
||||
if (GSS_ERROR(maj_stat)) {
|
||||
return NT_STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
if (output_token.length < length) {
|
||||
return NT_STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
sig_length = 45;
|
||||
|
||||
memcpy(data, ((uint8_t *)output_token.value) + sig_length, length);
|
||||
*sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length);
|
||||
|
||||
DEBUG(0,("gensec_gssapi_seal_packet: siglen: %d inlen: %d, wrap_len: %d\n", sig->length, length, output_token.length - sig_length));
|
||||
dump_data(0,sig->data, sig->length);
|
||||
dump_data(0,data, length);
|
||||
dump_data(0,((uint8_t *)output_token.value) + sig_length, output_token.length - sig_length);
|
||||
|
||||
gss_release_buffer(&min_stat, &output_token);
|
||||
|
||||
if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
|
||||
&& !conf_state) {
|
||||
return NT_STATUS_ACCESS_DENIED;
|
||||
}
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static NTSTATUS gensec_gssapi_unseal_packet(struct gensec_security *gensec_security,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
uint8_t *data, size_t length,
|
||||
const uint8_t *whole_pdu, size_t pdu_length,
|
||||
const DATA_BLOB *sig)
|
||||
{
|
||||
struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
|
||||
OM_uint32 maj_stat, min_stat;
|
||||
gss_buffer_desc input_token, output_token;
|
||||
int conf_state;
|
||||
gss_qop_t qop_state;
|
||||
DATA_BLOB in;
|
||||
|
||||
DEBUG(0,("gensec_gssapi_unseal_packet: siglen: %d\n", sig->length));
|
||||
dump_data(0,sig->data, sig->length);
|
||||
|
||||
in = data_blob_talloc(mem_ctx, NULL, sig->length + length);
|
||||
|
||||
memcpy(in.data, sig->data, sig->length);
|
||||
memcpy(in.data + sig->length, data, length);
|
||||
|
||||
input_token.length = in.length;
|
||||
input_token.value = in.data;
|
||||
|
||||
maj_stat = gss_unwrap(&min_stat,
|
||||
gensec_gssapi_state->gssapi_context,
|
||||
&input_token,
|
||||
&output_token,
|
||||
&conf_state,
|
||||
&qop_state);
|
||||
if (GSS_ERROR(maj_stat)) {
|
||||
return NT_STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
if (output_token.length != length) {
|
||||
return NT_STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
memcpy(data, output_token.value, length);
|
||||
|
||||
gss_release_buffer(&min_stat, &output_token);
|
||||
|
||||
if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
|
||||
&& !conf_state) {
|
||||
return NT_STATUS_ACCESS_DENIED;
|
||||
}
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static NTSTATUS gensec_gssapi_sign_packet(struct gensec_security *gensec_security,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const uint8_t *data, size_t length,
|
||||
const uint8_t *whole_pdu, size_t pdu_length,
|
||||
DATA_BLOB *sig)
|
||||
{
|
||||
struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
|
||||
OM_uint32 maj_stat, min_stat;
|
||||
gss_buffer_desc input_token, output_token;
|
||||
int conf_state;
|
||||
ssize_t sig_length = 0;
|
||||
|
||||
input_token.length = length;
|
||||
input_token.value = discard_const_p(uint8_t *, data);
|
||||
|
||||
maj_stat = gss_wrap(&min_stat,
|
||||
gensec_gssapi_state->gssapi_context,
|
||||
0,
|
||||
GSS_C_QOP_DEFAULT,
|
||||
&input_token,
|
||||
&conf_state,
|
||||
&output_token);
|
||||
if (GSS_ERROR(maj_stat)) {
|
||||
return NT_STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
if (output_token.length < length) {
|
||||
return NT_STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
sig_length = 45;
|
||||
|
||||
/*memcpy(data, ((uint8_t *)output_token.value) + sig_length, length);*/
|
||||
*sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length);
|
||||
|
||||
DEBUG(0,("gensec_gssapi_sign_packet: siglen: %d\n", sig->length));
|
||||
dump_data(0,sig->data, sig->length);
|
||||
|
||||
gss_release_buffer(&min_stat, &output_token);
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static NTSTATUS gensec_gssapi_check_packet(struct gensec_security *gensec_security,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const uint8_t *data, size_t length,
|
||||
const uint8_t *whole_pdu, size_t pdu_length,
|
||||
const DATA_BLOB *sig)
|
||||
{
|
||||
struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
|
||||
OM_uint32 maj_stat, min_stat;
|
||||
gss_buffer_desc input_token, output_token;
|
||||
int conf_state;
|
||||
gss_qop_t qop_state;
|
||||
DATA_BLOB in;
|
||||
|
||||
DEBUG(0,("gensec_gssapi_check_packet: siglen: %d\n", sig->length));
|
||||
dump_data(0,sig->data, sig->length);
|
||||
|
||||
in = data_blob_talloc(mem_ctx, NULL, sig->length + length);
|
||||
|
||||
memcpy(in.data, sig->data, sig->length);
|
||||
memcpy(in.data + sig->length, data, length);
|
||||
|
||||
input_token.length = in.length;
|
||||
input_token.value = in.data;
|
||||
|
||||
maj_stat = gss_unwrap(&min_stat,
|
||||
gensec_gssapi_state->gssapi_context,
|
||||
&input_token,
|
||||
&output_token,
|
||||
&conf_state,
|
||||
&qop_state);
|
||||
if (GSS_ERROR(maj_stat)) {
|
||||
return NT_STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
if (output_token.length != length) {
|
||||
return NT_STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
/*memcpy(data, output_token.value, length);*/
|
||||
|
||||
gss_release_buffer(&min_stat, &output_token);
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static BOOL gensec_gssapi_have_feature(struct gensec_security *gensec_security,
|
||||
uint32_t feature)
|
||||
{
|
||||
@ -323,9 +532,125 @@ static BOOL gensec_gssapi_have_feature(struct gensec_security *gensec_security,
|
||||
if (feature & GENSEC_FEATURE_SEAL) {
|
||||
return gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG;
|
||||
}
|
||||
if (feature & GENSEC_FEATURE_SESSION_KEY) {
|
||||
#ifdef HAVE_GSSKRB5_GET_INITIATOR_SUBKEY
|
||||
if ((gensec_gssapi_state->gss_oid->length == gensec_gss_krb5_mechanism_oid_desc.length)
|
||||
&& (memcmp(gensec_gssapi_state->gss_oid->elements, gensec_gss_krb5_mechanism_oid_desc.elements, gensec_gssapi_state->gss_oid->length) == 0)) {
|
||||
return True;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return False;
|
||||
}
|
||||
|
||||
static NTSTATUS gensec_gssapi_session_key(struct gensec_security *gensec_security,
|
||||
DATA_BLOB *session_key)
|
||||
{
|
||||
struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
|
||||
|
||||
if (gensec_gssapi_state->session_key.data) {
|
||||
*session_key = gensec_gssapi_state->session_key;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
#ifdef HAVE_GSSKRB5_GET_INITIATOR_SUBKEY
|
||||
if ((gensec_gssapi_state->gss_oid->length == gensec_gss_krb5_mechanism_oid_desc.length)
|
||||
&& (memcmp(gensec_gssapi_state->gss_oid->elements, gensec_gss_krb5_mechanism_oid_desc.elements, gensec_gssapi_state->gss_oid->length) == 0)) {
|
||||
OM_uint32 maj_stat, min_stat;
|
||||
gss_buffer_desc skey;
|
||||
|
||||
maj_stat = gsskrb5_get_initiator_subkey(&min_stat,
|
||||
gensec_gssapi_state->gssapi_context,
|
||||
&skey);
|
||||
|
||||
if (maj_stat == 0) {
|
||||
DEBUG(10, ("Got KRB5 session key of length %d\n", skey.length));
|
||||
gensec_gssapi_state->session_key = data_blob_talloc(gensec_gssapi_state,
|
||||
skey.value, skey.length);
|
||||
*session_key = gensec_gssapi_state->session_key;
|
||||
dump_data_pw("KRB5 Session Key:\n", session_key->data, session_key->length);
|
||||
|
||||
gss_release_buffer(&min_stat, &skey);
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
return NT_STATUS_NO_USER_SESSION_KEY;
|
||||
}
|
||||
#endif
|
||||
|
||||
DEBUG(1, ("NO session key for this mech\n"));
|
||||
return NT_STATUS_NO_USER_SESSION_KEY;
|
||||
}
|
||||
|
||||
static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_security,
|
||||
struct auth_session_info **_session_info)
|
||||
{
|
||||
NTSTATUS nt_status;
|
||||
struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
|
||||
struct auth_serversupplied_info *server_info = NULL;
|
||||
struct auth_session_info *session_info = NULL;
|
||||
char *p;
|
||||
char *principal;
|
||||
const char *account_name;
|
||||
const char *realm;
|
||||
OM_uint32 maj_stat, min_stat;
|
||||
gss_buffer_desc name_token;
|
||||
|
||||
maj_stat = gss_display_name (&min_stat,
|
||||
gensec_gssapi_state->client_name,
|
||||
&name_token,
|
||||
NULL);
|
||||
if (maj_stat) {
|
||||
return NT_STATUS_FOOBAR;
|
||||
}
|
||||
|
||||
principal = talloc_strndup(gensec_gssapi_state, name_token.value, name_token.length);
|
||||
|
||||
gss_release_buffer(&min_stat, &name_token);
|
||||
|
||||
NT_STATUS_HAVE_NO_MEMORY(principal);
|
||||
|
||||
p = strchr(principal, '@');
|
||||
if (p) {
|
||||
*p = '\0';
|
||||
p++;
|
||||
realm = p;
|
||||
} else {
|
||||
realm = lp_realm();
|
||||
}
|
||||
account_name = principal;
|
||||
|
||||
/* IF we have the PAC - otherwise we need to get this
|
||||
* data from elsewere - local ldb, or (TODO) lookup of some
|
||||
* kind...
|
||||
*
|
||||
* when heimdal can generate the PAC, we should fail if there's
|
||||
* no PAC present
|
||||
*/
|
||||
|
||||
{
|
||||
DATA_BLOB user_sess_key = data_blob(NULL, 0);
|
||||
DATA_BLOB lm_sess_key = data_blob(NULL, 0);
|
||||
/* TODO: should we pass the krb5 session key in here? */
|
||||
nt_status = sam_get_server_info(gensec_gssapi_state, account_name, realm,
|
||||
user_sess_key, lm_sess_key,
|
||||
&server_info);
|
||||
talloc_free(principal);
|
||||
NT_STATUS_NOT_OK_RETURN(nt_status);
|
||||
}
|
||||
|
||||
/* references the server_info into the session_info */
|
||||
nt_status = auth_generate_session_info(gensec_gssapi_state, server_info, &session_info);
|
||||
talloc_free(server_info);
|
||||
NT_STATUS_NOT_OK_RETURN(nt_status);
|
||||
|
||||
nt_status = gensec_gssapi_session_key(gensec_security, &session_info->session_key);
|
||||
NT_STATUS_NOT_OK_RETURN(nt_status);
|
||||
|
||||
*_session_info = session_info;
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/* As a server, this could in theory accept any GSSAPI mech */
|
||||
static const struct gensec_security_ops gensec_gssapi_krb5_security_ops = {
|
||||
.name = "gssapi_krb5",
|
||||
@ -334,6 +659,13 @@ static const struct gensec_security_ops gensec_gssapi_krb5_security_ops = {
|
||||
.client_start = gensec_gssapi_client_start,
|
||||
.server_start = gensec_gssapi_server_start,
|
||||
.update = gensec_gssapi_update,
|
||||
.session_key = gensec_gssapi_session_key,
|
||||
.session_info = gensec_gssapi_session_info,
|
||||
.sig_size = gensec_gssapi_sig_size,
|
||||
.sign_packet = gensec_gssapi_sign_packet,
|
||||
.check_packet = gensec_gssapi_check_packet,
|
||||
.seal_packet = gensec_gssapi_seal_packet,
|
||||
.unseal_packet = gensec_gssapi_unseal_packet,
|
||||
.wrap = gensec_gssapi_wrap,
|
||||
.unwrap = gensec_gssapi_unwrap,
|
||||
.have_feature = gensec_gssapi_have_feature,
|
||||
@ -348,6 +680,12 @@ static const struct gensec_security_ops gensec_gssapi_spnego_security_ops = {
|
||||
.client_start = gensec_gssapi_client_start,
|
||||
.server_start = gensec_gssapi_server_start,
|
||||
.update = gensec_gssapi_update,
|
||||
.session_key = gensec_gssapi_session_key,
|
||||
.sig_size = gensec_gssapi_sig_size,
|
||||
.sign_packet = gensec_gssapi_sign_packet,
|
||||
.check_packet = gensec_gssapi_check_packet,
|
||||
.seal_packet = gensec_gssapi_seal_packet,
|
||||
.unseal_packet = gensec_gssapi_unseal_packet,
|
||||
.wrap = gensec_gssapi_wrap,
|
||||
.unwrap = gensec_gssapi_unwrap,
|
||||
.have_feature = gensec_gssapi_have_feature,
|
||||
|
@ -452,6 +452,9 @@ if test x"$with_krb5_support" != x"no"; then
|
||||
samba_cv_GSS_C_DCE_STYLE=yes,
|
||||
samba_cv_GSS_C_DCE_STYLE=no)])
|
||||
|
||||
AC_CHECK_FUNC_EXT(gsskrb5_get_initiator_subkey, $KRB5_LIBS)
|
||||
AC_CHECK_FUNC_EXT(gsskrb5_extract_authz_data_from_sec_context, $KRB5_LIBS)
|
||||
|
||||
if test x"$ac_cv_lib_ext_krb5_krb5_mk_req_extended" = x"yes"; then
|
||||
AC_DEFINE(HAVE_KRB5,1,[Whether to have KRB5 support])
|
||||
AC_MSG_CHECKING(whether KRB5 support is used)
|
||||
|
Loading…
Reference in New Issue
Block a user