merge most of the initiator part from the samba patch by Stefan Metzmacher and Andrew Bartlet (still missing DCE/RPC support)

git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@18147 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
Love Hörnquist Åstrand
2006-09-22 10:41:31 +00:00
parent 1ade93b8c6
commit 226ba0b6cd
2 changed files with 287 additions and 130 deletions

View File

@@ -64,10 +64,22 @@ typedef struct {
COMPAT_OLD_DES3_SELECTED = 8,
ACCEPTOR_SUBKEY = 16
} more_flags;
enum gss_ctx_id_t_state {
/* initiator states */
INITIATOR_START,
INITIATOR_WAIT_FOR_MUTAL,
INITIATOR_READY,
/* acceptor states */
ACCEPTOR_START,
ACCEPTOR_WAIT_FOR_DCESTYLE,
ACCEPTOR_READY
} state;
struct krb5_ticket *ticket;
OM_uint32 lifetime;
HEIMDAL_MUTEX ctx_id_mutex;
struct gss_msg_order *order;
krb5_keyblock *service_keyblock;
krb5_data fwd_data;
} *gsskrb5_ctx;
typedef struct {

View File

@@ -97,6 +97,173 @@ set_addresses (krb5_auth_context ac,
return kret;
}
OM_uint32
_gsskrb5_create_ctx(
OM_uint32 * minor_status,
gss_ctx_id_t * context_handle,
const gss_channel_bindings_t input_chan_bindings,
enum gss_ctx_id_t_state state)
{
krb5_error_code kret;
gsskrb5_ctx ctx;
*context_handle = NULL;
ctx = malloc(sizeof(*ctx));
if (ctx == NULL) {
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
ctx->auth_context = NULL;
ctx->source = NULL;
ctx->target = NULL;
ctx->state = state;
ctx->flags = 0;
ctx->more_flags = 0;
ctx->service_keyblock = NULL;
ctx->ticket = NULL;
krb5_data_zero(&ctx->fwd_data);
ctx->lifetime = GSS_C_INDEFINITE;
ctx->order = NULL;
HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex);
kret = krb5_auth_con_init (_gsskrb5_context, &ctx->auth_context);
if (kret) {
*minor_status = kret;
_gsskrb5_set_error_string ();
HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex);
return GSS_S_FAILURE;
}
kret = set_addresses(ctx->auth_context, input_chan_bindings);
if (kret) {
*minor_status = kret;
HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex);
krb5_auth_con_free(_gsskrb5_context, ctx->auth_context);
return GSS_S_BAD_BINDINGS;
}
/*
* We need a sequence number
*/
krb5_auth_con_addflags(_gsskrb5_context,
ctx->auth_context,
KRB5_AUTH_CONTEXT_DO_SEQUENCE |
KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED,
NULL);
*context_handle = (gss_ctx_id_t)ctx;
return GSS_S_COMPLETE;
}
static OM_uint32
gsskrb5_get_creds(
OM_uint32 * minor_status,
krb5_ccache ccache,
gsskrb5_ctx ctx,
krb5_const_principal target_name,
OM_uint32 time_req,
OM_uint32 * time_rec,
krb5_creds ** cred)
{
OM_uint32 ret;
krb5_error_code kret;
krb5_creds this_cred;
OM_uint32 lifetime_rec;
*cred = NULL;
kret = krb5_cc_get_principal(_gsskrb5_context, ccache, &ctx->source);
if (kret) {
_gsskrb5_set_error_string ();
*minor_status = kret;
return GSS_S_FAILURE;
}
kret = krb5_copy_principal(_gsskrb5_context, target_name, &ctx->target);
if (kret) {
_gsskrb5_set_error_string ();
*minor_status = kret;
return GSS_S_FAILURE;
}
memset(&this_cred, 0, sizeof(this_cred));
this_cred.client = ctx->source;
this_cred.server = ctx->target;
if (time_req && time_req != GSS_C_INDEFINITE) {
krb5_timestamp ts;
krb5_timeofday (_gsskrb5_context, &ts);
this_cred.times.endtime = ts + time_req;
} else {
this_cred.times.endtime = 0;
}
this_cred.session.keytype = KEYTYPE_NULL;
kret = krb5_get_credentials(_gsskrb5_context,
0,
ccache,
&this_cred,
cred);
if (kret) {
_gsskrb5_set_error_string ();
*minor_status = kret;
return GSS_S_FAILURE;
}
ctx->lifetime = (*cred)->times.endtime;
ret = _gsskrb5_lifetime_left(minor_status, ctx->lifetime, &lifetime_rec);
if (ret) return ret;
if (lifetime_rec == 0) {
*minor_status = 0;
return GSS_S_CONTEXT_EXPIRED;
}
if (time_rec) *time_rec = lifetime_rec;
return GSS_S_COMPLETE;
}
static OM_uint32
gsskrb5_initiator_ready(
OM_uint32 * minor_status,
gsskrb5_ctx ctx)
{
OM_uint32 ret;
int32_t seq_number;
int is_cfx = 0;
OM_uint32 flags = ctx->flags;
krb5_auth_getremoteseqnumber (_gsskrb5_context,
ctx->auth_context,
&seq_number);
_gsskrb5i_is_cfx(ctx, &is_cfx);
ret = _gssapi_msg_order_create(minor_status,
&ctx->order,
_gssapi_msg_order_f(flags),
seq_number, 0, is_cfx);
if (ret) return ret;
ctx->state = INITIATOR_READY;
ctx->more_flags |= OPEN;
return GSS_S_COMPLETE;
}
/*
* handle delegated creds in init-sec-context
*/
@@ -168,7 +335,7 @@ static OM_uint32
init_auth
(OM_uint32 * minor_status,
gsskrb5_cred initiator_cred_handle,
gss_ctx_id_t * context_handle,
gsskrb5_ctx ctx,
krb5_const_principal name,
const gss_OID mech_type,
OM_uint32 req_flags,
@@ -184,7 +351,7 @@ init_auth
OM_uint32 ret = GSS_S_FAILURE;
krb5_error_code kret;
krb5_flags ap_options;
krb5_creds this_cred, *cred = NULL;
krb5_creds *cred = NULL;
krb5_data outbuf;
krb5_ccache ccache = NULL;
uint32_t flags;
@@ -193,52 +360,12 @@ init_auth
krb5_enctype enctype;
krb5_data fwd_data;
OM_uint32 lifetime_rec;
gsskrb5_ctx ctx;
krb5_data_zero(&outbuf);
krb5_data_zero(&fwd_data);
*minor_status = 0;
ctx = malloc(sizeof(*ctx));
if (ctx == NULL) {
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
ctx->auth_context = NULL;
ctx->source = NULL;
ctx->target = NULL;
ctx->flags = 0;
ctx->more_flags = 0;
ctx->ticket = NULL;
ctx->lifetime = GSS_C_INDEFINITE;
ctx->order = NULL;
HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex);
kret = krb5_auth_con_init (_gsskrb5_context,
&ctx->auth_context);
if (kret) {
_gsskrb5_set_error_string ();
*minor_status = kret;
ret = GSS_S_FAILURE;
goto failure;
}
kret = set_addresses (ctx->auth_context,
input_chan_bindings);
if (kret) {
*minor_status = kret;
ret = GSS_S_BAD_BINDINGS;
goto failure;
}
krb5_auth_con_addflags(_gsskrb5_context,
ctx->auth_context,
KRB5_AUTH_CONTEXT_DO_SEQUENCE |
KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED,
NULL);
if (actual_mech_type)
*actual_mech_type = GSS_KRB5_MECHANISM;
@@ -276,30 +403,15 @@ init_auth
goto failure;
memset(&this_cred, 0, sizeof(this_cred));
this_cred.client = ctx->source;
this_cred.server = ctx->target;
if (time_req && time_req != GSS_C_INDEFINITE) {
krb5_timestamp ts;
krb5_timeofday (_gsskrb5_context, &ts);
this_cred.times.endtime = ts + time_req;
} else
this_cred.times.endtime = 0;
this_cred.session.keytype = KEYTYPE_NULL;
kret = krb5_get_credentials (_gsskrb5_context,
0,
ret = gsskrb5_get_creds(minor_status,
ccache,
&this_cred,
ctx,
ctx->target,
time_req,
time_rec,
&cred);
if (kret) {
_gsskrb5_set_error_string ();
*minor_status = kret;
ret = GSS_S_FAILURE;
if (ret)
goto failure;
}
ctx->lifetime = cred->times.endtime;
@@ -364,6 +476,16 @@ init_auth
flags |= GSS_C_SEQUENCE_FLAG;
if (req_flags & GSS_C_ANON_FLAG)
; /* XXX */
if (req_flags & GSS_C_DCE_STYLE) {
/* GSS_C_DCE_STYLE implies GSS_C_MUTUAL_FLAG */
flags |= GSS_C_DCE_STYLE | GSS_C_MUTUAL_FLAG;
ap_options |= AP_OPTS_MUTUAL_REQUIRED;
}
if (req_flags & GSS_C_IDENTIFY_FLAG)
flags |= GSS_C_IDENTIFY_FLAG;
if (req_flags & GSS_C_EXTENDED_ERROR_FLAG)
flags |= GSS_C_EXTENDED_ERROR_FLAG;
flags |= GSS_C_CONF_FLAG;
flags |= GSS_C_INTEG_FLAG;
flags |= GSS_C_TRANS_FLAG;
@@ -426,60 +548,25 @@ init_auth
krb5_cc_close(_gsskrb5_context, ccache);
if (flags & GSS_C_MUTUAL_FLAG) {
*context_handle = (gss_ctx_id_t)ctx;
ctx->state = INITIATOR_WAIT_FOR_MUTAL;
return GSS_S_CONTINUE_NEEDED;
} else {
int32_t seq_number;
int is_cfx = 0;
krb5_auth_getremoteseqnumber (_gsskrb5_context,
ctx->auth_context,
&seq_number);
_gsskrb5i_is_cfx(ctx, &is_cfx);
ret = _gssapi_msg_order_create(minor_status,
&ctx->order,
_gssapi_msg_order_f(flags),
seq_number, 0, is_cfx);
if (ret)
goto failure;
if (time_rec)
*time_rec = lifetime_rec;
ctx->more_flags |= OPEN;
*context_handle = (gss_ctx_id_t)ctx;
return GSS_S_COMPLETE;
}
return gsskrb5_initiator_ready(minor_status, ctx);
failure:
krb5_auth_con_free (_gsskrb5_context,
ctx->auth_context);
krb5_data_free (&outbuf);
if(cred)
krb5_free_creds(_gsskrb5_context, cred);
if (ccache && initiator_cred_handle == NULL)
krb5_cc_close(_gsskrb5_context, ccache);
if(ctx->source)
krb5_free_principal (_gsskrb5_context,
ctx->source);
if(ctx->target)
krb5_free_principal (_gsskrb5_context,
ctx->target);
if(ctx->order)
_gssapi_msg_order_destroy(&ctx->order);
HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex);
free(ctx);
*context_handle = GSS_C_NO_CONTEXT;
return ret;
}
static OM_uint32
repl_mutual
(OM_uint32 * minor_status,
const gsskrb5_cred initiator_cred_handle,
gss_ctx_id_t * context_handle,
gsskrb5_ctx ctx,
const gss_OID mech_type,
OM_uint32 req_flags,
OM_uint32 time_req,
@@ -497,20 +584,16 @@ repl_mutual
krb5_data indata;
krb5_ap_rep_enc_part *repl;
int is_cfx = 0;
gsskrb5_ctx ctx = (gsskrb5_ctx) *context_handle;
output_token->length = 0;
output_token->value = NULL;
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
if (actual_mech_type)
*actual_mech_type = GSS_KRB5_MECHANISM;
ret = _gsskrb5_decapsulate (minor_status, input_token, &indata,
"\x02\x00", GSS_KRB5_MECHANISM);
if (ret) {
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
/* XXX - Handle AP_ERROR */
return ret;
}
@@ -520,7 +603,6 @@ repl_mutual
&indata,
&repl);
if (kret) {
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
_gsskrb5_set_error_string ();
*minor_status = kret;
return GSS_S_FAILURE;
@@ -539,12 +621,24 @@ repl_mutual
_gssapi_msg_order_f(ctx->flags),
seq_number, 0, is_cfx);
if (ret) {
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
return ret;
}
ctx->more_flags |= OPEN;
if (is_cfx) {
krb5_keyblock *key = NULL;
kret = krb5_auth_con_getremotesubkey(_gsskrb5_context,
ctx->auth_context,
&key);
if (kret == 0 && key != NULL) {
ctx->more_flags |= ACCEPTOR_SUBKEY;
krb5_free_keyblock (_gsskrb5_context, key);
}
}
*minor_status = 0;
if (time_rec) {
ret = _gsskrb5_lifetime_left(minor_status,
@@ -555,7 +649,6 @@ repl_mutual
}
if (ret_flags)
*ret_flags = ctx->flags;
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
return ret;
}
@@ -582,12 +675,19 @@ OM_uint32 _gsskrb5_init_sec_context
{
gsskrb5_cred cred = (gsskrb5_cred)initiator_cred_handle;
krb5_const_principal name = (krb5_const_principal)target_name;
gsskrb5_ctx ctx;
OM_uint32 ret;
GSSAPI_KRB5_INIT ();
output_token->length = 0;
output_token->value = NULL;
if (context_handle == NULL) {
*minor_status = 0;
return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE;
}
if (ret_flags)
*ret_flags = 0;
if (time_rec)
@@ -604,11 +704,36 @@ OM_uint32 _gsskrb5_init_sec_context
!gss_oid_equal(mech_type, GSS_KRB5_MECHANISM))
return GSS_S_BAD_MECH;
if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) {
OM_uint32 ret;
if (input_token == GSS_C_NO_BUFFER || input_token->length == 0)
return init_auth (minor_status,
cred,
if (*context_handle != GSS_C_NO_CONTEXT) {
*minor_status = 0;
return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE;
}
ret = _gsskrb5_create_ctx(minor_status,
context_handle,
input_chan_bindings,
INITIATOR_START);
if (ret)
return ret;
}
if (*context_handle == GSS_C_NO_CONTEXT) {
*minor_status = 0;
return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE;
}
ctx = (gsskrb5_ctx) *context_handle;
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
switch (ctx->state) {
case INITIATOR_START:
ret = init_auth(minor_status,
cred,
ctx,
name,
mech_type,
req_flags,
@@ -619,10 +744,10 @@ OM_uint32 _gsskrb5_init_sec_context
output_token,
ret_flags,
time_rec);
else
return repl_mutual(minor_status,
cred,
context_handle,
break;
case INITIATOR_WAIT_FOR_MUTAL:
ret = repl_mutual(minor_status,
ctx,
mech_type,
req_flags,
time_req,
@@ -632,4 +757,24 @@ OM_uint32 _gsskrb5_init_sec_context
output_token,
ret_flags,
time_rec);
break;
case INITIATOR_READY:
*minor_status = 0;
ret = GSS_S_BAD_STATUS;
break;
default:
*minor_status = 0;
ret = GSS_S_BAD_STATUS;
break;
}
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
/* destroy context in case of error */
if (GSS_ERROR(ret)) {
OM_uint32 min2;
_gsskrb5_delete_sec_context(&min2, context_handle, GSS_C_NO_BUFFER);
}
return ret;
}