1
0
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 commit is contained in:
Andrew Bartlett 2005-05-11 12:03:48 +00:00 committed by Gerald (Jerry) Carter
parent 2b36f1dfdd
commit 937ee36161
3 changed files with 350 additions and 8 deletions

View File

@ -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
################################################

View File

@ -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,

View File

@ -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)