diff --git a/lib/gssapi/gssapi/gssapi_krb5.h b/lib/gssapi/gssapi/gssapi_krb5.h index a84f43cdb..bab719019 100644 --- a/lib/gssapi/gssapi/gssapi_krb5.h +++ b/lib/gssapi/gssapi/gssapi_krb5.h @@ -66,6 +66,8 @@ extern GSSAPI_LIB_VARIABLE gss_OID GSS_KRB5_SET_DNS_CANONICALIZE_X; extern GSSAPI_LIB_VARIABLE gss_OID GSS_KRB5_SEND_TO_KDC_X; extern GSSAPI_LIB_VARIABLE gss_OID GSS_KRB5_SET_DEFAULT_REALM_X; extern GSSAPI_LIB_VARIABLE gss_OID GSS_KRB5_CCACHE_NAME_X; +extern GSSAPI_LIB_VARIABLE gss_OID GSS_KRB5_SET_TIME_OFFSET_X; +extern GSSAPI_LIB_VARIABLE gss_OID GSS_KRB5_GET_TIME_OFFSET_X; /* Extensions inquire context */ extern GSSAPI_LIB_VARIABLE gss_OID GSS_KRB5_GET_TKT_FLAGS_X; extern GSSAPI_LIB_VARIABLE gss_OID GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X; @@ -157,6 +159,12 @@ gsskrb5_get_subkey(OM_uint32 *minor_status, gss_ctx_id_t context_handle, struct EncryptionKey **out); +OM_uint32 GSSAPI_LIB_FUNCTION +gsskrb5_set_time_offset(int); + +OM_uint32 GSSAPI_LIB_FUNCTION +gsskrb5_get_time_offset(int *); + /* * Lucid - NFSv4 interface to GSS-API KRB5 to expose key material to * do GSS content token handling in-kernel. diff --git a/lib/gssapi/krb5/accept_sec_context.c b/lib/gssapi/krb5/accept_sec_context.c index e90964852..4080fc7d1 100644 --- a/lib/gssapi/krb5/accept_sec_context.c +++ b/lib/gssapi/krb5/accept_sec_context.c @@ -250,6 +250,65 @@ gsskrb5_acceptor_ready(OM_uint32 * minor_status, return GSS_S_COMPLETE; } +static OM_uint32 +send_error_token(OM_uint32 *minor_status, + krb5_context context, + krb5_error_code kret, + krb5_principal server, + krb5_data *indata, + gss_buffer_t output_token) +{ + krb5_principal ap_req_server = NULL; + krb5_error_code ret; + krb5_data outbuf; + + /* build server from request if the acceptor had not selected one */ + if (server == NULL) { + AP_REQ ap_req; + + ret = krb5_decode_ap_req(context, indata, &ap_req); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + ret = _krb5_principalname2krb5_principal(context, + &ap_req_server, + ap_req.ticket.sname, + ap_req.ticket.realm); + free_AP_REQ(&ap_req); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + server = ap_req_server; + } + + ret = krb5_mk_error(context, kret, NULL, NULL, NULL, + server, NULL, NULL, &outbuf); + if (ap_req_server) + krb5_free_principal(context, ap_req_server); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = _gsskrb5_encapsulate(minor_status, + &outbuf, + output_token, + "\x03\x00", + GSS_KRB5_MECHANISM); + krb5_data_free (&outbuf); + if (ret) + return ret; + + if (kret == KRB5KRB_AP_ERR_SKEW) + return GSS_S_CONTINUE_NEEDED; + + *minor_status = kret; + return GSS_S_FAILURE; +} + + static OM_uint32 gsskrb5_acceptor_start(OM_uint32 * minor_status, gsskrb5_ctx ctx, @@ -304,6 +363,10 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status, { krb5_rd_req_in_ctx in = NULL; krb5_rd_req_out_ctx out = NULL; + krb5_principal server = NULL; + + if (acceptor_cred) + server = acceptor_cred->principal; kret = krb5_rd_req_in_ctx_alloc(context, &in); if (kret == 0) @@ -319,17 +382,22 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status, kret = krb5_rd_req_ctx(context, &ctx->auth_context, &indata, - (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) ? NULL : acceptor_cred->principal, + server, in, &out); krb5_rd_req_in_ctx_free(context, in); if (kret) { - ret = GSS_S_FAILURE; - *minor_status = kret; - return ret; + /* No reply in not-MUTUAL mode */ + if (0 && !(ctx->flags & GSS_C_MUTUAL_FLAG)) { + ret = GSS_S_FAILURE; + *minor_status = kret; + return ret; + } + return send_error_token(minor_status, context, kret, + server, &indata, output_token); } /* - * We need to remember some data on the context_handle. + * we need to remember some data on the context_handle. */ kret = krb5_rd_req_out_get_ap_req_options(context, out, &ap_options); diff --git a/lib/gssapi/krb5/delete_sec_context.c b/lib/gssapi/krb5/delete_sec_context.c index 3f9158746..ec680d737 100644 --- a/lib/gssapi/krb5/delete_sec_context.c +++ b/lib/gssapi/krb5/delete_sec_context.c @@ -61,6 +61,8 @@ _gsskrb5_delete_sec_context(OM_uint32 * minor_status, HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); krb5_auth_con_free (context, ctx->auth_context); + if (ctx->kcred) + krb5_free_creds(context, ctx->kcred); if(ctx->source) krb5_free_principal (context, ctx->source); if(ctx->target) diff --git a/lib/gssapi/krb5/external.c b/lib/gssapi/krb5/external.c index 9442b5167..87e4aa01d 100644 --- a/lib/gssapi/krb5/external.c +++ b/lib/gssapi/krb5/external.c @@ -396,6 +396,20 @@ static gss_OID_desc gss_krb5_ccache_name_x_desc = gss_OID GSSAPI_LIB_VARIABLE GSS_KRB5_CCACHE_NAME_X = &gss_krb5_ccache_name_x_desc; +/* 1.2.752.43.13.17 */ +static gss_OID_desc gss_krb5_set_time_offset_x_desc = + {6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x11")}; + +gss_OID GSSAPI_LIB_VARIABLE GSS_KRB5_SET_TIME_OFFSET_X = + &gss_krb5_set_time_offset_x_desc; + +/* 1.2.752.43.13.18 */ +static gss_OID_desc gss_krb5_get_time_offset_x_desc = + {6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x12")}; + +gss_OID GSSAPI_LIB_VARIABLE GSS_KRB5_GET_TIME_OFFSET_X = + &gss_krb5_get_time_offset_x_desc; + /* 1.2.752.43.14.1 */ static gss_OID_desc gss_sasl_digest_md5_mechanism_desc = {6, rk_UNCONST("\x2a\x85\x70\x2b\x0e\x01") }; diff --git a/lib/gssapi/krb5/gsskrb5_locl.h b/lib/gssapi/krb5/gsskrb5_locl.h index 42ed253cd..4025d14d2 100644 --- a/lib/gssapi/krb5/gsskrb5_locl.h +++ b/lib/gssapi/krb5/gsskrb5_locl.h @@ -62,11 +62,14 @@ typedef struct { enum { LOCAL = 1, OPEN = 2, COMPAT_OLD_DES3 = 4, COMPAT_OLD_DES3_SELECTED = 8, - ACCEPTOR_SUBKEY = 16 + ACCEPTOR_SUBKEY = 16, + RETRIED = 32, + CLOSE_CCACHE = 64 } more_flags; enum gss_ctx_id_t_state { /* initiator states */ INITIATOR_START, + INITIATOR_RESTART, INITIATOR_WAIT_FOR_MUTAL, INITIATOR_READY, /* acceptor states */ @@ -74,6 +77,8 @@ typedef struct { ACCEPTOR_WAIT_FOR_DCESTYLE, ACCEPTOR_READY } state; + krb5_creds *kcred; + krb5_ccache ccache; struct krb5_ticket *ticket; OM_uint32 lifetime; HEIMDAL_MUTEX ctx_id_mutex; diff --git a/lib/gssapi/krb5/init_sec_context.c b/lib/gssapi/krb5/init_sec_context.c index 3e6a02421..637a24e69 100644 --- a/lib/gssapi/krb5/init_sec_context.c +++ b/lib/gssapi/krb5/init_sec_context.c @@ -121,6 +121,8 @@ _gsskrb5_create_ctx( ctx->auth_context = NULL; ctx->source = NULL; ctx->target = NULL; + ctx->kcred = NULL; + ctx->ccache = NULL; ctx->state = state; ctx->flags = 0; ctx->more_flags = 0; @@ -134,9 +136,7 @@ _gsskrb5_create_ctx( kret = krb5_auth_con_init (context, &ctx->auth_context); if (kret) { *minor_status = kret; - HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); - return GSS_S_FAILURE; } @@ -232,27 +232,32 @@ gsskrb5_initiator_ready( gsskrb5_ctx ctx, krb5_context context) { - OM_uint32 ret; - int32_t seq_number; - int is_cfx = 0; - OM_uint32 flags = ctx->flags; + OM_uint32 ret; + int32_t seq_number; + int is_cfx = 0; + OM_uint32 flags = ctx->flags; + + krb5_free_creds(context, ctx->kcred); + ctx->kcred = NULL; - krb5_auth_getremoteseqnumber (context, - ctx->auth_context, - &seq_number); + if (ctx->more_flags & CLOSE_CCACHE) + krb5_cc_close(context, ctx->ccache); + ctx->ccache = NULL; - _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; + krb5_auth_getremoteseqnumber (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; } /* @@ -333,7 +338,6 @@ init_auth const gss_OID mech_type, OM_uint32 req_flags, OM_uint32 time_req, - const gss_channel_bindings_t input_chan_bindings, const gss_buffer_t input_token, gss_OID * actual_mech_type, gss_buffer_t output_token, @@ -343,14 +347,7 @@ init_auth { OM_uint32 ret = GSS_S_FAILURE; krb5_error_code kret; - krb5_flags ap_options; - krb5_creds *kcred = NULL; krb5_data outbuf; - krb5_ccache ccache = NULL; - uint32_t flags; - krb5_data authenticator; - Checksum cksum; - krb5_enctype enctype; krb5_data fwd_data; OM_uint32 lifetime_rec; @@ -363,16 +360,17 @@ init_auth *actual_mech_type = GSS_KRB5_MECHANISM; if (cred == NULL) { - kret = krb5_cc_default (context, &ccache); + kret = krb5_cc_default (context, &ctx->ccache); if (kret) { *minor_status = kret; ret = GSS_S_FAILURE; goto failure; } + ctx->more_flags |= CLOSE_CCACHE; } else - ccache = cred->ccache; + ctx->ccache = cred->ccache; - kret = krb5_cc_get_principal (context, ccache, &ctx->source); + kret = krb5_cc_get_principal (context, ctx->ccache, &ctx->source); if (kret) { *minor_status = kret; ret = GSS_S_FAILURE; @@ -407,16 +405,16 @@ init_auth ret = gsskrb5_get_creds(minor_status, context, - ccache, + ctx->ccache, ctx, ctx->target, time_req, time_rec, - &kcred); + &ctx->kcred); if (ret) goto failure; - ctx->lifetime = kcred->times.endtime; + ctx->lifetime = ctx->kcred->times.endtime; ret = _gsskrb5_lifetime_left(minor_status, context, @@ -434,17 +432,59 @@ init_auth krb5_auth_con_setkey(context, ctx->auth_context, - &kcred->session); + &ctx->kcred->session); kret = krb5_auth_con_generatelocalsubkey(context, ctx->auth_context, - &kcred->session); + &ctx->kcred->session); if(kret) { *minor_status = kret; ret = GSS_S_FAILURE; goto failure; } - + + return GSS_S_COMPLETE; + +failure: + if (ctx->ccache && (ctx->more_flags & CLOSE_CCACHE)) + krb5_cc_close(context, ctx->ccache); + ctx->ccache = NULL; + + return ret; + +} + +static OM_uint32 +init_auth_restart +(OM_uint32 * minor_status, + gsskrb5_cred cred, + gsskrb5_ctx ctx, + krb5_context context, + OM_uint32 req_flags, + const gss_channel_bindings_t input_chan_bindings, + const gss_buffer_t input_token, + gss_OID * actual_mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec + ) +{ + OM_uint32 ret = GSS_S_FAILURE; + krb5_error_code kret; + krb5_flags ap_options; + krb5_data outbuf; + uint32_t flags; + krb5_data authenticator; + Checksum cksum; + krb5_enctype enctype; + krb5_data fwd_data, timedata; + int32_t offset = 0, oldoffset; + + krb5_data_zero(&outbuf); + krb5_data_zero(&fwd_data); + + *minor_status = 0; + /* * If the credential doesn't have ok-as-delegate, check what local * policy say about ok-as-delegate, default is FALSE that makes @@ -452,13 +492,14 @@ init_auth * requested. If it is TRUE, strip of the GSS_C_DELEG_FLAG if the * KDC doesn't set ok-as-delegate. */ - if (!kcred->flags.b.ok_as_delegate) { + if (!ctx->kcred->flags.b.ok_as_delegate) { krb5_boolean delegate, realm_setting; krb5_data data; realm_setting = FALSE; - ret = krb5_cc_get_config(context, ccache, "realm-config", &data); + ret = krb5_cc_get_config(context, ctx->ccache, NULL, + "realm-config", &data); if (ret == 0) { /* XXX 1 is use ok-as-delegate */ if (data.length > 0 && (((unsigned char *)data.data)[0]) & 1) @@ -466,7 +507,7 @@ init_auth krb5_data_free(&data); } - krb5_appdefault_boolean(context, "gssapi", name->realm, + krb5_appdefault_boolean(context, "gssapi", ctx->target->realm, "ok-as-delegate", realm_setting, &delegate); if (delegate) @@ -478,7 +519,8 @@ init_auth if (req_flags & GSS_C_DELEG_FLAG) do_delegation (context, ctx->auth_context, - ccache, kcred, name, &fwd_data, &flags); + ctx->ccache, ctx->kcred, ctx->target, + &fwd_data, &flags); if (req_flags & GSS_C_MUTUAL_FLAG) { flags |= GSS_C_MUTUAL_FLAG; @@ -529,16 +571,33 @@ init_auth enctype = ctx->auth_context->keyblock->keytype; + ret = krb5_cc_get_config(context, ctx->ccache, ctx->target, + "time-offset", &timedata); + if (ret == 0) { + if (timedata.length == 4) { + const u_char *p = timedata.data; + offset = (p[0] <<24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0); + } + krb5_data_free(&timedata); + } + + if (offset) { + krb5_get_kdc_sec_offset (context, &oldoffset, NULL); + krb5_set_kdc_sec_offset (context, offset, -1); + } + kret = krb5_build_authenticator (context, ctx->auth_context, enctype, - kcred, + ctx->kcred, &cksum, NULL, &authenticator, KRB5_KU_AP_REQ_AUTH); if (kret) { + if (offset) + krb5_set_kdc_sec_offset (context, oldoffset, -1); *minor_status = kret; ret = GSS_S_FAILURE; goto failure; @@ -546,11 +605,12 @@ init_auth kret = krb5_build_ap_req (context, enctype, - kcred, + ctx->kcred, ap_options, authenticator, &outbuf); - + if (offset) + krb5_set_kdc_sec_offset (context, oldoffset, -1); if (kret) { *minor_status = kret; ret = GSS_S_FAILURE; @@ -568,10 +628,7 @@ init_auth goto failure; } - krb5_free_creds(context, kcred); free_Checksum(&cksum); - if (cred == NULL) - krb5_cc_close(context, ccache); if (flags & GSS_C_MUTUAL_FLAG) { ctx->state = INITIATOR_WAIT_FOR_MUTAL; @@ -580,15 +637,14 @@ init_auth return gsskrb5_initiator_ready(minor_status, ctx, context); failure: - if(kcred) - krb5_free_creds(context, kcred); - if (ccache && cred == NULL) - krb5_cc_close(context, ccache); + if (ctx->ccache && (ctx->more_flags & CLOSE_CCACHE)) + krb5_cc_close(context, ctx->ccache); + ctx->ccache = NULL; return ret; - } + static OM_uint32 repl_mutual (OM_uint32 * minor_status, @@ -627,8 +683,46 @@ repl_mutual &indata, "\x02\x00", GSS_KRB5_MECHANISM); - if (ret) { - /* XXX - Handle AP_ERROR */ + if (ret == GSS_S_DEFECTIVE_TOKEN) { + /* check if there is an error token sent instead */ + ret = _gsskrb5_decapsulate (minor_status, + input_token, + &indata, + "\x03\x00", + GSS_KRB5_MECHANISM); + if (ret == GSS_S_COMPLETE) { + KRB_ERROR error; + + kret = krb5_rd_error(context, &indata, &error); + if (kret == 0) { + kret = krb5_error_from_rd_error(context, &error, NULL); + + /* save the time skrew for this host */ + if (kret == KRB5KRB_AP_ERR_SKEW) { + krb5_data timedata; + unsigned char p[4]; + int32_t t = error.stime - time(NULL); + + p[0] = (t >> 24) & 0xFF; + p[1] = (t >> 16) & 0xFF; + p[2] = (t >> 8) & 0xFF; + p[3] = (t >> 0) & 0xFF; + + timedata.data = p; + timedata.length = sizeof(p); + + krb5_cc_set_config(context, ctx->ccache, ctx->target, + "time-offset", &timedata); + + if ((ctx->more_flags & RETRIED) == 0) + ctx->state = INITIATOR_RESTART; + ctx->more_flags |= RETRIED; + } + free_KRB_ERROR (&error); + } + *minor_status = kret; + return GSS_S_FAILURE; + } return ret; } } @@ -779,6 +873,7 @@ OM_uint32 _gsskrb5_init_sec_context HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + again: switch (ctx->state) { case INITIATOR_START: ret = init_auth(minor_status, @@ -789,12 +884,24 @@ OM_uint32 _gsskrb5_init_sec_context mech_type, req_flags, time_req, - input_chan_bindings, input_token, actual_mech_type, output_token, ret_flags, time_rec); + /* FALL THOUGH */ + case INITIATOR_RESTART: + ret = init_auth_restart(minor_status, + cred, + ctx, + context, + req_flags, + input_chan_bindings, + input_token, + actual_mech_type, + output_token, + ret_flags, + time_rec); break; case INITIATOR_WAIT_FOR_MUTAL: ret = repl_mutual(minor_status, @@ -809,6 +916,8 @@ OM_uint32 _gsskrb5_init_sec_context output_token, ret_flags, time_rec); + if (ctx->state == INITIATOR_RESTART) + goto again; break; case INITIATOR_READY: /* diff --git a/lib/gssapi/krb5/set_sec_context_option.c b/lib/gssapi/krb5/set_sec_context_option.c index 569e75efc..f28d2397b 100644 --- a/lib/gssapi/krb5/set_sec_context_option.c +++ b/lib/gssapi/krb5/set_sec_context_option.c @@ -70,6 +70,36 @@ get_string(OM_uint32 *minor_status, return GSS_S_COMPLETE; } +static OM_uint32 +get_int32(OM_uint32 *minor_status, + const gss_buffer_t value, + OM_uint32 *ret) +{ + *minor_status = 0; + if (value == NULL || value->length == 0) + *ret = 0; + else if (value->length == sizeof(*ret)) + memcpy(ret, value->value, sizeof(*ret)); + else + return GSS_S_UNAVAILABLE; + + return GSS_S_COMPLETE; +} + +static OM_uint32 +set_int32(OM_uint32 *minor_status, + const gss_buffer_t value, + OM_uint32 set) +{ + *minor_status = 0; + if (value->length == sizeof(set)) + memcpy(value->value, &set, sizeof(set)); + else + return GSS_S_UNAVAILABLE; + + return GSS_S_COMPLETE; +} + OM_uint32 _gsskrb5_set_sec_context_option (OM_uint32 *minor_status, @@ -185,6 +215,35 @@ _gsskrb5_set_sec_context_option return GSS_S_FAILURE; return GSS_S_COMPLETE; + } else if (gss_oid_equal(desired_object, GSS_KRB5_SET_TIME_OFFSET_X)) { + OM_uint32 offset; + time_t t; + + maj_stat = get_int32(minor_status, value, &offset); + if (maj_stat != GSS_S_COMPLETE) + return maj_stat; + + t = time(NULL) + offset; + + krb5_set_real_time(context, t, 0); + + *minor_status = 0; + return GSS_S_COMPLETE; + } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_TIME_OFFSET_X)) { + krb5_timestamp sec; + int32_t usec; + time_t t; + + t = time(NULL); + + krb5_us_timeofday (context, &sec, &usec); + + maj_stat = set_int32(minor_status, value, sec - t); + if (maj_stat != GSS_S_COMPLETE) + return maj_stat; + + *minor_status = 0; + return GSS_S_COMPLETE; } *minor_status = EINVAL; diff --git a/lib/gssapi/mech/gss_krb5.c b/lib/gssapi/mech/gss_krb5.c index 020b7a3bf..d30d5ce57 100644 --- a/lib/gssapi/mech/gss_krb5.c +++ b/lib/gssapi/mech/gss_krb5.c @@ -870,3 +870,53 @@ gss_krb5_get_tkt_flags(OM_uint32 *minor_status, return GSS_S_COMPLETE; } +OM_uint32 GSSAPI_LIB_FUNCTION +gsskrb5_set_time_offset(int offset) +{ + struct _gss_mech_switch *m; + gss_buffer_desc buffer; + OM_uint32 junk; + int32_t o = offset; + + _gss_load_mech(); + + buffer.value = &o; + buffer.length = sizeof(o); + + SLIST_FOREACH(m, &_gss_mechs, gm_link) { + if (m->gm_mech.gm_set_sec_context_option == NULL) + continue; + m->gm_mech.gm_set_sec_context_option(&junk, NULL, + GSS_KRB5_SET_TIME_OFFSET_X, &buffer); + } + + return (GSS_S_COMPLETE); +} + +OM_uint32 GSSAPI_LIB_FUNCTION +gsskrb5_get_time_offset(int *offset) +{ + struct _gss_mech_switch *m; + gss_buffer_desc buffer; + OM_uint32 maj_stat, junk; + int32_t o; + + _gss_load_mech(); + + buffer.value = &o; + buffer.length = sizeof(o); + + SLIST_FOREACH(m, &_gss_mechs, gm_link) { + if (m->gm_mech.gm_set_sec_context_option == NULL) + continue; + maj_stat = m->gm_mech.gm_set_sec_context_option(&junk, NULL, + GSS_KRB5_GET_TIME_OFFSET_X, &buffer); + + if (maj_stat == GSS_S_COMPLETE) { + *offset = o; + return maj_stat; + } + } + + return (GSS_S_UNAVAILABLE); +} diff --git a/lib/gssapi/test_context.c b/lib/gssapi/test_context.c index aea4d5a02..f8ad52c83 100644 --- a/lib/gssapi/test_context.c +++ b/lib/gssapi/test_context.c @@ -50,6 +50,8 @@ static int deleg_flag = 0; static int server_no_deleg_flag = 0; static char *gsskrb5_acceptor_identity = NULL; static char *session_enctype_string = NULL; +static int client_time_offset = 0; +static int server_time_offset = 0; static int version_flag = 0; static int verbose_flag = 0; static int help_flag = 0; @@ -127,6 +129,8 @@ loop(gss_OID mechoid, while (!server_done || !client_done) { + gsskrb5_set_time_offset(client_time_offset); + maj_stat = gss_init_sec_context(&min_stat, init_cred, cctx, @@ -148,12 +152,16 @@ loop(gss_OID mechoid, else client_done = 1; + gsskrb5_get_time_offset(&client_time_offset); + if (client_done && server_done) break; if (input_token.length != 0) gss_release_buffer(&min_stat, &input_token); + gsskrb5_set_time_offset(server_time_offset); + maj_stat = gss_accept_sec_context(&min_stat, sctx, GSS_C_NO_CREDENTIAL, @@ -169,8 +177,7 @@ loop(gss_OID mechoid, errx(1, "accept_sec_context: %s", gssapi_err(maj_stat, min_stat, actual_mech_server)); - if (verbose_flag) - printf("%.*s", (int)input_token.length, (char *)input_token.value); + gsskrb5_get_time_offset(&server_time_offset); if (output_token.length != 0) gss_release_buffer(&min_stat, &output_token); @@ -198,6 +205,11 @@ loop(gss_OID mechoid, if (gss_oid_equal(actual_mech_server, actual_mech_client) == 0) errx(1, "mech mismatch"); *actual_mech = actual_mech_server; + + if (verbose_flag) { + printf("server time offset: %d\n", server_time_offset); + printf("client time offset: %d\n", client_time_offset); + } } static void @@ -270,6 +282,8 @@ static struct getargs args[] = { "server should get a credential", NULL }, {"gsskrb5-acceptor-identity", 0, arg_string, &gsskrb5_acceptor_identity, "keytab", NULL }, {"session-enctype", 0, arg_string, &session_enctype_string, "enctype", NULL }, + {"client-time-offset", 0, arg_integer, &client_time_offset, "time", NULL }, + {"server-time-offset", 0, arg_integer, &server_time_offset, "time", NULL }, {"version", 0, arg_flag, &version_flag, "print version", NULL }, {"verbose", 'v', arg_flag, &verbose_flag, "verbose", NULL }, {"help", 0, arg_flag, &help_flag, NULL, NULL } diff --git a/lib/krb5/context.c b/lib/krb5/context.c index 8ce19c634..bf5d6411f 100644 --- a/lib/krb5/context.c +++ b/lib/krb5/context.c @@ -985,7 +985,7 @@ krb5_get_dns_canonicalize_hostname (krb5_context context) * @param sec seconds part of offset. * @param usec micro seconds part of offset. * - * @return return non zero if the library uses DNS to canonicalize hostnames. + * @return returns zero * * @ingroup krb5 */ @@ -1000,6 +1000,27 @@ krb5_get_kdc_sec_offset (krb5_context context, int32_t *sec, int32_t *usec) return 0; } +/** + * Set current offset in time to the KDC. + * + * @param context Kerberos 5 context. + * @param sec seconds part of offset. + * @param usec micro seconds part of offset. + * + * @return returns zero + * + * @ingroup krb5 + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_set_kdc_sec_offset (krb5_context context, int32_t sec, int32_t usec) +{ + context->kdc_sec_offset = sec; + if (usec >= 0) + context->kdc_usec_offset = usec; + return 0; +} + /** * Get max time skew allowed. * diff --git a/tests/gss/check-context.in b/tests/gss/check-context.in index 7ad22d3fd..14061043d 100644 --- a/tests/gss/check-context.in +++ b/tests/gss/check-context.in @@ -50,6 +50,7 @@ nokeytab="FILE:no-such-keytab" cache="FILE:krb5ccfile" kinit="${TESTS_ENVIRONMENT} ../../kuser/kinit -c $cache --no-afslog" +klist="${TESTS_ENVIRONMENT} ../../kuser/klist -c $cache" kadmin="${TESTS_ENVIRONMENT} ../../kadmin/kadmin -l -r $R" kdc="${TESTS_ENVIRONMENT} ../../kdc/kdc --addresses=localhost -P $port" @@ -266,6 +267,28 @@ ${context} \ --name-type=hostbased-service host@lucid.test.h5l.se || \ { exitcode=1 ; echo "test failed"; } +echo "Getting client initial ticket" +${kinit} --password-file=${objdir}/foopassword user1@${R} || exitcode=1 + +echo "No time offset" +${context} \ + --mech-type=krb5 \ + --name-type=hostbased-service host@lucid.test.h5l.se || \ + { exitcode=1 ; echo "test failed"; } + +echo "Server time offset" +../../libtool --mode=execute gdb --arg \ +${context} \ + --verbose \ + --mech-type=krb5 \ + --mutual-auth \ + --server-time-offset=3600 \ + --name-type=hostbased-service host@lucid.test.h5l.se || \ + { exitcode=1 ; echo "test failed"; } + +${klist} --hidden + + echo "killing kdc (${kdcpid})" kill ${kdcpid} 2> /dev/null