void *server_thread(void *pvt) { const char **argv; struct athread *data; char buffer[MAX_RPC_SIZE]; uint32_t buflen; gss_buffer_desc in_token = GSS_C_EMPTY_BUFFER; uint32_t ret_maj; uint32_t ret_min; struct gssx_ctx *context_handle = NULL; struct gssx_cred *cred_handle = NULL; struct gssx_name *src_name = NULL; gss_buffer_desc out_token = GSS_C_EMPTY_BUFFER; struct gssx_cred *deleg_cred = NULL; gss_OID_set mech_set = GSS_C_NO_OID_SET; gss_OID_set mech_names = GSS_C_NO_OID_SET; gss_OID_set mech_types = GSS_C_NO_OID_SET; gss_OID_set mech_attrs = GSS_C_NO_OID_SET; gss_OID_set known_mech_attrs = GSS_C_NO_OID_SET; gss_buffer_desc sasl_mech_name = GSS_C_EMPTY_BUFFER; gss_buffer_desc mech_name = GSS_C_EMPTY_BUFFER; gss_buffer_desc mech_description = GSS_C_EMPTY_BUFFER; gss_buffer_desc name = GSS_C_EMPTY_BUFFER; gss_buffer_desc short_desc = GSS_C_EMPTY_BUFFER; gss_buffer_desc long_desc = GSS_C_EMPTY_BUFFER; gss_OID_set mechs = GSS_C_NO_OID_SET; gss_buffer_desc target_buf; struct gssx_name *target_name = NULL; struct gssx_name *canon_name = NULL; gss_buffer_desc out_name_buf = GSS_C_EMPTY_BUFFER; gss_OID out_name_type = GSS_C_NO_OID; gss_buffer_desc msg_token = GSS_C_EMPTY_BUFFER; int ret; gss_buffer_desc input_message_buffer = GSS_C_EMPTY_BUFFER; gss_buffer_desc output_message_buffer = GSS_C_EMPTY_BUFFER; gss_qop_t qop_state; int conf_state; data = (struct athread *)pvt; argv = data->argv; target_buf.value = (void *)data->target; target_buf.length = strlen(data->target) + 1; /* import name family functions tests */ ret_maj = gpm_import_name(&ret_min, &target_buf, GSS_C_NT_HOSTBASED_SERVICE, &target_name); if (ret_maj) { DEBUG("gssproxy returned an error: %d\n", ret_maj); gp_log_failure(GSS_C_NO_OID, ret_maj, ret_min); goto done; } ret_maj = gpm_canonicalize_name(&ret_min, target_name, discard_const(gss_mech_krb5), &canon_name); if (ret_maj) { DEBUG("gssproxy returned an error: %d\n", ret_maj); gp_log_failure(GSS_C_NO_OID, ret_maj, ret_min); goto done; } ret_maj = gpm_display_name(&ret_min, canon_name, &out_name_buf, &out_name_type); if (ret_maj) { DEBUG("gssproxy returned an error: %d\n", ret_maj); gp_log_failure(GSS_C_NO_OID, ret_maj, ret_min); goto done; } DEBUG("Acquiring for: %s\n", (char *)out_name_buf.value); /* indicate mechs family functions tests */ ret_maj = gpm_indicate_mechs(&ret_min, &mech_set); if (ret_maj) { DEBUG("gssproxy returned an error: %d\n", ret_maj); gp_log_failure(GSS_C_NO_OID, ret_maj, ret_min); goto done; } ret_maj = gpm_inquire_names_for_mech(&ret_min, &mech_set->elements[0], &mech_names); if (ret_maj) { DEBUG("gssproxy returned an error: %d\n", ret_maj); gp_log_failure(&mech_set->elements[0], ret_maj, ret_min); goto done; } ret_maj = gpm_inquire_attrs_for_mech(&ret_min, &mech_set->elements[0], &mech_attrs, &known_mech_attrs); if (ret_maj) { DEBUG("gssproxy returned an error: %d\n", ret_maj); gp_log_failure(&mech_set->elements[0], ret_maj, ret_min); goto done; } ret_maj = gpm_inquire_saslname_for_mech(&ret_min, &mech_set->elements[0], &sasl_mech_name, &mech_name, &mech_description); if (ret_maj) { DEBUG("gssproxy returned an error: %d\n", ret_maj); gp_log_failure(&mech_set->elements[0], ret_maj, ret_min); goto done; } ret_maj = gpm_display_mech_attr(&ret_min, &mech_attrs->elements[0], &name, &short_desc, &long_desc); if (ret_maj) { DEBUG("gssproxy returned an error: %d\n", ret_maj); gp_log_failure(GSS_C_NO_OID, ret_maj, ret_min); goto done; } ret_maj = gpm_indicate_mechs_by_attrs(&ret_min, GSS_C_NO_OID_SET, GSS_C_NO_OID_SET, GSS_C_NO_OID_SET, &mechs); if (ret_maj) { DEBUG("gssproxy returned an error: %d\n", ret_maj); gp_log_failure(GSS_C_NO_OID, ret_maj, ret_min); goto done; } ret_maj = gpm_inquire_mechs_for_name(&ret_min, target_name, &mech_types); if (ret_maj) { DEBUG("gssproxy returned an error: %d\n", ret_maj); gp_log_failure(GSS_C_NO_OID, ret_maj, ret_min); goto done; } ret_maj = gpm_acquire_cred(&ret_min, NULL, NULL, GSS_C_INDEFINITE, mech_set, GSS_C_ACCEPT, false, &cred_handle, NULL, NULL); if (ret_maj) { DEBUG("gssproxy returned an error: %d\n", ret_maj); gp_log_failure(GSS_C_NO_OID, ret_maj, ret_min); goto done; } ret = t_recv_buffer(data->srv_pipe[0], buffer, &buflen); if (ret) { DEBUG("Failed to get data from client!\n"); goto done; } in_token.value = buffer; in_token.length = buflen; ret_maj = gpm_accept_sec_context(&ret_min, &context_handle, cred_handle, &in_token, GSS_C_NO_CHANNEL_BINDINGS, &src_name, NULL, &out_token, NULL, NULL, &deleg_cred); if (ret_maj) { DEBUG("gssproxy returned an error: %d\n", ret_maj); gp_log_failure(GSS_C_NO_OID, ret_maj, ret_min); goto done; } if (out_token.length) { ret = t_send_buffer(data->cli_pipe[1], out_token.value, out_token.length); if (ret) { DEBUG("Failed to send data to client!\n"); goto done; } } /* receive message from client */ ret = t_recv_buffer(data->srv_pipe[0], buffer, &buflen); if (ret) { DEBUG("Failed to get data from client!\n"); goto done; } in_token.value = buffer; in_token.length = buflen; /* receive signature from client */ ret = t_recv_buffer(data->srv_pipe[0], &buffer[in_token.length], &buflen); if (ret) { DEBUG("Failed to get data from client!\n"); goto done; } msg_token.value = &buffer[in_token.length]; msg_token.length = buflen; ret_maj = gpm_verify_mic(&ret_min, context_handle, &in_token, &msg_token, NULL); if (ret_maj) { DEBUG("gpm_verify_mic failed: %d\n", ret_maj); gp_log_failure(GSS_C_NO_OID, ret_maj, ret_min); goto done; } DEBUG("Received valid msg from client: [%s]\n", buffer); ret = t_recv_buffer(data->srv_pipe[0], buffer, &buflen); if (ret) { DEBUG("Failed to get data from client!\n"); goto done; } input_message_buffer.value = buffer; input_message_buffer.length = buflen; ret_maj = gpm_unwrap(&ret_min, context_handle, &input_message_buffer, &output_message_buffer, &conf_state, &qop_state); if (ret_maj) { DEBUG("gpm_unwrap failed: %d\n", ret_maj); gp_log_failure(GSS_C_NO_OID, ret_maj, ret_min); goto done; } DEBUG("Received valid msg from client: [%s]\n", (char *)output_message_buffer.value); done: gpm_release_name(&ret_min, &src_name); gpm_release_buffer(&ret_min, &out_token); gpm_release_buffer(&ret_min, &output_message_buffer); gpm_release_cred(&ret_min, &deleg_cred); gpm_delete_sec_context(&ret_min, &context_handle, GSS_C_NO_BUFFER); gss_release_oid_set(&ret_min, &mech_set); gss_release_oid_set(&ret_min, &mech_names); gss_release_oid_set(&ret_min, &mech_types); gss_release_oid_set(&ret_min, &mech_attrs); gss_release_oid_set(&ret_min, &known_mech_attrs); gss_release_buffer(&ret_min, &sasl_mech_name); gss_release_buffer(&ret_min, &mech_name); gss_release_buffer(&ret_min, &mech_description); gss_release_buffer(&ret_min, &name); gss_release_buffer(&ret_min, &short_desc); gss_release_buffer(&ret_min, &long_desc); gss_release_oid_set(&ret_min, &mechs); gpm_release_name(&ret_min, &target_name); gpm_release_name(&ret_min, &canon_name); gss_release_buffer(&ret_min, &out_name_buf); gss_release_oid(&ret_min, &out_name_type); close(data->srv_pipe[0]); close(data->cli_pipe[1]); pthread_exit(NULL); }
uint32_t gp_export_gssx_cred(uint32_t *min, struct gp_call_ctx *gpcall, gss_cred_id_t *in, gssx_cred *out) { uint32_t ret_maj; uint32_t ret_min; gss_name_t name = NULL; uint32_t lifetime; gss_cred_usage_t cred_usage; gss_OID_set mechanisms = NULL; uint32_t initiator_lifetime; uint32_t acceptor_lifetime; struct gssx_cred_element *el; int ret; int i, j; struct gp_creds_handle *handle = NULL; gss_buffer_desc token = GSS_C_EMPTY_BUFFER; ret_maj = gss_inquire_cred(&ret_min, *in, &name, &lifetime, &cred_usage, &mechanisms); if (ret_maj) { goto done; } ret_maj = gp_conv_name_to_gssx(&ret_min, name, &out->desired_name); if (ret_maj) { goto done; } gss_release_name(&ret_min, &name); name = NULL; out->elements.elements_len = mechanisms->count; out->elements.elements_val = calloc(out->elements.elements_len, sizeof(gssx_cred_element)); if (!out->elements.elements_val) { ret_maj = GSS_S_FAILURE; ret_min = ENOMEM; goto done; } for (i = 0, j = 0; i < mechanisms->count; i++, j++) { el = &out->elements.elements_val[j]; ret_maj = gss_inquire_cred_by_mech(&ret_min, *in, &mechanisms->elements[i], &name, &initiator_lifetime, &acceptor_lifetime, &cred_usage); if (ret_maj) { gp_log_failure(&mechanisms->elements[i], ret_maj, ret_min); /* temporarily skip any offender */ out->elements.elements_len--; j--; continue; #if 0 ret = EINVAL; goto done; #endif } ret_maj = gp_conv_name_to_gssx(&ret_min, name, &el->MN); if (ret_maj) { goto done; } gss_release_name(&ret_min, &name); name = NULL; ret = gp_conv_oid_to_gssx(&mechanisms->elements[i], &el->mech); if (ret) { ret_maj = GSS_S_FAILURE; ret_min = ret; goto done; } el->cred_usage = gp_conv_gssx_to_cred_usage(cred_usage); el->initiator_time_rec = initiator_lifetime; el->acceptor_time_rec = acceptor_lifetime; } handle = gp_service_get_creds_handle(gpcall->service); if (!handle) { ret_maj = GSS_S_FAILURE; ret_min = EINVAL; goto done; } ret_maj = gss_export_cred(&ret_min, *in, &token); if (ret_maj) { goto done; } ret = gp_encrypt_buffer(handle->context, &handle->key, token.length, token.value, &out->cred_handle_reference); if (ret) { ret_maj = GSS_S_FAILURE; ret_min = ret; goto done; } out->needs_release = false; /* now we have serialized creds in the hands of the client. * we can safey free them here so that we can remain sateless and * not leak memory */ gss_release_cred(&ret_min, in); ret_maj = GSS_S_COMPLETE; ret_min = 0; done: *min = ret_min; gss_release_name(&ret_min, &name); gss_release_oid_set(&ret_min, &mechanisms); return ret_maj; }
void *client_thread(void *pvt) { const char **argv; struct athread *data; uint32_t ret_maj; uint32_t ret_min; char buffer[MAX_RPC_SIZE]; uint32_t buflen; gss_buffer_desc target_buf; gss_buffer_desc in_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc out_token = GSS_C_EMPTY_BUFFER; struct gssx_name *name = NULL; struct gssx_ctx *ctx = NULL; struct gssx_cred *cred_handle = NULL; int ret = 0; gss_buffer_desc msg_buf = GSS_C_EMPTY_BUFFER; int conf_state; uint32_t max_size; data = (struct athread *)pvt; argv = data->argv; target_buf.value = (void *)data->target; target_buf.length = strlen(data->target) + 1; ret_maj = gpm_import_name(&ret_min, &target_buf, GSS_C_NT_HOSTBASED_SERVICE, &name); if (ret_maj) { goto done; } do { ret_maj = gpm_init_sec_context(&ret_min, cred_handle, &ctx, name, GSS_C_NO_OID, GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG, 0, GSS_C_NO_CHANNEL_BINDINGS, &in_token, NULL, &out_token, NULL, NULL); if (ret_maj != GSS_S_COMPLETE && ret_maj != GSS_S_CONTINUE_NEEDED) { DEBUG("gss_init_sec_context() failed with: %d\n", ret_maj); goto done; } if (out_token.length != 0) { /* send to server */ ret = t_send_buffer(data->srv_pipe[1], out_token.value, out_token.length); if (ret) { goto done; } gss_release_buffer(&ret_min, &out_token); } if (!ctx) { goto done; } if (ret_maj == GSS_S_CONTINUE_NEEDED) { /* and wait for reply */ ret = t_recv_buffer(data->cli_pipe[0], buffer, &buflen); if (ret) { goto done; } in_token.value = buffer; in_token.length = buflen; } } while (ret_maj == GSS_S_CONTINUE_NEEDED); memcpy(buffer, CLI_MSG, sizeof(CLI_MSG)); msg_buf.value = (void *)buffer; msg_buf.length = sizeof(CLI_MSG); ret_maj = gpm_get_mic(&ret_min, ctx, GSS_C_QOP_DEFAULT, &msg_buf, &out_token); if (ret_maj) { DEBUG("gpm_get_mic failed: %d\n", ret_maj); gp_log_failure(GSS_C_NO_OID, ret_maj, ret_min); goto done; } /* send msg to server */ ret = t_send_buffer(data->srv_pipe[1], msg_buf.value, msg_buf.length); if (ret) { goto done; } /* send signature to server */ ret = t_send_buffer(data->srv_pipe[1], out_token.value, out_token.length); if (ret) { goto done; } gss_release_buffer(&ret_min, &out_token); in_token.value = discard_const(CLI_MSG); in_token.length = strlen(in_token.value) + 1; ret_maj = gpm_wrap(&ret_min, ctx, 1, /* conf_req_flag */ GSS_C_QOP_DEFAULT, /* qop_req */ &in_token, &conf_state, &out_token); if (ret_maj) { DEBUG("gpm_wrap failed: %d\n", ret_maj); gp_log_failure(GSS_C_NO_OID, ret_maj, ret_min); goto done; } /* send to server */ ret = t_send_buffer(data->srv_pipe[1], out_token.value, out_token.length); if (ret) { goto done; } ret_maj = gpm_wrap_size_limit(&ret_min, ctx, 1, /* conf_req */ GSS_C_QOP_DEFAULT, /* qop_req */ 4096, /* size_req */ &max_size); if (ret_maj) { DEBUG("gpm_wrap_size_limit failed: %d\n", ret_maj); gp_log_failure(GSS_C_NO_OID, ret_maj, ret_min); goto done; } DEBUG("client: Success!\n"); done: gpm_release_name(&ret_min, &name); gss_release_buffer(&ret_min, &out_token); close(data->cli_pipe[0]); close(data->srv_pipe[1]); pthread_exit(NULL); }