diff options
author | Simo Sorce <simo@redhat.com> | 2013-12-15 20:19:04 -0500 |
---|---|---|
committer | Simo Sorce <simo@redhat.com> | 2013-12-15 21:10:20 -0500 |
commit | 23a45a4d4de4290ed9eb960881e8caf0a39a92f3 (patch) | |
tree | 2725d6f47039c81d72b499be670d9a0b8c2cbf0e | |
parent | b0bd0602c661a0b52bf765180135093d546ed790 (diff) | |
download | gss-ntlmssp-23a45a4d4de4290ed9eb960881e8caf0a39a92f3.tar.gz gss-ntlmssp-23a45a4d4de4290ed9eb960881e8caf0a39a92f3.tar.xz gss-ntlmssp-23a45a4d4de4290ed9eb960881e8caf0a39a92f3.zip |
Implement import context function
-rw-r--r-- | src/gss_serialize.c | 314 |
1 files changed, 313 insertions, 1 deletions
diff --git a/src/gss_serialize.c b/src/gss_serialize.c index aadf6ad..369e0a4 100644 --- a/src/gss_serialize.c +++ b/src/gss_serialize.c @@ -398,9 +398,321 @@ done: } } +static uint32_t import_data_buffer(uint32_t *minor_status, + struct export_ctx_state *state, + uint8_t **dest, size_t *len, bool alloc, + struct relmem *rm, bool str) +{ + void *ptr; + + if (rm->ptr + rm->len > state->exp_len) { + return GSS_S_DEFECTIVE_TOKEN; + } + ptr = state->exp->data + rm->ptr; + if (alloc) { + if (str) { + *dest = (uint8_t *)strndup((const char *)ptr, rm->len); + } else { + *dest = malloc(rm->len); + if (*dest) { + memcpy(*dest, ptr, rm->len); + } + } + if (!*dest) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + } else { + if (!*len) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + if (rm->len > *len) { + return GSS_S_DEFECTIVE_TOKEN; + } + memcpy(*dest, ptr, rm->len); + } + if (len) *len = rm->len; + return GSS_S_COMPLETE; +} + +static uint32_t import_name(uint32_t *minor_status, + struct export_ctx_state *state, + struct export_name *name, + struct gssntlm_name *imp_name) +{ + uint8_t *dest; + uint32_t maj; + + switch (name->type) { + case EXP_NAME_NONE: + memset(imp_name, 0, sizeof(struct gssntlm_name)); + return GSS_S_COMPLETE; + + case EXP_NAME_ANON: + memset(imp_name, 0, sizeof(struct gssntlm_name)); + imp_name->type = GSSNTLM_NAME_ANON; + return GSS_S_COMPLETE; + + case EXP_NAME_USER: + imp_name->type = GSSNTLM_NAME_USER; + dest = NULL; + if (name->domain.len > 0) { + maj = import_data_buffer(minor_status, state, + &dest, NULL, true, + &name->domain, true); + if (maj != GSS_S_COMPLETE) return maj; + } + imp_name->data.user.domain = (char *)dest; + dest = NULL; + if (name->name.len > 0) { + maj = import_data_buffer(minor_status, state, + &dest, NULL, true, + &name->name, true); + if (maj != GSS_S_COMPLETE) return maj; + } + imp_name->data.user.name = (char *)dest; + return GSS_S_COMPLETE; + + case EXP_NAME_SERV: + imp_name->type = GSSNTLM_NAME_SERVER; + dest = NULL; + if (name->name.len > 0) { + maj = import_data_buffer(minor_status, state, + &dest, NULL, true, + &name->name, true); + if (maj != GSS_S_COMPLETE) return maj; + } + imp_name->data.server.name = (char *)dest; + return GSS_S_COMPLETE; + + default: + break; + } + + return GSS_S_DEFECTIVE_TOKEN; +} + +static uint32_t import_keys(uint32_t *minor_status, + struct export_ctx_state *state, + struct export_keys *keys, + struct gssntlm_signseal *imp_keys) +{ + struct ntlm_buffer in; + uint8_t *dest; + uint32_t maj; + int ret; + + if (keys->sign_key.len > 0) { + imp_keys->sign_key.length = 16; /* buf max size */ + dest = imp_keys->sign_key.data; + maj = import_data_buffer(minor_status, state, + &dest, &imp_keys->sign_key.length, + false, &keys->sign_key, false); + if (maj != GSS_S_COMPLETE) return maj; + } else { + memset(&imp_keys->sign_key, 0, sizeof(struct ntlm_key)); + } + + if (keys->seal_key.len > 0) { + imp_keys->seal_key.length = 16; /* buf max size */ + dest = imp_keys->seal_key.data; + maj = import_data_buffer(minor_status, state, + &dest, &imp_keys->seal_key.length, + false, &keys->seal_key, false); + if (maj != GSS_S_COMPLETE) return maj; + } else { + memset(&imp_keys->seal_key, 0, sizeof(struct ntlm_key)); + } + + if (keys->rc4_state.len > 0) { + maj = import_data_buffer(minor_status, state, + &in.data, &in.length, true, + &keys->rc4_state, false); + if (maj != GSS_S_COMPLETE) return maj; + ret = RC4_IMPORT(&imp_keys->seal_handle, &in); + safezero(in.data, in.length); + safefree(in.data); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + } else { + imp_keys->seal_handle = NULL; + } + + imp_keys->seq_num = le32toh(keys->seq_num); + + return GSS_S_COMPLETE; +} + uint32_t gssntlm_import_sec_context(uint32_t *minor_status, gss_buffer_t interprocess_token, gss_ctx_id_t *context_handle) { - return GSS_S_UNAVAILABLE; + struct gssntlm_ctx *ctx; + struct export_ctx_state state; + uint8_t *dest; + uint64_t time; + uint32_t maj; + + if (minor_status == NULL) { + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + *minor_status = 0; + + if (interprocess_token == NULL) { + return GSS_S_CALL_INACCESSIBLE_READ; + } + + if (interprocess_token->length < sizeof(struct export_ctx)) { + return GSS_S_DEFECTIVE_TOKEN; + } + + if (context_handle == NULL) { + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + + ctx = malloc(sizeof(struct gssntlm_ctx)); + if (!ctx) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + *minor_status = ntlm_init_ctx(&ctx->ntlm); + if (*minor_status) { + free(ctx); + return GSS_S_FAILURE; + } + + state.exp = (struct export_ctx *)interprocess_token->value; + state.exp_len = interprocess_token->length; + state.exp_ptr = 0; + + if (state.exp->version != le16toh(1)) { + maj = GSS_S_DEFECTIVE_TOKEN; + goto done; + } + + switch (state.exp->role) { + case EXP_CTX_CLIENT: + ctx->role = GSSNTLM_CLIENT; + break; + case EXP_CTX_SERVER: + ctx->role = GSSNTLM_SERVER; + break; + case EXP_CTX_DOMSRV: + ctx->role = GSSNTLM_DOMAIN_SERVER; + break; + case EXP_CTX_DOMCTR: + ctx->role = GSSNTLM_DOMAIN_CONTROLLER; + break; + default: + maj = GSS_S_DEFECTIVE_TOKEN; + goto done; + } + + switch (state.exp->stage) { + case EXP_STG_INIT: + ctx->stage = NTLMSSP_STAGE_INIT; + break; + case EXP_STG_NEGO: + ctx->stage = NTLMSSP_STAGE_NEGOTIATE; + break; + case EXP_STG_CHAL: + ctx->stage = NTLMSSP_STAGE_CHALLENGE; + break; + case EXP_STG_AUTH: + ctx->stage = NTLMSSP_STAGE_AUTHENTICATE; + break; + case EXP_STG_DONE: + ctx->stage = NTLMSSP_STAGE_DONE; + break; + default: + maj = GSS_S_DEFECTIVE_TOKEN; + goto done; + } + + dest = NULL; + if (state.exp->workstation.len > 0) { + maj = import_data_buffer(minor_status, &state, &dest, NULL, + true, &state.exp->workstation, true); + if (maj != GSS_S_COMPLETE) goto done; + } + ctx->workstation = (char *)dest; + + if (state.exp->nego_msg.len > 0) { + maj = import_data_buffer(minor_status, &state, + &ctx->nego_msg.data, &ctx->nego_msg.length, + true, &state.exp->nego_msg, false); + if (maj != GSS_S_COMPLETE) goto done; + } else { + ctx->nego_msg.data = NULL; + ctx->nego_msg.length = 0; + } + + if (state.exp->chal_msg.len > 0) { + maj = import_data_buffer(minor_status, &state, + &ctx->chal_msg.data, &ctx->chal_msg.length, + true, &state.exp->chal_msg, false); + if (maj != GSS_S_COMPLETE) goto done; + } else { + ctx->chal_msg.data = NULL; + ctx->chal_msg.length = 0; + } + + if (state.exp->auth_msg.len > 0) { + maj = import_data_buffer(minor_status, &state, + &ctx->auth_msg.data, &ctx->auth_msg.length, + true, &state.exp->auth_msg, false); + if (maj != GSS_S_COMPLETE) goto done; + } else { + ctx->auth_msg.data = NULL; + ctx->auth_msg.length = 0; + } + + maj = import_name(minor_status, &state, + &state.exp->source, &ctx->source_name); + if (maj != GSS_S_COMPLETE) goto done; + + maj = import_name(minor_status, &state, + &state.exp->target, &ctx->target_name); + if (maj != GSS_S_COMPLETE) goto done; + + memcpy(ctx->server_chal, state.exp->server_chal, 8); + + ctx->gss_flags = le32toh(state.exp->gss_flags); + ctx->neg_flags = le32toh(state.exp->neg_flags); + + if (state.exp->exported_session_key.len > 0) { + ctx->exported_session_key.length = 16; /* buf max size */ + dest = ctx->exported_session_key.data; + maj = import_data_buffer(minor_status, &state, &dest, + &ctx->exported_session_key.length, + false, &state.exp->workstation, true); + if (maj != GSS_S_COMPLETE) goto done; + } else { + memset(&ctx->exported_session_key, 0, sizeof(struct ntlm_key)); + } + + maj = import_keys(minor_status, &state, &state.exp->send, &ctx->send); + if (maj != GSS_S_COMPLETE) goto done; + + maj = import_keys(minor_status, &state, &state.exp->recv, &ctx->recv); + if (maj != GSS_S_COMPLETE) goto done; + + ctx->established = (state.exp->established == 1) ? true : false; + + time = le64toh(state.exp->expration_time); + ctx->expiration_time = time; + + maj = GSS_S_COMPLETE; + +done: + if (maj == GSS_S_COMPLETE) { + *context_handle = (gss_ctx_id_t)ctx; + } else { + uint32_t min; + gssntlm_delete_sec_context(&min, (gss_ctx_id_t *)&ctx, NULL); + } + return maj; } |