/** * EscalateModuleHandleFinish: * @self: PAM module that should return the result in @message. * @message: Message from the helper process containing its final result. * @error: (out)(allow-none): Error return location or #NULL. Unused for now, * but included to match the signature of EscalateModuleHandleConversation(). * * Returns: #TRUE always. */ static gboolean EscalateModuleHandleFinish(EscalateModule *self, EscalateMessage *message, GError **error) { if (!EscalateSubprocessShutdown(self->child, ESCALATE_MODULE_SHUTDOWN_TIMEOUT, error)) { return FALSE; } EscalateMessageGetValues(message, &self->result); self->keep_going = FALSE; return TRUE; }
/** * EscalateHelperPrompt: * @self: #EscalateHelper instance. * @conv_request: Conversation message to send. * @conv_response: Conversation response contents received. * * Returns: PAM_SUCCESS if one message was sent and response was read, or * PAM_CONV_ERROR on failure. Error are logged with pam_syslog. */ static int EscalateHelperPrompt(EscalateHelper *self, const struct pam_message *conv_request, struct pam_response *conv_response) { EscalateMessage *request = NULL; GError *error = NULL; EscalateMessage *response = NULL; gchar *response_msg = NULL; int response_retcode = 0; int result = PAM_CONV_ERR; request = EscalateMessageNew(ESCALATE_MESSAGE_TYPE_CONV_MESSAGE, conv_request->msg_style, conv_request->msg); if (!EscalateMessageWrite(request, self->writer, &error)) { pam_syslog(self->pamh, LOG_WARNING, "Failed to write conversation request: %s", error->message); g_clear_error(&error); goto done; } response = EscalateHelperRecv(self, ESCALATE_MESSAGE_TYPE_CONV_RESPONSE, &error); if (!response) { pam_syslog(self->pamh, LOG_WARNING, "Failed to read conversation response: %s", error->message); g_clear_error(&error); goto done; } EscalateMessageGetValues(response, &response_msg, &response_retcode); if (response_msg) { conv_response->resp = strdup(response_msg); } else { conv_response->resp = NULL; } conv_response->resp_retcode = response_retcode; result = PAM_SUCCESS; done: if (request) EscalateMessageUnref(request); if (response) EscalateMessageUnref(response); g_free(response_msg); return result; }
/** * EscalateModuleHandleConversation: * @self: PAM module to forward conversation messages to. * @message: Conversation message from the helper process holding the same * values as one "struct pam_message". * @error: (out)(allow-none): Error return location or #NULL. * * Returns: #TRUE if a response message was sent back to the helper process. */ static gboolean EscalateModuleHandleConversation(EscalateModule *self, EscalateMessage *message, GError **error) { gchar *conv_message_str = NULL; struct pam_message conv_message = { 0, NULL }; const struct pam_message *conv_message_array [] = { &conv_message, NULL }; struct pam_response *conv_response = NULL; gint pam_status = PAM_SYSTEM_ERR; EscalateMessage *response = NULL; gboolean result = FALSE; EscalateMessageGetValues(message, &conv_message.msg_style, &conv_message_str); conv_message.msg = conv_message_str; // TODO(vonhollen): Support multiple requests/responses per call. pam_status = self->conv->conv(1, conv_message_array, &conv_response, self->conv->appdata_ptr); if (pam_status != PAM_SUCCESS) { g_set_error(error, ESCALATE_MODULE_ERROR, ESCALATE_MODULE_ERROR_CONV, "Conversation function failed: %s", pam_strerror(self->pamh, pam_status)); goto done; } response = EscalateMessageNew(ESCALATE_MESSAGE_TYPE_CONV_RESPONSE, conv_response[0].resp, conv_response[0].resp_retcode); if (EscalateSubprocessSend(self->child, response, error)) result = TRUE; done: g_free(conv_message_str); if (conv_response) { free(conv_response[0].resp); free(conv_response); } if (response) { EscalateMessageUnref(response); } return result; }
/** * EscalateHelperHandleStart: * @self: #EscalateHelper instance. * @error: (out)(allow-none): Error return location or #NULL. * * Return: #TRUE if pam_start() was called and it's OK to call * EscalateHelperDoAction(). #FALSE if there was an error and the finish message * was sent. */ gboolean EscalateHelperHandleStart(EscalateHelper *self, GError **error) { EscalateMessage *message = NULL; EscalateMessage *response = NULL; GVariantIter *items = NULL; GVariantIter *env = NULL; int pam_status = PAM_SYSTEM_ERR; int item_type = -1; const gchar *item_value = NULL; gboolean result = FALSE; // Support EscalateHelperHandleStart() being called multiple times. self->action = ESCALATE_MESSAGE_ACTION_UNKNOWN; self->flags = 0; g_free(self->username); self->username = NULL; self->result = PAM_SYSTEM_ERR; message = EscalateHelperRecv(self, ESCALATE_MESSAGE_TYPE_START, error); if (!message) goto done; EscalateMessageGetValues(message, &self->action, &self->flags, &self->username, &items, &env); if (!EscalateHelperIsUserAllowed(self, error)) goto done; // TODO(vonhollen): Safely allow calls to multiple services. pam_status = pam_start(ESCALATE_SERVICE_NAME, self->username, &self->conv, &self->pamh); if (pam_status != PAM_SUCCESS) { g_set_error(error, ESCALATE_HELPER_ERROR, ESCALATE_HELPER_ERROR_START_FAILED, "Failed to start PAM session: %s", pam_strerror(self->pamh, pam_status)); goto done; } while (g_variant_iter_loop(items, "{im&s}", &item_type, &item_value)) { if (!EscalateHelperIsSafeItem(item_type)) { g_set_error(error, ESCALATE_HELPER_ERROR, ESCALATE_HELPER_ERROR_UNSUPPORTED_ITEM, "Item type %d is not supported", item_type); goto done; } pam_status = pam_set_item(self->pamh, item_type, item_value); if (pam_status != PAM_SUCCESS) { g_set_error(error, ESCALATE_HELPER_ERROR, ESCALATE_HELPER_ERROR_SET_ITEM_FAILED, "Failed to set item type %d to '%s'", item_type, item_value); goto done; } } result = EscalateUtilPamEnvFromVariant(self->pamh, env, error); done: if (!result) { response = EscalateMessageNew(ESCALATE_MESSAGE_TYPE_FINISH, PAM_SYSTEM_ERR, NULL); EscalateMessageWrite(response, self->writer, NULL); EscalateMessageUnref(response); } if (items) g_variant_iter_free(items); if (env) g_variant_iter_free(env); if (message) EscalateMessageUnref(message); return result; }
static void TestGetValues(gconstpointer user_data) { guint index = GPOINTER_TO_UINT(user_data); EscalateMessage *message = NULL; gint action = 0; gint flags = 0; gchar *username = NULL; gchar *value = NULL; gint item_key = 0; gchar *item_value = NULL; GVariantIter *items_iter = NULL; gchar *env_key = NULL; gchar *env_value = NULL; GVariantIter *env_iter = NULL; message = EscalateMessageLoad(example_messages[index], NULL); g_assert(message); switch (index) { case 0: EscalateMessageGetValues(message, &action, &flags, &username, &items_iter, &env_iter); g_assert_cmpint(1, ==, action); g_assert_cmpint(0, ==, flags); g_assert_cmpstr("testuser", ==, username); g_assert(g_variant_iter_next(items_iter, "{ims}", &item_key, &item_value)); g_assert_cmpint(2, ==, item_key); g_assert_cmpstr("testuser", ==, item_value); g_assert(!g_variant_iter_next(items_iter, "{ims}", NULL, NULL)); g_variant_iter_free(items_iter); g_assert(g_variant_iter_next(env_iter, "{ss}", &env_key, &env_value)); g_assert_cmpstr("PATH", ==, env_key); g_assert_cmpstr("/path", ==, env_value); g_assert(!g_variant_iter_next(env_iter, "{ss}", NULL, NULL)); g_variant_iter_free(env_iter); break; case 1: EscalateMessageGetValues(message, &flags, &value); g_assert_cmpint(1, ==, flags); g_assert_cmpstr("Password: "******"testpass", ==, value); g_assert_cmpint(0, ==, flags); break; case 3: EscalateMessageGetValues(message, &flags, &env_iter); g_assert_cmpint(0, ==, flags); g_assert(g_variant_iter_next(env_iter, "{ss}", &env_key, &env_value)); g_assert_cmpstr("PATH", ==, env_key); g_assert_cmpstr("/path", ==, env_value); g_assert(!g_variant_iter_next(env_iter, "{ss}", NULL, NULL)); g_variant_iter_free(env_iter); break; default: g_error("No message available for index %d", index); } g_free(username); g_free(value); g_free(item_value); g_free(env_key); g_free(env_value); EscalateMessageUnref(message); }