コード例 #1
0
/**
 * 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;
}
コード例 #2
0
/**
 * 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;
}
コード例 #3
0
/**
 * 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;
}
コード例 #4
0
/**
 * 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;
}
コード例 #5
0
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);
}