postprocess: Use names (not ids) in synthesized tmpfiles.d files
Related to: https://github.com/projectatomic/rpm-ostree/issues/49 We want to support "name binding" per client system, rather than having a hardcoded mapping in our tree. Currently if e.g. a new daemon is added as a dependency (or as part of e.g. systemd) it's easy to silently miss it. This is prep for doing that binding client side consistently, which is what we do with package layering. Closes: #1077 Approved by: jlebon
This commit is contained in:
parent
669031f63b
commit
d6218e0e16
@ -1140,3 +1140,97 @@ rpmostree_passwd_complete_rpm_layering (int rootfs_dfd,
|
||||
*/
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
struct RpmOstreePasswdDB
|
||||
{
|
||||
GHashTable *users;
|
||||
GHashTable *groups;
|
||||
};
|
||||
|
||||
static gboolean
|
||||
add_passwd_to_hash (int rootfs_dfd, const char *path,
|
||||
GHashTable *users, GError **error)
|
||||
{
|
||||
g_autoptr(FILE) src_stream = open_file_stream_read_at (rootfs_dfd, path, error);
|
||||
if (!src_stream)
|
||||
return FALSE;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
errno = 0;
|
||||
struct passwd *pw = fgetpwent (src_stream);
|
||||
if (!pw)
|
||||
{
|
||||
if (errno != 0 && errno != ENOENT)
|
||||
return glnx_throw_errno_prefix (error, "fgetpwent");
|
||||
break;
|
||||
}
|
||||
g_hash_table_insert (users, GUINT_TO_POINTER (pw->pw_uid), g_strdup (pw->pw_name));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
add_groups_to_hash (int rootfs_dfd, const char *path,
|
||||
GHashTable *groups, GError **error)
|
||||
{
|
||||
g_autoptr(FILE) src_stream = open_file_stream_read_at (rootfs_dfd, path, error);
|
||||
if (!src_stream)
|
||||
return FALSE;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
errno = 0;
|
||||
struct group *gr = fgetgrent (src_stream);
|
||||
if (!gr)
|
||||
{
|
||||
if (errno != 0 && errno != ENOENT)
|
||||
return glnx_throw_errno_prefix (error, "fgetgrent");
|
||||
break;
|
||||
}
|
||||
g_hash_table_insert (groups, GUINT_TO_POINTER (gr->gr_gid), g_strdup (gr->gr_name));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
RpmOstreePasswdDB *
|
||||
rpmostree_passwddb_open (int rootfs, GCancellable *cancellable, GError **error)
|
||||
{
|
||||
g_autoptr(RpmOstreePasswdDB) ret = g_new0 (RpmOstreePasswdDB, 1);
|
||||
ret->users = g_hash_table_new_full (NULL, NULL, NULL, g_free);
|
||||
ret->groups = g_hash_table_new_full (NULL, NULL, NULL, g_free);
|
||||
|
||||
if (!add_passwd_to_hash (rootfs, "usr/etc/passwd", ret->users, error))
|
||||
return NULL;
|
||||
if (!add_passwd_to_hash (rootfs, "usr/lib/passwd", ret->users, error))
|
||||
return NULL;
|
||||
|
||||
if (!add_groups_to_hash (rootfs, "usr/etc/group", ret->groups, error))
|
||||
return NULL;
|
||||
if (!add_groups_to_hash (rootfs, "usr/lib/group", ret->groups, error))
|
||||
return NULL;
|
||||
|
||||
return g_steal_pointer (&ret);
|
||||
}
|
||||
|
||||
const char *
|
||||
rpmostree_passwddb_lookup_user (RpmOstreePasswdDB *db, uid_t uid)
|
||||
{
|
||||
return g_hash_table_lookup (db->users, GUINT_TO_POINTER (uid));
|
||||
}
|
||||
|
||||
const char *
|
||||
rpmostree_passwddb_lookup_group (RpmOstreePasswdDB *db, gid_t gid)
|
||||
{
|
||||
return g_hash_table_lookup (db->groups, GUINT_TO_POINTER (gid));
|
||||
}
|
||||
|
||||
void
|
||||
rpmostree_passwddb_free (RpmOstreePasswdDB *db)
|
||||
{
|
||||
g_hash_table_unref (db->users);
|
||||
g_hash_table_unref (db->groups);
|
||||
g_free (db);
|
||||
}
|
||||
|
@ -63,6 +63,16 @@ rpmostree_generate_passwd_from_previous (OstreeRepo *repo,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
typedef struct RpmOstreePasswdDB RpmOstreePasswdDB;
|
||||
RpmOstreePasswdDB *
|
||||
rpmostree_passwddb_open (int rootfs, GCancellable *cancellable, GError **error);
|
||||
const char *
|
||||
rpmostree_passwddb_lookup_user (RpmOstreePasswdDB *db, uid_t uid);
|
||||
const char *
|
||||
rpmostree_passwddb_lookup_group (RpmOstreePasswdDB *db, gid_t gid);
|
||||
void
|
||||
rpmostree_passwddb_free (RpmOstreePasswdDB *db);
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(RpmOstreePasswdDB, rpmostree_passwddb_free)
|
||||
|
||||
gboolean
|
||||
rpmostree_passwd_cleanup (int rootfs_dfd, GCancellable *cancellable, GError **error);
|
||||
|
@ -428,6 +428,7 @@ process_kernel_and_initramfs (int rootfs_dfd,
|
||||
static gboolean
|
||||
convert_var_to_tmpfiles_d_recurse (GOutputStream *tmpfiles_out,
|
||||
int dfd,
|
||||
RpmOstreePasswdDB *pwdb,
|
||||
GString *prefix,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
@ -478,13 +479,19 @@ convert_var_to_tmpfiles_d_recurse (GOutputStream *tmpfiles_out,
|
||||
return FALSE;
|
||||
|
||||
g_string_append_printf (tmpfiles_d_buf, " 0%02o", stbuf.st_mode & ~S_IFMT);
|
||||
g_string_append_printf (tmpfiles_d_buf, " %d %d - -", stbuf.st_uid, stbuf.st_gid);
|
||||
const char *user = rpmostree_passwddb_lookup_user (pwdb, stbuf.st_uid);
|
||||
if (!user)
|
||||
return glnx_throw (error, "Failed to find user '%u' for %s", stbuf.st_uid, dent->d_name);
|
||||
const char *group = rpmostree_passwddb_lookup_group (pwdb, stbuf.st_gid);
|
||||
if (!group)
|
||||
return glnx_throw (error, "Failed to find group '%u' for %s", stbuf.st_gid, dent->d_name);
|
||||
g_string_append_printf (tmpfiles_d_buf, " %s %s - -", user, group);
|
||||
|
||||
/* Push prefix */
|
||||
g_string_append_c (prefix, '/');
|
||||
g_string_append (prefix, dent->d_name);
|
||||
|
||||
if (!convert_var_to_tmpfiles_d_recurse (tmpfiles_out, dfd, prefix,
|
||||
if (!convert_var_to_tmpfiles_d_recurse (tmpfiles_out, dfd, pwdb, prefix,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
@ -525,6 +532,10 @@ convert_var_to_tmpfiles_d (int rootfs_dfd,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(RpmOstreePasswdDB) pwdb = rpmostree_passwddb_open (rootfs_dfd, cancellable, error);
|
||||
if (!pwdb)
|
||||
return FALSE;
|
||||
|
||||
glnx_autofd int var_dfd = -1;
|
||||
/* List of files that are known to possibly exist, but in practice
|
||||
* things work fine if we simply ignore them. Don't add something
|
||||
@ -573,7 +584,7 @@ convert_var_to_tmpfiles_d (int rootfs_dfd,
|
||||
return FALSE;
|
||||
|
||||
g_autoptr(GString) prefix = g_string_new ("/var");
|
||||
if (!convert_var_to_tmpfiles_d_recurse (tmpfiles_out, rootfs_dfd, prefix, cancellable, error))
|
||||
if (!convert_var_to_tmpfiles_d_recurse (tmpfiles_out, rootfs_dfd, pwdb, prefix, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
if (!g_output_stream_close (tmpfiles_out, cancellable, error))
|
||||
|
@ -57,5 +57,7 @@ echo "ok no leftover files"
|
||||
ostree --repo=${repobuild} cat ${treeref} /usr/lib/tmpfiles.d/rpm-ostree-1-autovar.conf > autovar.txt
|
||||
# Picked this one at random as an example of something that won't likely be
|
||||
# converted to tmpfiles.d upstream. But if it is, we can change this test.
|
||||
assert_file_has_content_literal autovar.txt 'd /var/cache 0755 0 0 - -'
|
||||
assert_file_has_content_literal autovar.txt 'd /var/cache 0755 root root - -'
|
||||
# And this one has a non-root uid
|
||||
assert_file_has_content_literal autovar.txt 'd /var/log/chrony 0755 chrony chrony - -'
|
||||
echo "ok autovar"
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
"repos": ["fedora"],
|
||||
|
||||
"packages": ["kernel", "nss-altfiles", "systemd", "ostree", "selinux-policy-targeted"],
|
||||
"packages": ["kernel", "nss-altfiles", "systemd", "ostree", "selinux-policy-targeted", "chrony"],
|
||||
|
||||
"packages-aarch64": ["grub2-efi", "ostree-grub2",
|
||||
"efibootmgr", "shim"],
|
||||
|
Loading…
Reference in New Issue
Block a user