+static int write_authenticate_message(struct discover_server *server,
+ struct client *client)
+{
+ struct pb_protocol_message *message;
+ struct auth_message auth_msg;
+ int len;
+
+ auth_msg.op = AUTH_MSG_RESPONSE;
+ auth_msg.authenticated = client->can_modify;
+
+ len = pb_protocol_authenticate_len(&auth_msg);
+
+ message = pb_protocol_create_message(client,
+ PB_PROTOCOL_ACTION_AUTHENTICATE, len);
+ if (!message)
+ return -1;
+
+ pb_protocol_serialise_authenticate(&auth_msg, message->payload, len);
+
+ return client_write_message(server, client, message);
+}
+
+static int client_auth_timeout(void *arg)
+{
+ struct client *client = arg;
+ int rc;
+
+ client->auth_waiter = NULL;
+ client->can_modify = false;
+
+ rc = write_authenticate_message(client->server, client);
+ if (rc)
+ pb_log("failed to send client auth timeout\n");
+
+ return 0;
+}
+
+static int discover_server_handle_auth_message(struct client *client,
+ struct auth_message *auth_msg)
+{
+ struct status *status;
+ char *hash;
+ int rc = 0;
+
+ status = talloc_zero(client, struct status);
+
+ switch (auth_msg->op) {
+ case AUTH_MSG_REQUEST:
+ if (!crypt_check_password(auth_msg->password)) {
+ rc = -1;
+ pb_log("Client failed to authenticate\n");
+ status->type = STATUS_ERROR;
+ status->message = talloc_asprintf(status,
+ _("Password incorrect"));
+ } else {
+ client->can_modify = true;
+ rc = write_authenticate_message(client->server,
+ client);
+ if (client->auth_waiter)
+ waiter_remove(client->auth_waiter);
+ client->auth_waiter = waiter_register_timeout(
+ client->server->waitset,
+ 300000, /* 5 min */
+ client_auth_timeout, client);
+ pb_log("Client authenticated\n");
+ status->type = STATUS_INFO;
+ status->message = talloc_asprintf(status,
+ _("Authenticated successfully"));
+ }
+ break;
+ case AUTH_MSG_SET:
+ if (client->server->restrict_clients) {
+ if (!crypt_check_password(auth_msg->set_password.password)) {
+ rc = -1;
+ pb_log("Wrong password for set request\n");
+ status->type = STATUS_ERROR;
+ status->message = talloc_asprintf(status,
+ _("Password incorrect"));
+ break;
+ }
+ }
+
+ rc = crypt_set_password(auth_msg,
+ auth_msg->set_password.new_password);
+ if (rc) {
+ pb_log("Failed to set password\n");
+ status->type = STATUS_ERROR;
+ status->message = talloc_asprintf(status,
+ _("Error setting password"));
+ } else {
+ if (!auth_msg->set_password.new_password ||
+ !strlen(auth_msg->set_password.new_password)) {
+ platform_set_password("");
+ discover_server_set_auth_mode(client->server,
+ false);
+ pb_log("Password cleared\n");
+ } else {
+ hash = crypt_get_hash(auth_msg);
+ platform_set_password(hash);
+ talloc_free(hash);
+ discover_server_set_auth_mode(client->server,
+ true);
+ }
+ pb_log("System password changed\n");
+ status->type = STATUS_ERROR;
+ status->message = talloc_asprintf(status,
+ _("Password updated successfully"));
+ }
+ break;
+ case AUTH_MSG_DECRYPT:
+ if (!client->can_modify) {
+ pb_log("Unauthenticated client tried to open encrypted device %s\n",
+ auth_msg->decrypt_dev.device_id);
+ rc = -1;
+ status->type = STATUS_ERROR;
+ status->message = talloc_asprintf(status,
+ _("Must authenticate before opening encrypted device"));
+ break;
+ }
+
+ device_handler_open_encrypted_dev(client->server->device_handler,
+ auth_msg->decrypt_dev.password,
+ auth_msg->decrypt_dev.device_id);
+ break;
+ default:
+ pb_log("%s: unknown op\n", __func__);
+ rc = -1;
+ break;
+ }
+
+ if (status->message)
+ write_boot_status_message(client->server, client, status);
+ talloc_free(status);
+
+ return rc;
+}
+