OM_uint32 _gss_ntlm_acquire_cred(OM_uint32 * min_stat, const gss_name_t desired_name, OM_uint32 time_req, const gss_OID_set desired_mechs, gss_cred_usage_t cred_usage, gss_cred_id_t * output_cred_handle, gss_OID_set * actual_mechs, OM_uint32 * time_rec) { ntlm_name name = (ntlm_name) desired_name; OM_uint32 maj_stat, junk; ntlm_ctx ctx; *min_stat = 0; *output_cred_handle = GSS_C_NO_CREDENTIAL; if (actual_mechs) *actual_mechs = GSS_C_NO_OID_SET; if (time_rec) *time_rec = GSS_C_INDEFINITE; if (desired_name == NULL) return GSS_S_NO_CRED; if (cred_usage == GSS_C_BOTH || cred_usage == GSS_C_ACCEPT) { gss_ctx_id_t gctx; maj_stat = _gss_ntlm_allocate_ctx(min_stat, name->domain, &ctx); if (maj_stat != GSS_S_COMPLETE) return maj_stat; gctx = (gss_ctx_id_t)ctx; _gss_ntlm_delete_sec_context(&junk, &gctx, NULL); } if (cred_usage == GSS_C_BOTH || cred_usage == GSS_C_INITIATE) { ntlm_cred cred; /* if we have a anon name, lets dup it directly */ if ((name->flags & NTLM_ANON_NAME) != 0) { maj_stat = _gss_ntlm_duplicate_name(min_stat, (gss_name_t)name, (gss_name_t *)&cred); if (maj_stat) return maj_stat; } else { maj_stat = _gss_ntlm_have_cred(min_stat, name, &cred); if (maj_stat) return maj_stat; } *output_cred_handle = (gss_cred_id_t)cred; } return (GSS_S_COMPLETE); }
OM_uint32 GSSAPI_CALLCONV _gss_ntlm_acquire_cred(OM_uint32 *min_stat, gss_const_name_t desired_name, OM_uint32 time_req, const gss_OID_set desired_mechs, gss_cred_usage_t cred_usage, gss_cred_id_t *output_cred_handle, gss_OID_set *actual_mechs, OM_uint32 *time_rec) { ntlm_name name = (ntlm_name) desired_name; const char *domain = NULL; OM_uint32 maj_stat; ntlm_ctx ctx; *min_stat = 0; *output_cred_handle = GSS_C_NO_CREDENTIAL; if (actual_mechs) *actual_mechs = GSS_C_NO_OID_SET; if (time_rec) *time_rec = GSS_C_INDEFINITE; if (cred_usage == GSS_C_BOTH || cred_usage == GSS_C_ACCEPT) { maj_stat = _gss_ntlm_allocate_ctx(min_stat, &ctx); if (maj_stat != GSS_S_COMPLETE) return maj_stat; domain = name != NULL ? name->domain : NULL; maj_stat = (*ctx->server->nsi_probe)(min_stat, ctx->ictx, domain); { gss_ctx_id_t context = (gss_ctx_id_t)ctx; OM_uint32 junk; _gss_ntlm_delete_sec_context(&junk, &context, NULL); } if (maj_stat) return maj_stat; } if (cred_usage == GSS_C_BOTH || cred_usage == GSS_C_INITIATE) { ntlm_cred cred; *min_stat = _gss_ntlm_get_user_cred(name, &cred); if (*min_stat) return GSS_S_NO_CRED; cred->usage = cred_usage; *output_cred_handle = (gss_cred_id_t)cred; } return (GSS_S_COMPLETE); }
OM_uint32 GSSAPI_CALLCONV _gss_ntlm_accept_sec_context (OM_uint32 * minor_status, gss_ctx_id_t * context_handle, const gss_cred_id_t acceptor_cred_handle, const gss_buffer_t input_token_buffer, const gss_channel_bindings_t input_chan_bindings, gss_name_t * src_name, gss_OID * mech_type, gss_buffer_t output_token, OM_uint32 * ret_flags, OM_uint32 * time_rec, gss_cred_id_t * delegated_cred_handle ) { krb5_error_code ret; struct ntlm_buf data; OM_uint32 junk; ntlm_ctx ctx; output_token->value = NULL; output_token->length = 0; *minor_status = 0; if (context_handle == NULL) return GSS_S_FAILURE; if (input_token_buffer == GSS_C_NO_BUFFER) return GSS_S_FAILURE; if (src_name) *src_name = GSS_C_NO_NAME; if (mech_type) *mech_type = GSS_C_NO_OID; if (ret_flags) *ret_flags = 0; if (time_rec) *time_rec = 0; if (delegated_cred_handle) *delegated_cred_handle = GSS_C_NO_CREDENTIAL; if (*context_handle == GSS_C_NO_CONTEXT) { struct ntlm_type1 type1; OM_uint32 major_status; OM_uint32 retflags; struct ntlm_buf out; major_status = _gss_ntlm_allocate_ctx(minor_status, &ctx); if (major_status) return major_status; *context_handle = (gss_ctx_id_t)ctx; /* check if the mechs is allowed by remote service */ major_status = (*ctx->server->nsi_probe)(minor_status, ctx->ictx, NULL); if (major_status) { _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL); return major_status; } data.data = input_token_buffer->value; data.length = input_token_buffer->length; ret = heim_ntlm_decode_type1(&data, &type1); if (ret) { _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL); *minor_status = ret; return GSS_S_FAILURE; } if ((type1.flags & NTLM_NEG_UNICODE) == 0) { heim_ntlm_free_type1(&type1); _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL); *minor_status = EINVAL; return GSS_S_FAILURE; } if (type1.flags & NTLM_NEG_SIGN) ctx->gssflags |= GSS_C_CONF_FLAG; if (type1.flags & NTLM_NEG_SIGN) ctx->gssflags |= GSS_C_INTEG_FLAG; major_status = (*ctx->server->nsi_type2)(minor_status, ctx->ictx, type1.flags, type1.hostname, type1.domain, &retflags, &out); heim_ntlm_free_type1(&type1); if (major_status != GSS_S_COMPLETE) { OM_uint32 junk; _gss_ntlm_delete_sec_context(&junk, context_handle, NULL); return major_status; } output_token->value = malloc(out.length); if (output_token->value == NULL && out.length != 0) { OM_uint32 junk; _gss_ntlm_delete_sec_context(&junk, context_handle, NULL); *minor_status = ENOMEM; return GSS_S_FAILURE; } memcpy(output_token->value, out.data, out.length); output_token->length = out.length; ctx->flags = retflags; return GSS_S_CONTINUE_NEEDED; } else { OM_uint32 maj_stat; struct ntlm_type3 type3; struct ntlm_buf session; ctx = (ntlm_ctx)*context_handle; data.data = input_token_buffer->value; data.length = input_token_buffer->length; ret = heim_ntlm_decode_type3(&data, 1, &type3); if (ret) { _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL); *minor_status = ret; return GSS_S_FAILURE; } maj_stat = (*ctx->server->nsi_type3)(minor_status, ctx->ictx, &type3, &session); if (maj_stat) { heim_ntlm_free_type3(&type3); _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL); return maj_stat; } if (src_name) { ntlm_name n = calloc(1, sizeof(*n)); if (n) { n->user = strdup(type3.username); n->domain = strdup(type3.targetname); } if (n == NULL || n->user == NULL || n->domain == NULL) { gss_name_t tempn = (gss_name_t)n; _gss_ntlm_release_name(&junk, &tempn); heim_ntlm_free_type3(&type3); _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL); return maj_stat; } *src_name = (gss_name_t)n; } heim_ntlm_free_type3(&type3); ret = krb5_data_copy(&ctx->sessionkey, session.data, session.length); if (ret) { if (src_name) _gss_ntlm_release_name(&junk, src_name); _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL); *minor_status = ret; return GSS_S_FAILURE; } if (session.length != 0) { ctx->status |= STATUS_SESSIONKEY; if (ctx->flags & NTLM_NEG_NTLM2_SESSION) { _gss_ntlm_set_key(&ctx->u.v2.send, 1, (ctx->flags & NTLM_NEG_KEYEX), ctx->sessionkey.data, ctx->sessionkey.length); _gss_ntlm_set_key(&ctx->u.v2.recv, 0, (ctx->flags & NTLM_NEG_KEYEX), ctx->sessionkey.data, ctx->sessionkey.length); } else { RC4_set_key(&ctx->u.v1.crypto_send.key, ctx->sessionkey.length, ctx->sessionkey.data); RC4_set_key(&ctx->u.v1.crypto_recv.key, ctx->sessionkey.length, ctx->sessionkey.data); } } if (mech_type) *mech_type = GSS_NTLM_MECHANISM; if (time_rec) *time_rec = GSS_C_INDEFINITE; ctx->status |= STATUS_OPEN; if (ret_flags) *ret_flags = ctx->gssflags; return GSS_S_COMPLETE; } }