summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimo Sorce <simo@redhat.com>2013-12-15 20:19:04 -0500
committerSimo Sorce <simo@redhat.com>2013-12-15 21:10:20 -0500
commit23a45a4d4de4290ed9eb960881e8caf0a39a92f3 (patch)
tree2725d6f47039c81d72b499be670d9a0b8c2cbf0e
parentb0bd0602c661a0b52bf765180135093d546ed790 (diff)
downloadgss-ntlmssp-23a45a4d4de4290ed9eb960881e8caf0a39a92f3.tar.gz
gss-ntlmssp-23a45a4d4de4290ed9eb960881e8caf0a39a92f3.tar.xz
gss-ntlmssp-23a45a4d4de4290ed9eb960881e8caf0a39a92f3.zip
Implement import context function
-rw-r--r--src/gss_serialize.c314
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;
}