mirror of
https://git.proxmox.com/git/fwupd
synced 2025-08-06 04:57:59 +00:00
Allow running fwsignd as the non-root user
...however, most users will still want to use the root user so that the owner and group are set correctly on the destination files.
This commit is contained in:
parent
0bdd5cbcb8
commit
ebaf7ba035
@ -73,6 +73,12 @@ find %{buildroot} -name '*.la' -exec rm -f {} ';'
|
||||
|
||||
%find_lang %{name}
|
||||
|
||||
%pre
|
||||
getent group fwsignd >/dev/null || groupadd -r fwsignd
|
||||
getent passwd fwsignd >/dev/null || \
|
||||
useradd -r -g fwsignd -d /var/lib/fwsignd -s /sbin/nologin \
|
||||
-c "User for fwsignd" fwsignd
|
||||
|
||||
%post
|
||||
/sbin/ldconfig
|
||||
%systemd_post fwupd.service
|
||||
@ -112,6 +118,7 @@ find %{buildroot} -name '*.la' -exec rm -f {} ';'
|
||||
%config(noreplace)%{_sysconfdir}/fwsignd.conf
|
||||
%{_unitdir}/fwsignd.service
|
||||
%{_libexecdir}/fwsignd
|
||||
%attr(755,fwsignd,fwsignd) %dir %{_localstatedir}/lib/fwsignd
|
||||
|
||||
%files devel
|
||||
%{_includedir}/fwupd-1
|
||||
|
@ -4,11 +4,36 @@
|
||||
#
|
||||
# IMPORTANT: the files we could process are deleted from this location when
|
||||
# they have been signed successfully.
|
||||
SourceDirectory=/mnt/source
|
||||
#
|
||||
# You will need to modify the permissions on this directory so that the signd
|
||||
# user can read from this location, e.g.
|
||||
# # chown fwsignd:fwsignd /srv/fwsignd/source
|
||||
#
|
||||
# If you are running as non-root, you probably also want to do something like:
|
||||
# # chmod g+s /srv/fwsignd/source
|
||||
SourceDirectory=/mnt/fwsignd/source
|
||||
|
||||
# The path where we write new signed .cab files
|
||||
DestinationDirectory=/mnt/destination
|
||||
#
|
||||
# You will need to modify the permissions on this directory so that the signd
|
||||
# user can write to this location, e.g.
|
||||
# # chown fwsignd:fwsignd /srv/fwsignd/destination -R
|
||||
DestinationDirectory=/mnt/fwsignd/destination
|
||||
|
||||
# The GPG key ID used for signing -- you probably want to create a key without
|
||||
# a password, e.g. gpg2 --gen-key && gpg2 --edit-key; passwd; quit
|
||||
# a password, e.g.
|
||||
# # useradd temp
|
||||
# # su -l temp
|
||||
# $ gpg2 --full-gen-key
|
||||
# $ gpg2 --list-secret-keys
|
||||
# $ gpg2 --edit-key 12345678
|
||||
# gpg> passwd
|
||||
# gpg> quit
|
||||
# # cp /home/temp/.gnupg /var/lib/fwsignd/ -Rv
|
||||
# # chown fwsignd:fwsignd /var/lib/fwsignd/.gnupg -R
|
||||
KeyID=12345678
|
||||
|
||||
# Set the destination files to the same user and group as the source files
|
||||
#
|
||||
# This requires that the fwsignd binary is being run as the root user.
|
||||
SetDestinationOwner=true
|
||||
|
@ -210,6 +210,8 @@ install-data-hook:
|
||||
if test -w $(DESTDIR)$(prefix)/; then \
|
||||
mkdir -p $(DESTDIR)$(localstatedir)/lib/fwupd; \
|
||||
chmod 0755 $(DESTDIR)$(localstatedir)/lib/fwupd; \
|
||||
mkdir -p $(DESTDIR)$(localstatedir)/lib/fwsignd; \
|
||||
chmod 0755 $(DESTDIR)$(localstatedir)/lib/fwsignd; \
|
||||
mkdir -p $(DESTDIR)$(localstatedir)/cache/app-info/xmls; \
|
||||
mkdir -p $(DESTDIR)$(localstatedir)/cache/app-info/icons; \
|
||||
fi
|
||||
|
145
src/fu-sign.c
145
src/fu-sign.c
@ -21,11 +21,13 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <appstream-glib.h>
|
||||
#include <fwupd.h>
|
||||
#include <gio/gio.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <glib/gstdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "fu-cleanup.h"
|
||||
#include "fu-cab.h"
|
||||
@ -36,16 +38,18 @@ typedef struct {
|
||||
gchar *source;
|
||||
gchar *destination;
|
||||
gchar *key_id;
|
||||
gboolean set_owner;
|
||||
FuKeyring *keyring;
|
||||
} FuSignPrivate;
|
||||
|
||||
/**
|
||||
* fu_sign_process_file:
|
||||
* fu_sign_process_file_cab:
|
||||
**/
|
||||
static gboolean
|
||||
fu_sign_process_file (FuSignPrivate *priv,
|
||||
const gchar *fn_src,
|
||||
const gchar *fn_dst,
|
||||
GError **error)
|
||||
fu_sign_process_file_cab (FuSignPrivate *priv,
|
||||
const gchar *fn_src,
|
||||
const gchar *fn_dst,
|
||||
GError **error)
|
||||
{
|
||||
gsize fw_len = 0;
|
||||
_cleanup_bytes_unref_ GBytes *fw = NULL;
|
||||
@ -53,7 +57,6 @@ fu_sign_process_file (FuSignPrivate *priv,
|
||||
_cleanup_free_ gchar *fw_data = NULL;
|
||||
_cleanup_free_ gchar *fn_bin_asc = NULL;
|
||||
_cleanup_object_unref_ FuCab *cab = NULL;
|
||||
_cleanup_object_unref_ FuKeyring *kr = NULL;
|
||||
_cleanup_object_unref_ GFile *src = NULL;
|
||||
_cleanup_object_unref_ GFile *dst = NULL;
|
||||
const gchar *fn_bin;
|
||||
@ -71,15 +74,10 @@ fu_sign_process_file (FuSignPrivate *priv,
|
||||
/* sign the .bin */
|
||||
fn_bin = fu_cab_get_filename_firmware (cab);
|
||||
g_info ("signing %s with key %s", fn_bin, priv->key_id);
|
||||
kr = fu_keyring_new ();
|
||||
if (priv->key_id != NULL) {
|
||||
if (!fu_keyring_set_signing_key (kr, priv->key_id, error))
|
||||
return FALSE;
|
||||
}
|
||||
if (!g_file_get_contents (fn_bin, &fw_data, &fw_len, error))
|
||||
return FALSE;
|
||||
fw = g_bytes_new_static (fw_data, fw_len);
|
||||
sig = fu_keyring_sign_data (kr, fw, error);
|
||||
sig = fu_keyring_sign_data (priv->keyring, fw, error);
|
||||
if (sig == NULL)
|
||||
return FALSE;
|
||||
|
||||
@ -101,10 +99,6 @@ fu_sign_process_file (FuSignPrivate *priv,
|
||||
if (!fu_cab_save_file (cab, dst, NULL, error))
|
||||
return FALSE;
|
||||
|
||||
/* delete the source file */
|
||||
g_debug ("deleting %s", fn_src);
|
||||
g_unlink (fn_src);
|
||||
|
||||
/* delete the working space */
|
||||
g_unlink (fn_bin_asc);
|
||||
if (!fu_cab_delete_temp_files (cab, error))
|
||||
@ -112,6 +106,105 @@ fu_sign_process_file (FuSignPrivate *priv,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_sign_process_file_xml:
|
||||
**/
|
||||
static gboolean
|
||||
fu_sign_process_file_xml (FuSignPrivate *priv,
|
||||
const gchar *fn_src,
|
||||
const gchar *fn_dst,
|
||||
GError **error)
|
||||
{
|
||||
gsize xml_len = 0;
|
||||
_cleanup_bytes_unref_ GBytes *xml = NULL;
|
||||
_cleanup_bytes_unref_ GBytes *sig = NULL;
|
||||
_cleanup_free_ gchar *xml_data = NULL;
|
||||
|
||||
/* sign the firmware */
|
||||
g_info ("signing %s with key %s", fn_src, priv->key_id);
|
||||
if (!g_file_get_contents (fn_src, &xml_data, &xml_len, error))
|
||||
return FALSE;
|
||||
xml = g_bytes_new_static (xml_data, xml_len);
|
||||
sig = fu_keyring_sign_data (priv->keyring, xml, error);
|
||||
if (sig == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* write new detached signature */
|
||||
g_debug ("writing to %s", fn_dst);
|
||||
if (!g_file_set_contents (fn_dst,
|
||||
g_bytes_get_data (sig, NULL),
|
||||
g_bytes_get_size (sig),
|
||||
error))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_sign_process_file:
|
||||
**/
|
||||
static gboolean
|
||||
fu_sign_process_file (FuSignPrivate *priv,
|
||||
const gchar *fn_src,
|
||||
GError **error)
|
||||
{
|
||||
guint32 uid;
|
||||
guint32 gid;
|
||||
gboolean ret = FALSE;
|
||||
_cleanup_free_ gchar *fn_dst = NULL;
|
||||
_cleanup_free_ gchar *basename = NULL;
|
||||
_cleanup_object_unref_ GFileInfo *info = NULL;
|
||||
_cleanup_object_unref_ GFile *src = NULL;
|
||||
|
||||
/* get the file owner */
|
||||
src = g_file_new_for_path (fn_src);
|
||||
info = g_file_query_info (src,
|
||||
G_FILE_ATTRIBUTE_UNIX_UID ","
|
||||
G_FILE_ATTRIBUTE_UNIX_GID ","
|
||||
G_FILE_ATTRIBUTE_OWNER_USER ","
|
||||
G_FILE_ATTRIBUTE_OWNER_GROUP,
|
||||
G_FILE_QUERY_INFO_NONE,
|
||||
NULL, error);
|
||||
if (info == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* process these in different ways */
|
||||
if (g_str_has_suffix (fn_src, ".cab")) {
|
||||
/* cab file */
|
||||
basename = g_path_get_basename (fn_src);
|
||||
fn_dst = g_build_filename (priv->destination, basename, NULL);
|
||||
ret = fu_sign_process_file_cab (priv, fn_src, fn_dst, error);
|
||||
} else if (as_app_guess_source_kind (fn_src) == AS_APP_SOURCE_KIND_APPSTREAM) {
|
||||
/* AppStream metadata */
|
||||
basename = g_path_get_basename (fn_src);
|
||||
fn_dst = g_strdup_printf ("%s/%s.asc", priv->destination, basename);
|
||||
ret = fu_sign_process_file_xml (priv, fn_src, fn_dst, error);
|
||||
} else {
|
||||
/* unknown */
|
||||
g_set_error_literal (error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_INVALID_FILE,
|
||||
"unknown file type");
|
||||
}
|
||||
if (!ret)
|
||||
return FALSE;
|
||||
|
||||
/* set the owner:group on the new file */
|
||||
if (priv->set_owner) {
|
||||
uid = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_UID);
|
||||
gid = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_GID);
|
||||
g_debug ("Attempting to set unix owner to %s:%s",
|
||||
g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_OWNER_USER),
|
||||
g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_OWNER_GROUP));
|
||||
chown (fn_dst, uid, gid);
|
||||
}
|
||||
|
||||
/* only delete the source file if *everything* worked */
|
||||
g_debug ("deleting %s", fn_src);
|
||||
g_unlink (fn_src);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_sign_coldplug:
|
||||
**/
|
||||
@ -126,13 +219,11 @@ fu_sign_coldplug (FuSignPrivate *priv, GError **error)
|
||||
while (TRUE) {
|
||||
const gchar *fn;
|
||||
_cleanup_free_ gchar *fn_src = NULL;
|
||||
_cleanup_free_ gchar *fn_dst = NULL;
|
||||
fn = g_dir_read_name (dir);
|
||||
if (fn == NULL)
|
||||
break;
|
||||
fn_src = g_build_filename (priv->source, fn, NULL);
|
||||
fn_dst = g_build_filename (priv->destination, fn, NULL);
|
||||
if (!fu_sign_process_file (priv, fn_src, fn_dst, error))
|
||||
if (!fu_sign_process_file (priv, fn_src, error))
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
@ -148,8 +239,6 @@ fu_sign_monitor_changed_cb (GFileMonitor *monitor,
|
||||
FuSignPrivate *priv)
|
||||
{
|
||||
_cleanup_error_free_ GError *error = NULL;
|
||||
_cleanup_free_ gchar *basename = NULL;
|
||||
_cleanup_free_ gchar *fn_dst = NULL;
|
||||
_cleanup_free_ gchar *fn_src = NULL;
|
||||
|
||||
/* only new files */
|
||||
@ -160,9 +249,7 @@ fu_sign_monitor_changed_cb (GFileMonitor *monitor,
|
||||
return;
|
||||
|
||||
/* process file */
|
||||
basename = g_file_get_basename (file);
|
||||
fn_dst = g_build_filename (priv->destination, basename, NULL);
|
||||
if (!fu_sign_process_file (priv, fn_src, fn_dst, &error)) {
|
||||
if (!fu_sign_process_file (priv, fn_src, &error)) {
|
||||
g_warning ("failed to process %s: %s", fn_src, error->message);
|
||||
return;
|
||||
}
|
||||
@ -226,6 +313,7 @@ main (int argc, char *argv[])
|
||||
/* fall back to keyfile */
|
||||
config = g_key_file_new ();
|
||||
config_file = g_build_filename (SYSCONFDIR, "fwsignd.conf", NULL);
|
||||
g_debug ("Loading fallback values from %s", config_file);
|
||||
if (!g_key_file_load_from_file (config, config_file,
|
||||
G_KEY_FILE_NONE, &error)) {
|
||||
g_print ("failed to load config file %s: %s\n",
|
||||
@ -248,6 +336,14 @@ main (int argc, char *argv[])
|
||||
priv->source = g_strdup (source);
|
||||
priv->destination = g_strdup (destination);
|
||||
priv->key_id = g_strdup (key_id);
|
||||
priv->keyring = fu_keyring_new ();
|
||||
priv->set_owner = g_key_file_get_boolean (config, "fwupd", "SetDestinationOwner", NULL);
|
||||
if (priv->key_id != NULL &&
|
||||
!fu_keyring_set_signing_key (priv->keyring, priv->key_id, &error)) {
|
||||
g_print ("valid GPG key required: %s\n", error->message);
|
||||
retval = EXIT_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* process */
|
||||
g_debug ("clearing queue");
|
||||
@ -277,6 +373,7 @@ main (int argc, char *argv[])
|
||||
retval = 0;
|
||||
out:
|
||||
if (priv != NULL) {
|
||||
g_object_unref (priv->keyring);
|
||||
g_free (priv->source);
|
||||
g_free (priv->destination);
|
||||
g_free (priv->key_id);
|
||||
|
Loading…
Reference in New Issue
Block a user