libpriv/passwd: move passwd database to Rust
This moves to Rust the in-memory structure holding passwd entries (users and groups).
This commit is contained in:
parent
803e4db50c
commit
bdf8269dfa
@ -13,6 +13,9 @@ prefix = "ROR"
|
||||
# Here we exclude entries belonging to the C side which we use on the Rust side and so
|
||||
# doesn't make sense to re-export.
|
||||
exclude = ["RpmOstreeOrigin",
|
||||
"PasswdDB",
|
||||
"rpmostree_add_group_to_hash",
|
||||
"rpmostree_add_passwd_to_hash",
|
||||
"rpmostree_get_repodata_chksum_repr",
|
||||
"rpmostree_origin_get_live_state" ]
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*/
|
||||
|
||||
use c_utf8::CUtf8;
|
||||
use gio_sys;
|
||||
use glib_sys;
|
||||
use libc;
|
||||
@ -120,6 +121,17 @@ pub(crate) fn ref_from_raw_ptr<T>(p: *mut T) -> &'static mut T {
|
||||
// return a Result (using the std Error).
|
||||
// TODO: Try upstreaming this into the glib crate?
|
||||
|
||||
/// Convert C results (int + GError convention) to anyhow.
|
||||
pub(crate) fn int_gerror_to_result(res: i32, gerror: *mut glib_sys::GError) -> anyhow::Result<()> {
|
||||
if res != 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
assert!(!gerror.is_null(), "invalid failure, NULL Gerror");
|
||||
let err_msg = unsafe { CUtf8::from_ptr((*gerror).message) }?;
|
||||
anyhow::bail!("{}", err_msg)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn error_to_glib<E: Display>(e: &E, gerror: *mut *mut glib_sys::GError) {
|
||||
if gerror.is_null() {
|
||||
return;
|
||||
|
@ -8,6 +8,7 @@ NOTICE: The C header definitions are canonical, please update those first
|
||||
then synchronize the entries here.
|
||||
!*/
|
||||
|
||||
use crate::passwd::PasswdDB;
|
||||
use libdnf_sys::DnfPackage;
|
||||
|
||||
// From `libpriv/rpmostree-rpm-util.h`.
|
||||
@ -18,3 +19,22 @@ extern "C" {
|
||||
gerror: *mut *mut glib_sys::GError,
|
||||
) -> libc::c_int;
|
||||
}
|
||||
|
||||
// From `libpriv/rpmostree-passwd-util.h`.
|
||||
extern "C" {
|
||||
#[allow(improper_ctypes)]
|
||||
pub(crate) fn rpmostree_add_passwd_to_hash(
|
||||
rootfs_dfd: libc::c_int,
|
||||
path: *const libc::c_char,
|
||||
db: *mut PasswdDB,
|
||||
gerror: *mut *mut glib_sys::GError,
|
||||
) -> libc::c_int;
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
pub(crate) fn rpmostree_add_group_to_hash(
|
||||
rootfs_dfd: libc::c_int,
|
||||
path: *const libc::c_char,
|
||||
db: *mut PasswdDB,
|
||||
gerror: *mut *mut glib_sys::GError,
|
||||
) -> libc::c_int;
|
||||
}
|
||||
|
@ -109,6 +109,20 @@ mod ffi {
|
||||
// FIXME/cxx make this Option<&str>
|
||||
fn transaction_apply_live(sysroot: Pin<&mut OstreeSysroot>, target: &str) -> Result<()>;
|
||||
}
|
||||
|
||||
// passwd.rs
|
||||
extern "Rust" {
|
||||
fn passwddb_open(rootfs: i32) -> Result<Box<PasswdDB>>;
|
||||
|
||||
type PasswdDB;
|
||||
fn add_user(self: &mut PasswdDB, uid: u32, username: &str);
|
||||
fn lookup_user(self: &PasswdDB, uid: u32) -> Result<String>;
|
||||
fn add_group(self: &mut PasswdDB, gid: u32, groupname: &str);
|
||||
fn lookup_group(self: &PasswdDB, gid: u32) -> Result<String>;
|
||||
// TODO(lucab): get rid of the two methods below.
|
||||
fn add_group_content(self: &mut PasswdDB, rootfs: i32, group_path: &str) -> Result<()>;
|
||||
fn add_passwd_content(self: &mut PasswdDB, rootfs: i32, passwd_path: &str) -> Result<()>;
|
||||
}
|
||||
}
|
||||
|
||||
mod client;
|
||||
@ -137,6 +151,8 @@ pub(crate) use self::live::*;
|
||||
mod origin;
|
||||
mod ostree_diff;
|
||||
mod ostree_utils;
|
||||
mod passwd;
|
||||
use passwd::{passwddb_open, PasswdDB};
|
||||
mod progress;
|
||||
pub use self::progress::*;
|
||||
mod scripts;
|
||||
|
84
rust/src/passwd.rs
Normal file
84
rust/src/passwd.rs
Normal file
@ -0,0 +1,84 @@
|
||||
use crate::ffiutil;
|
||||
use crate::includes::*;
|
||||
use anyhow::{anyhow, bail};
|
||||
use c_utf8::CUtf8Buf;
|
||||
use nix::unistd::{Gid, Uid};
|
||||
use std::collections::HashMap;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
|
||||
/// Populate a new DB with content from `passwd` and `group` files.
|
||||
pub(crate) fn passwddb_open(rootfs: i32) -> anyhow::Result<Box<PasswdDB>> {
|
||||
let fd = ffiutil::ffi_view_openat_dir(rootfs);
|
||||
PasswdDB::populate_new(&fd).map(|db| Box::new(db))
|
||||
}
|
||||
|
||||
/// Database holding users and groups.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct PasswdDB {
|
||||
users: HashMap<Uid, String>,
|
||||
groups: HashMap<Gid, String>,
|
||||
}
|
||||
|
||||
impl PasswdDB {
|
||||
/// Populate a new DB with content from `passwd` and `group` files.
|
||||
pub fn populate_new(rootfs: &openat::Dir) -> anyhow::Result<Self> {
|
||||
let mut db = Self::default();
|
||||
db.add_passwd_content(rootfs.as_raw_fd(), "usr/etc/passwd")?;
|
||||
db.add_passwd_content(rootfs.as_raw_fd(), "usr/lib/passwd")?;
|
||||
db.add_group_content(rootfs.as_raw_fd(), "usr/etc/group")?;
|
||||
db.add_group_content(rootfs.as_raw_fd(), "usr/lib/group")?;
|
||||
Ok(db)
|
||||
}
|
||||
|
||||
/// Lookup user name by ID.
|
||||
pub fn lookup_user(&self, uid: u32) -> anyhow::Result<String> {
|
||||
let key = Uid::from_raw(uid);
|
||||
self.users
|
||||
.get(&key)
|
||||
.cloned()
|
||||
.ok_or_else(|| anyhow!("failed to find user ID '{}'", uid))
|
||||
}
|
||||
|
||||
/// Lookup group name by ID.
|
||||
pub fn lookup_group(&self, gid: u32) -> anyhow::Result<String> {
|
||||
let key = Gid::from_raw(gid);
|
||||
self.groups
|
||||
.get(&key)
|
||||
.cloned()
|
||||
.ok_or_else(|| anyhow!("failed to find group ID '{}'", gid))
|
||||
}
|
||||
|
||||
/// Add a user ID with the associated name.
|
||||
pub fn add_user(&mut self, uid: u32, username: &str) {
|
||||
let id = Uid::from_raw(uid);
|
||||
self.users.insert(id, username.to_string());
|
||||
}
|
||||
|
||||
/// Add a group ID with the associated name.
|
||||
pub fn add_group(&mut self, gid: u32, groupname: &str) {
|
||||
let id = Gid::from_raw(gid);
|
||||
self.groups.insert(id, groupname.to_string());
|
||||
}
|
||||
|
||||
/// Add content from a `group` file.
|
||||
pub fn add_group_content(&mut self, rootfs: i32, group_path: &str) -> anyhow::Result<()> {
|
||||
let c_path: CUtf8Buf = group_path.to_string().into();
|
||||
let db_ptr = self as *mut Self;
|
||||
let mut gerror: *mut glib_sys::GError = std::ptr::null_mut();
|
||||
// TODO(lucab): find a replacement for `fgetgrent` and drop this.
|
||||
let res =
|
||||
unsafe { rpmostree_add_group_to_hash(rootfs, c_path.as_ptr(), db_ptr, &mut gerror) };
|
||||
ffiutil::int_gerror_to_result(res, gerror)
|
||||
}
|
||||
|
||||
/// Add content from a `passwd` file.
|
||||
pub fn add_passwd_content(&mut self, rootfs: i32, passwd_path: &str) -> anyhow::Result<()> {
|
||||
let c_path: CUtf8Buf = passwd_path.to_string().into();
|
||||
let db_ptr = self as *mut Self;
|
||||
let mut gerror: *mut glib_sys::GError = std::ptr::null_mut();
|
||||
// TODO(lucab): find a replacement for `fgetpwent` and drop this.
|
||||
let res =
|
||||
unsafe { rpmostree_add_passwd_to_hash(rootfs, c_path.as_ptr(), db_ptr, &mut gerror) };
|
||||
ffiutil::int_gerror_to_result(res, gerror)
|
||||
}
|
||||
}
|
@ -1278,15 +1278,10 @@ 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)
|
||||
gboolean
|
||||
rpmostree_add_passwd_to_hash (int rootfs_dfd, const char *path,
|
||||
rpmostreecxx::PasswdDB *db,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(FILE) src_stream = open_file_stream_read_at (rootfs_dfd, path, error);
|
||||
if (!src_stream)
|
||||
@ -1302,15 +1297,20 @@ add_passwd_to_hash (int rootfs_dfd, const char *path,
|
||||
return glnx_throw_errno_prefix (error, "fgetpwent");
|
||||
break;
|
||||
}
|
||||
g_hash_table_insert (users, GUINT_TO_POINTER (pw->pw_uid), g_strdup (pw->pw_name));
|
||||
if (pw->pw_name != NULL)
|
||||
{
|
||||
std::string username(pw->pw_name);
|
||||
db->add_user (pw->pw_uid, username);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
add_groups_to_hash (int rootfs_dfd, const char *path,
|
||||
GHashTable *groups, GError **error)
|
||||
gboolean
|
||||
rpmostree_add_group_to_hash (int rootfs_dfd, const char *path,
|
||||
rpmostreecxx::PasswdDB *db,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(FILE) src_stream = open_file_stream_read_at (rootfs_dfd, path, error);
|
||||
if (!src_stream)
|
||||
@ -1326,48 +1326,12 @@ add_groups_to_hash (int rootfs_dfd, const char *path,
|
||||
return glnx_throw_errno_prefix (error, "fgetgrent");
|
||||
break;
|
||||
}
|
||||
g_hash_table_insert (groups, GUINT_TO_POINTER (gr->gr_gid), g_strdup (gr->gr_name));
|
||||
if (gr->gr_name != NULL)
|
||||
{
|
||||
std::string groupname(gr->gr_name);
|
||||
db->add_group (gr->gr_gid, groupname);
|
||||
}
|
||||
}
|
||||
|
||||
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 util::move_nullify (ret);
|
||||
}
|
||||
|
||||
const char *
|
||||
rpmostree_passwddb_lookup_user (RpmOstreePasswdDB *db, uid_t uid)
|
||||
{
|
||||
return static_cast<const char*>(g_hash_table_lookup (db->users, GUINT_TO_POINTER (uid)));
|
||||
}
|
||||
|
||||
const char *
|
||||
rpmostree_passwddb_lookup_group (RpmOstreePasswdDB *db, gid_t gid)
|
||||
{
|
||||
return static_cast<const char*>(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);
|
||||
}
|
||||
|
@ -25,10 +25,20 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "rpmostree-cxxrs.h"
|
||||
#include "rpmostree-rust.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
gboolean
|
||||
rpmostree_add_passwd_to_hash (int rootfs_dfd, const char *path,
|
||||
rpmostreecxx::PasswdDB *db,
|
||||
GError **error);
|
||||
gboolean
|
||||
rpmostree_add_group_to_hash (int rootfs_dfd, const char *path,
|
||||
rpmostreecxx::PasswdDB *db,
|
||||
GError **error);
|
||||
|
||||
gboolean
|
||||
rpmostree_check_passwd (OstreeRepo *repo,
|
||||
int rootfs_dfd,
|
||||
@ -69,17 +79,6 @@ rpmostree_passwd_compose_prep (int rootfs_dfd,
|
||||
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);
|
||||
|
||||
|
@ -479,12 +479,12 @@ 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)
|
||||
convert_var_to_tmpfiles_d_recurse (GOutputStream *tmpfiles_out,
|
||||
int dfd,
|
||||
rpmostreecxx::PasswdDB &pwdb,
|
||||
GString *prefix,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
|
||||
gsize bytes_written;
|
||||
@ -538,15 +538,11 @@ convert_var_to_tmpfiles_d_recurse (GOutputStream *tmpfiles_out,
|
||||
struct stat stbuf;
|
||||
if (!glnx_fstatat (dfd_iter.fd, dent->d_name, &stbuf, AT_SYMLINK_NOFOLLOW, error))
|
||||
return FALSE;
|
||||
|
||||
g_string_append_printf (tmpfiles_d_buf, " 0%02o", stbuf.st_mode & ~S_IFMT);
|
||||
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);
|
||||
|
||||
auto username = pwdb.lookup_user (stbuf.st_uid);
|
||||
auto groupname = pwdb.lookup_group (stbuf.st_gid);
|
||||
g_string_append_printf (tmpfiles_d_buf, " %s %s - -", username.c_str(), groupname.c_str());
|
||||
|
||||
if (filetype_c == 'd')
|
||||
{
|
||||
@ -595,9 +591,7 @@ convert_var_to_tmpfiles_d (int rootfs_dfd,
|
||||
{
|
||||
GLNX_AUTO_PREFIX_ERROR ("Converting /var to tmpfiles.d", error);
|
||||
|
||||
g_autoptr(RpmOstreePasswdDB) pwdb = rpmostree_passwddb_open (rootfs_dfd, cancellable, error);
|
||||
if (!pwdb)
|
||||
return FALSE;
|
||||
auto pwdb = rpmostreecxx::passwddb_open (rootfs_dfd);
|
||||
|
||||
glnx_autofd int var_dfd = -1;
|
||||
/* List of files that are known to possibly exist, but in practice
|
||||
@ -647,7 +641,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, pwdb, 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))
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <ostree.h>
|
||||
#include "rpmostree-json-parsing.h"
|
||||
#include "rpmostree-rust.h"
|
||||
#include "rpmostree-cxxrs.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user