static int test_parse(void) { const char *user = "******", *domain = "mydomain", *password = "******", *target = "DOMAIN"; struct ntlm_type1 type1; struct ntlm_type2 type2; struct ntlm_type3 type3; struct ntlm_buf data; int ret, flags; memset(&type1, 0, sizeof(type1)); type1.flags = NTLM_NEG_UNICODE|NTLM_NEG_TARGET|NTLM_NEG_NTLM; type1.domain = rk_UNCONST(domain); type1.hostname = NULL; type1.os[0] = 0; type1.os[1] = 0; ret = heim_ntlm_encode_type1(&type1, &data); if (ret) errx(1, "heim_ntlm_encode_type1"); memset(&type1, 0, sizeof(type1)); ret = heim_ntlm_decode_type1(&data, &type1); free(data.data); if (ret) errx(1, "heim_ntlm_encode_type1"); heim_ntlm_free_type1(&type1); /* * */ memset(&type2, 0, sizeof(type2)); flags = NTLM_NEG_UNICODE | NTLM_NEG_NTLM | NTLM_TARGET_DOMAIN; type2.flags = flags; memset(type2.challenge, 0x7f, sizeof(type2.challenge)); type2.targetname = rk_UNCONST(target); type2.targetinfo.data = NULL; type2.targetinfo.length = 0; ret = heim_ntlm_encode_type2(&type2, &data); if (ret) errx(1, "heim_ntlm_encode_type2"); memset(&type2, 0, sizeof(type2)); ret = heim_ntlm_decode_type2(&data, &type2); free(data.data); if (ret) errx(1, "heim_ntlm_decode_type2"); heim_ntlm_free_type2(&type2); /* * */ memset(&type3, 0, sizeof(type3)); type3.flags = flags; type3.username = rk_UNCONST(user); type3.targetname = rk_UNCONST(target); type3.ws = rk_UNCONST("workstation"); { struct ntlm_buf key; heim_ntlm_nt_key(password, &key); heim_ntlm_calculate_ntlm1(key.data, key.length, type2.challenge, &type3.ntlm); free(key.data); } ret = heim_ntlm_encode_type3(&type3, &data); if (ret) errx(1, "heim_ntlm_encode_type3"); free(type3.ntlm.data); memset(&type3, 0, sizeof(type3)); ret = heim_ntlm_decode_type3(&data, 1, &type3); free(data.data); if (ret) errx(1, "heim_ntlm_decode_type3"); if (strcmp("workstation", type3.ws) != 0) errx(1, "type3 ws wrong"); if (strcmp(target, type3.targetname) != 0) errx(1, "type3 targetname wrong"); if (strcmp(user, type3.username) != 0) errx(1, "type3 username wrong"); heim_ntlm_free_type3(&type3); /* * NTLMv2 */ memset(&type2, 0, sizeof(type2)); flags = NTLM_NEG_UNICODE | NTLM_NEG_NTLM | NTLM_TARGET_DOMAIN; type2.flags = flags; memset(type2.challenge, 0x7f, sizeof(type2.challenge)); type2.targetname = rk_UNCONST(target); type2.targetinfo.data = "\x00\x00"; type2.targetinfo.length = 2; ret = heim_ntlm_encode_type2(&type2, &data); if (ret) errx(1, "heim_ntlm_encode_type2"); memset(&type2, 0, sizeof(type2)); ret = heim_ntlm_decode_type2(&data, &type2); free(data.data); if (ret) errx(1, "heim_ntlm_decode_type2"); heim_ntlm_free_type2(&type2); return 0; }
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; } }