mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-09 13:26:48 +00:00
Implememt static cap credentials
This commit is contained in:
parent
2a0446265e
commit
c99e6b4ced
347
services/libs/jinux-std/src/process/credentials/credentials_.rs
Normal file
347
services/libs/jinux-std/src/process/credentials/credentials_.rs
Normal file
@ -0,0 +1,347 @@
|
||||
use super::group::AtomicGid;
|
||||
use super::user::AtomicUid;
|
||||
use super::{Gid, Uid};
|
||||
use crate::prelude::*;
|
||||
use jinux_frame::sync::{RwLockReadGuard, RwLockWriteGuard};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct Credentials_ {
|
||||
/// Real user id. The user to which the process belongs.
|
||||
ruid: AtomicUid,
|
||||
/// Effective user id. Used to determine the permissions granted to a process when it tries to perform various operations (i.e., system calls)
|
||||
euid: AtomicUid,
|
||||
/// Saved-set uid. Used by set_uid elf, the saved_set_uid will be set if the elf has setuid bit
|
||||
suid: AtomicUid,
|
||||
/// User id used for filesystem checks.
|
||||
fsuid: AtomicUid,
|
||||
|
||||
/// Real group id. The group to which the process belongs
|
||||
rgid: AtomicGid,
|
||||
/// Effective gid,
|
||||
egid: AtomicGid,
|
||||
/// Saved-set gid. Used by set_gid elf, the saved_set_gid will be set if the elf has setgid bit
|
||||
sgid: AtomicGid,
|
||||
/// Group id used for file system checks.
|
||||
fsgid: AtomicGid,
|
||||
|
||||
// A set of additional groups to which a process belongs.
|
||||
supplementary_gids: RwLock<BTreeSet<Gid>>,
|
||||
}
|
||||
|
||||
impl Credentials_ {
|
||||
/// Create a new credentials. ruid, euid, suid will be set as the same uid, and gid is the same.
|
||||
pub fn new(uid: Uid, gid: Gid) -> Self {
|
||||
let mut supplementary_gids = BTreeSet::new();
|
||||
supplementary_gids.insert(gid);
|
||||
|
||||
Self {
|
||||
ruid: AtomicUid::new(uid),
|
||||
euid: AtomicUid::new(uid),
|
||||
suid: AtomicUid::new(uid),
|
||||
fsuid: AtomicUid::new(uid),
|
||||
rgid: AtomicGid::new(gid),
|
||||
egid: AtomicGid::new(gid),
|
||||
sgid: AtomicGid::new(gid),
|
||||
fsgid: AtomicGid::new(gid),
|
||||
supplementary_gids: RwLock::new(supplementary_gids),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_privileged(&self) -> bool {
|
||||
self.euid.is_root()
|
||||
}
|
||||
|
||||
// ******* Uid methods *******
|
||||
|
||||
pub(super) fn ruid(&self) -> Uid {
|
||||
self.ruid.get()
|
||||
}
|
||||
|
||||
pub(super) fn euid(&self) -> Uid {
|
||||
self.euid.get()
|
||||
}
|
||||
|
||||
pub(super) fn suid(&self) -> Uid {
|
||||
self.suid.get()
|
||||
}
|
||||
|
||||
pub(super) fn fsuid(&self) -> Uid {
|
||||
self.fsuid.get()
|
||||
}
|
||||
|
||||
pub(super) fn set_uid(&self, uid: Uid) {
|
||||
if self.is_privileged() {
|
||||
self.ruid.set(uid);
|
||||
self.euid.set(uid);
|
||||
self.suid.set(uid);
|
||||
} else {
|
||||
self.euid.set(uid);
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn set_reuid(&self, ruid: Option<Uid>, euid: Option<Uid>) -> Result<()> {
|
||||
self.check_uid_perm(ruid.as_ref(), euid.as_ref(), None, false)?;
|
||||
|
||||
let should_set_suid = ruid.is_some() || euid.is_some_and(|euid| euid != self.ruid());
|
||||
|
||||
self.set_resuid_unchecked(ruid, euid, None);
|
||||
|
||||
if should_set_suid {
|
||||
self.suid.set(self.euid());
|
||||
}
|
||||
|
||||
// FIXME: should we set fsuid here? The linux document for syscall `setfsuid` is contradictory
|
||||
// with the document of syscall `setreuid`. The `setfsuid` document says the `fsuid` is always
|
||||
// the same as `euid`, but `setreuid` does not mention the `fsuid` should be set.
|
||||
self.fsuid.set(self.euid());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn set_resuid(
|
||||
&self,
|
||||
ruid: Option<Uid>,
|
||||
euid: Option<Uid>,
|
||||
suid: Option<Uid>,
|
||||
) -> Result<()> {
|
||||
self.check_uid_perm(ruid.as_ref(), euid.as_ref(), suid.as_ref(), true)?;
|
||||
|
||||
self.set_resuid_unchecked(ruid, euid, suid);
|
||||
|
||||
self.fsuid.set(self.euid());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn set_fsuid(&self, fsuid: Option<Uid>) -> Result<Uid> {
|
||||
let old_fsuid = self.fsuid();
|
||||
|
||||
let Some(fsuid) = fsuid else {
|
||||
return Ok(old_fsuid);
|
||||
};
|
||||
|
||||
if self.is_privileged() {
|
||||
self.fsuid.set(fsuid);
|
||||
return Ok(old_fsuid);
|
||||
}
|
||||
|
||||
if fsuid != self.ruid() && fsuid != self.euid() && fsuid != self.suid() {
|
||||
return_errno_with_message!(
|
||||
Errno::EPERM,
|
||||
"fsuid can only be one of old ruid, old euid and old suid."
|
||||
)
|
||||
}
|
||||
|
||||
self.fsuid.set(fsuid);
|
||||
|
||||
Ok(old_fsuid)
|
||||
}
|
||||
|
||||
pub(super) fn set_euid(&self, euid: Uid) {
|
||||
self.euid.set(euid);
|
||||
}
|
||||
|
||||
pub(super) fn set_suid(&self, suid: Uid) {
|
||||
self.suid.set(suid);
|
||||
}
|
||||
|
||||
// For `setreuid`, ruid can *NOT* be set to old suid,
|
||||
// while for `setresuid`, ruid can be set to old suid.
|
||||
fn check_uid_perm(
|
||||
&self,
|
||||
ruid: Option<&Uid>,
|
||||
euid: Option<&Uid>,
|
||||
suid: Option<&Uid>,
|
||||
ruid_may_be_old_suid: bool,
|
||||
) -> Result<()> {
|
||||
if self.is_privileged() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some(ruid) = ruid && *ruid != self.ruid() && *ruid != self.euid() && (!ruid_may_be_old_suid || *ruid != self.suid()) {
|
||||
return_errno_with_message!(Errno::EPERM, "ruid can only be one of old ruid, old euid (and old suid).");
|
||||
}
|
||||
|
||||
if let Some(euid) = euid && *euid != self.ruid() && *euid != self.euid() && *euid != self.suid() {
|
||||
return_errno_with_message!(Errno::EPERM, "euid can only be one of old ruid, old euid and old suid.")
|
||||
}
|
||||
|
||||
if let Some(suid) = suid && *suid != self.ruid() && *suid != self.euid() && *suid != self.suid() {
|
||||
return_errno_with_message!(Errno::EPERM, "suid can only be one of old ruid, old euid and old suid.")
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_resuid_unchecked(&self, ruid: Option<Uid>, euid: Option<Uid>, suid: Option<Uid>) {
|
||||
if let Some(ruid) = ruid {
|
||||
self.ruid.set(ruid);
|
||||
}
|
||||
|
||||
if let Some(euid) = euid {
|
||||
self.euid.set(euid);
|
||||
}
|
||||
|
||||
if let Some(suid) = suid {
|
||||
self.suid.set(suid);
|
||||
}
|
||||
}
|
||||
|
||||
// ******* Gid methods *******
|
||||
|
||||
pub(super) fn rgid(&self) -> Gid {
|
||||
self.rgid.get()
|
||||
}
|
||||
|
||||
pub(super) fn egid(&self) -> Gid {
|
||||
self.egid.get()
|
||||
}
|
||||
|
||||
pub(super) fn sgid(&self) -> Gid {
|
||||
self.sgid.get()
|
||||
}
|
||||
|
||||
pub(super) fn fsgid(&self) -> Gid {
|
||||
self.fsgid.get()
|
||||
}
|
||||
|
||||
pub(super) fn set_gid(&self, gid: Gid) {
|
||||
if self.is_privileged() {
|
||||
self.rgid.set(gid);
|
||||
self.egid.set(gid);
|
||||
self.sgid.set(gid);
|
||||
} else {
|
||||
self.egid.set(gid);
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn set_regid(&self, rgid: Option<Gid>, egid: Option<Gid>) -> Result<()> {
|
||||
self.check_gid_perm(rgid.as_ref(), egid.as_ref(), None, false)?;
|
||||
|
||||
let should_set_sgid = rgid.is_some() || egid.is_some_and(|egid| egid != self.rgid());
|
||||
|
||||
self.set_resgid_unchecked(rgid, egid, None);
|
||||
|
||||
if should_set_sgid {
|
||||
self.sgid.set(self.egid());
|
||||
}
|
||||
|
||||
self.fsgid.set(self.egid());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn set_resgid(
|
||||
&self,
|
||||
rgid: Option<Gid>,
|
||||
egid: Option<Gid>,
|
||||
sgid: Option<Gid>,
|
||||
) -> Result<()> {
|
||||
self.check_gid_perm(rgid.as_ref(), egid.as_ref(), sgid.as_ref(), true)?;
|
||||
|
||||
self.set_resgid_unchecked(rgid, egid, sgid);
|
||||
|
||||
self.fsgid.set(self.egid());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn set_fsgid(&self, fsgid: Option<Gid>) -> Result<Gid> {
|
||||
let old_fsgid = self.fsgid();
|
||||
|
||||
let Some(fsgid) = fsgid else {
|
||||
return Ok(old_fsgid);
|
||||
};
|
||||
|
||||
if self.is_privileged() {
|
||||
self.fsgid.set(fsgid);
|
||||
return Ok(old_fsgid);
|
||||
}
|
||||
|
||||
if fsgid != self.rgid() && fsgid != self.egid() && fsgid != self.sgid() {
|
||||
return_errno_with_message!(
|
||||
Errno::EPERM,
|
||||
"fsuid can only be one of old ruid, old euid and old suid."
|
||||
)
|
||||
}
|
||||
|
||||
self.fsgid.set(fsgid);
|
||||
|
||||
Ok(old_fsgid)
|
||||
}
|
||||
|
||||
pub(super) fn set_egid(&self, egid: Gid) {
|
||||
self.egid.set(egid);
|
||||
}
|
||||
|
||||
pub(super) fn set_sgid(&self, sgid: Gid) {
|
||||
self.sgid.set(sgid);
|
||||
}
|
||||
|
||||
// For `setregid`, rgid can *NOT* be set to old sgid,
|
||||
// while for `setresgid`, ruid can be set to old sgid.
|
||||
fn check_gid_perm(
|
||||
&self,
|
||||
rgid: Option<&Gid>,
|
||||
egid: Option<&Gid>,
|
||||
sgid: Option<&Gid>,
|
||||
rgid_may_be_old_sgid: bool,
|
||||
) -> Result<()> {
|
||||
if self.is_privileged() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some(rgid) = rgid && *rgid != self.rgid() && *rgid != self.egid() && (!rgid_may_be_old_sgid || *rgid != self.sgid()) {
|
||||
return_errno_with_message!(Errno::EPERM, "rgid can only be one of old rgid, old egid (and old sgid).");
|
||||
}
|
||||
|
||||
if let Some(egid) = egid && *egid != self.rgid() && *egid != self.egid() && *egid != self.sgid() {
|
||||
return_errno_with_message!(Errno::EPERM, "egid can only be one of old rgid, old egid and old sgid.")
|
||||
}
|
||||
|
||||
if let Some(sgid) = sgid && *sgid != self.rgid() && *sgid != self.egid() && *sgid != self.sgid() {
|
||||
return_errno_with_message!(Errno::EPERM, "sgid can only be one of old rgid, old egid and old sgid.")
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_resgid_unchecked(&self, rgid: Option<Gid>, egid: Option<Gid>, sgid: Option<Gid>) {
|
||||
if let Some(rgid) = rgid {
|
||||
self.rgid.set(rgid);
|
||||
}
|
||||
|
||||
if let Some(egid) = egid {
|
||||
self.egid.set(egid);
|
||||
}
|
||||
|
||||
if let Some(sgid) = sgid {
|
||||
self.sgid.set(sgid);
|
||||
}
|
||||
}
|
||||
|
||||
// ******* Supplementary groups methods *******
|
||||
pub(super) fn groups(&self) -> RwLockReadGuard<'_, BTreeSet<Gid>> {
|
||||
self.supplementary_gids.read()
|
||||
}
|
||||
|
||||
pub(super) fn groups_mut(&self) -> RwLockWriteGuard<'_, BTreeSet<Gid>> {
|
||||
self.supplementary_gids.write()
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Credentials_ {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
ruid: self.ruid.clone(),
|
||||
euid: self.euid.clone(),
|
||||
suid: self.suid.clone(),
|
||||
fsuid: self.fsuid.clone(),
|
||||
rgid: self.rgid.clone(),
|
||||
egid: self.egid.clone(),
|
||||
sgid: self.sgid.clone(),
|
||||
fsgid: self.fsgid.clone(),
|
||||
supplementary_gids: RwLock::new(self.supplementary_gids.read().clone()),
|
||||
}
|
||||
}
|
||||
}
|
50
services/libs/jinux-std/src/process/credentials/group.rs
Normal file
50
services/libs/jinux-std/src/process/credentials/group.rs
Normal file
@ -0,0 +1,50 @@
|
||||
use core::sync::atomic::{AtomicU32, Ordering};
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Pod, Default, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[repr(C)]
|
||||
pub struct Gid(u32);
|
||||
|
||||
impl Gid {
|
||||
pub const fn new(gid: u32) -> Self {
|
||||
Self(gid)
|
||||
}
|
||||
|
||||
pub const fn new_root() -> Self {
|
||||
Self(ROOT_GID)
|
||||
}
|
||||
|
||||
pub const fn as_u32(&self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub const fn is_root(&self) -> bool {
|
||||
self.0 == ROOT_GID
|
||||
}
|
||||
}
|
||||
|
||||
const ROOT_GID: u32 = 0;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct AtomicGid(AtomicU32);
|
||||
|
||||
impl AtomicGid {
|
||||
pub const fn new(gid: Gid) -> Self {
|
||||
Self(AtomicU32::new(gid.as_u32()))
|
||||
}
|
||||
|
||||
pub fn set(&self, gid: Gid) {
|
||||
self.0.store(gid.as_u32(), Ordering::Relaxed)
|
||||
}
|
||||
|
||||
pub fn get(&self) -> Gid {
|
||||
Gid(self.0.load(Ordering::Relaxed))
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for AtomicGid {
|
||||
fn clone(&self) -> Self {
|
||||
Self(AtomicU32::new(self.0.load(Ordering::Relaxed)))
|
||||
}
|
||||
}
|
45
services/libs/jinux-std/src/process/credentials/mod.rs
Normal file
45
services/libs/jinux-std/src/process/credentials/mod.rs
Normal file
@ -0,0 +1,45 @@
|
||||
mod credentials_;
|
||||
mod group;
|
||||
mod static_cap;
|
||||
mod user;
|
||||
|
||||
use crate::prelude::*;
|
||||
use credentials_::Credentials_;
|
||||
use jinux_rights::{FullOp, ReadOp, WriteOp};
|
||||
|
||||
pub use group::Gid;
|
||||
pub use user::Uid;
|
||||
|
||||
use super::posix_thread::PosixThreadExt;
|
||||
|
||||
/// `Credentials` represents a set of associated numeric user ids (UIDs) and group identifiers (GIDs)
|
||||
/// for a process.
|
||||
/// These identifiers are as follows:
|
||||
/// - real user ID and group ID;
|
||||
/// - effective user ID and group ID;
|
||||
/// - saved-set user ID and saved-set group ID;
|
||||
/// - file system user ID and group ID (Linux-specific);
|
||||
/// - supplementary group IDs.
|
||||
pub struct Credentials<R = FullOp>(Arc<Credentials_>, R);
|
||||
|
||||
/// Gets read-only credentials of current thread.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// This method should only be called in process context.
|
||||
pub fn credentials() -> Credentials<ReadOp> {
|
||||
let current_thread = current_thread!();
|
||||
let posix_thread = current_thread.as_posix_thread().unwrap();
|
||||
posix_thread.credentials()
|
||||
}
|
||||
|
||||
/// Gets write-only credentials of current thread.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// This method should only be called in process context.
|
||||
pub fn credentials_mut() -> Credentials<WriteOp> {
|
||||
let current_thread = current_thread!();
|
||||
let posix_thread = current_thread.as_posix_thread().unwrap();
|
||||
posix_thread.credentials_mut()
|
||||
}
|
248
services/libs/jinux-std/src/process/credentials/static_cap.rs
Normal file
248
services/libs/jinux-std/src/process/credentials/static_cap.rs
Normal file
@ -0,0 +1,248 @@
|
||||
use super::credentials_::Credentials_;
|
||||
use super::{Credentials, Gid, Uid};
|
||||
use crate::prelude::*;
|
||||
use jinux_frame::sync::{RwLockReadGuard, RwLockWriteGuard};
|
||||
use jinux_rights::{Dup, Read, TRights, Write};
|
||||
use jinux_rights_proc::require;
|
||||
|
||||
impl<R: TRights> Credentials<R> {
|
||||
/// Creates a root `Credentials`. This method can only be used when creating the first process
|
||||
pub fn new_root() -> Self {
|
||||
let uid = Uid::new_root();
|
||||
let gid = Gid::new_root();
|
||||
let credentials_ = Arc::new(Credentials_::new(uid, gid));
|
||||
Self(credentials_, R::new())
|
||||
}
|
||||
|
||||
/// Clones a new `Credentials` from an existing `Credentials`.
|
||||
///
|
||||
/// This method requires the `Read` right.
|
||||
#[require(R1 > Read)]
|
||||
pub fn new_from<R1: TRights>(credentials: &Credentials<R1>) -> Self {
|
||||
let credentials_ = Arc::new(credentials.0.as_ref().clone());
|
||||
|
||||
Self(credentials_, R::new())
|
||||
}
|
||||
|
||||
/// Duplicates the capabilities.
|
||||
///
|
||||
/// This method requires the `Dup` right.
|
||||
#[require(R > Dup)]
|
||||
pub fn dup(&self) -> Self {
|
||||
Self(self.0.clone(), self.1)
|
||||
}
|
||||
|
||||
/// Restricts capabilities to a smaller set.
|
||||
#[require(R > R1)]
|
||||
pub fn restrict<R1: TRights>(self) -> Credentials<R1> {
|
||||
let Credentials(credentials_, _) = self;
|
||||
|
||||
Credentials(credentials_, R1::new())
|
||||
}
|
||||
|
||||
// *********** Uid methods **********
|
||||
|
||||
/// Gets real user id.
|
||||
///
|
||||
/// This method requies the `Read` right.
|
||||
#[require(R > Read)]
|
||||
pub fn ruid(&self) -> Uid {
|
||||
self.0.ruid()
|
||||
}
|
||||
|
||||
/// Gets effective user id.
|
||||
///
|
||||
/// This method requies the `Read` right.
|
||||
#[require(R > Read)]
|
||||
pub fn euid(&self) -> Uid {
|
||||
self.0.euid()
|
||||
}
|
||||
|
||||
/// Gets saved-set user id.
|
||||
///
|
||||
/// This method requies the `Read` right.
|
||||
#[require(R > Read)]
|
||||
pub fn suid(&self) -> Uid {
|
||||
self.0.suid()
|
||||
}
|
||||
|
||||
/// Gets file system user id.
|
||||
///
|
||||
/// This method requies the `Read` right.
|
||||
#[require(R > Read)]
|
||||
pub fn fsuid(&self) -> Uid {
|
||||
self.0.fsuid()
|
||||
}
|
||||
|
||||
/// Sets uid. If self is privileged, sets the effective, real, saved-set user ids as `uid`,
|
||||
/// Otherwise, sets effective user id as `uid`.
|
||||
///
|
||||
/// This method requires the `Write` right.
|
||||
#[require(R > Write)]
|
||||
pub fn set_uid(&self, uid: Uid) {
|
||||
self.0.set_uid(uid);
|
||||
}
|
||||
|
||||
/// Sets real, effective user ids as `ruid`, `euid` respectively. if `ruid` or `euid`
|
||||
/// is `None`, the corresponding user id will leave unchanged.
|
||||
///
|
||||
/// This method requires the `Write` right.
|
||||
#[require(R > Write)]
|
||||
pub fn set_reuid(&self, ruid: Option<Uid>, euid: Option<Uid>) -> Result<()> {
|
||||
self.0.set_reuid(ruid, euid)
|
||||
}
|
||||
|
||||
/// Sets real, effective, saved-set user ids as `ruid`, `euid`, `suid` respectively. if
|
||||
/// `ruid`, `euid` or `suid` is `None`, the corresponding user id will leave unchanged.
|
||||
///
|
||||
/// This method requires the `Write` right.
|
||||
#[require(R > Write)]
|
||||
pub fn set_resuid(
|
||||
&self,
|
||||
ruid: Option<Uid>,
|
||||
euid: Option<Uid>,
|
||||
suid: Option<Uid>,
|
||||
) -> Result<()> {
|
||||
self.0.set_resuid(ruid, euid, suid)
|
||||
}
|
||||
|
||||
/// Sets file system user id as `fsuid`. Returns the original file system user id.
|
||||
/// If `fsuid` is None, leaves file system user id unchanged.
|
||||
///
|
||||
/// This method requires the `Write` right.
|
||||
#[require(R > Write)]
|
||||
pub fn set_fsuid(&self, fsuid: Option<Uid>) -> Result<Uid> {
|
||||
self.0.set_fsuid(fsuid)
|
||||
}
|
||||
|
||||
/// Sets effective user id as `euid`. This method should only be used when executing a file
|
||||
/// whose `setuid` bit is set.
|
||||
///
|
||||
/// This method requires the `Write` right.
|
||||
#[require(R > Write)]
|
||||
pub fn set_euid(&self, euid: Uid) {
|
||||
self.0.set_euid(euid);
|
||||
}
|
||||
|
||||
/// Sets saved-set user id as the same of effective user id. This method should only be used when
|
||||
/// executing a new executable file.
|
||||
///
|
||||
/// This method requires the `Write` right.
|
||||
#[require(R > Write)]
|
||||
pub fn reset_suid(&self) {
|
||||
let euid = self.0.euid();
|
||||
self.0.set_suid(euid);
|
||||
}
|
||||
|
||||
// *********** Gid methods **********
|
||||
|
||||
/// Gets real group id.
|
||||
///
|
||||
/// This method requies the `Read` right.
|
||||
#[require(R > Read)]
|
||||
pub fn rgid(&self) -> Gid {
|
||||
self.0.rgid()
|
||||
}
|
||||
|
||||
/// Gets effective group id.
|
||||
///
|
||||
/// This method requies the `Read` right.
|
||||
#[require(R > Read)]
|
||||
pub fn egid(&self) -> Gid {
|
||||
self.0.egid()
|
||||
}
|
||||
|
||||
/// Gets saved-set group id.
|
||||
///
|
||||
/// This method requies the `Read` right.
|
||||
#[require(R > Read)]
|
||||
pub fn sgid(&self) -> Gid {
|
||||
self.0.sgid()
|
||||
}
|
||||
|
||||
/// Gets file system group id.
|
||||
///
|
||||
/// This method requies the `Read` right.
|
||||
#[require(R > Read)]
|
||||
pub fn fsgid(&self) -> Gid {
|
||||
self.0.fsgid()
|
||||
}
|
||||
|
||||
/// Sets gid. If self is privileged, sets the effective, real, saved-set group ids as `gid`,
|
||||
/// Otherwise, sets effective group id as `gid`.
|
||||
///
|
||||
/// This method requires the `Write` right.
|
||||
#[require(R > Write)]
|
||||
pub fn set_gid(&self, gid: Gid) {
|
||||
self.0.set_gid(gid);
|
||||
}
|
||||
|
||||
/// Sets real, effective group ids as `rgid`, `egid` respectively. if `rgid` or `egid`
|
||||
/// is `None`, the corresponding group id will leave unchanged.
|
||||
///
|
||||
/// This method requires the `Write` right.
|
||||
#[require(R > Write)]
|
||||
pub fn set_regid(&self, rgid: Option<Gid>, egid: Option<Gid>) -> Result<()> {
|
||||
self.0.set_regid(rgid, egid)
|
||||
}
|
||||
|
||||
/// Sets real, effective, saved-set group ids as `rgid`, `egid`, `sgid` respectively. if
|
||||
/// `rgid`, `egid` or `sgid` is `None`, the corresponding group id will leave unchanged.
|
||||
///
|
||||
/// This method requires the `Write` right.
|
||||
#[require(R > Write)]
|
||||
pub fn set_resgid(
|
||||
&self,
|
||||
rgid: Option<Gid>,
|
||||
egid: Option<Gid>,
|
||||
sgid: Option<Gid>,
|
||||
) -> Result<()> {
|
||||
self.0.set_resgid(rgid, egid, sgid)
|
||||
}
|
||||
|
||||
/// Sets file system group id as `fsgid`. Returns the original file system group id.
|
||||
/// If `fsgid` is None, leaves file system group id unchanged.
|
||||
///
|
||||
/// This method requires the `Write` right.
|
||||
#[require(R > Write)]
|
||||
pub fn set_fsgid(&self, fsgid: Option<Gid>) -> Result<Gid> {
|
||||
self.0.set_fsgid(fsgid)
|
||||
}
|
||||
|
||||
/// Sets effective group id as `egid`. This method should only be used when executing a file
|
||||
/// whose `setgid` bit is set.
|
||||
///
|
||||
/// This method requires the `Write` right.
|
||||
#[require(R > Write)]
|
||||
pub fn set_egid(&self, egid: Gid) {
|
||||
self.0.set_egid(egid);
|
||||
}
|
||||
|
||||
/// Sets saved-set group id as the same of effective group id. This method should only be used when
|
||||
/// executing a new executable file.
|
||||
///
|
||||
/// This method requires the `Write` right.
|
||||
#[require(R > Write)]
|
||||
pub fn reset_sgid(&self) {
|
||||
let egid = self.0.egid();
|
||||
self.0.set_sgid(egid);
|
||||
}
|
||||
|
||||
// *********** Supplementary group methods **********
|
||||
|
||||
/// Acquires the read lock of supplementary group ids.
|
||||
///
|
||||
/// This method requies the `Read` right.
|
||||
#[require(R > Read)]
|
||||
pub fn groups(&self) -> RwLockReadGuard<'_, BTreeSet<Gid>> {
|
||||
self.0.groups()
|
||||
}
|
||||
|
||||
/// Acquires the write lock of supplementary group ids.
|
||||
///
|
||||
/// This method requires the `Write` right.
|
||||
#[require(R > Write)]
|
||||
pub fn groups_mut(&self) -> RwLockWriteGuard<'_, BTreeSet<Gid>> {
|
||||
self.0.groups_mut()
|
||||
}
|
||||
}
|
54
services/libs/jinux-std/src/process/credentials/user.rs
Normal file
54
services/libs/jinux-std/src/process/credentials/user.rs
Normal file
@ -0,0 +1,54 @@
|
||||
use core::sync::atomic::{AtomicU32, Ordering};
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Pod)]
|
||||
#[repr(C)]
|
||||
pub struct Uid(u32);
|
||||
|
||||
const ROOT_UID: u32 = 0;
|
||||
|
||||
impl Uid {
|
||||
pub const fn new_root() -> Self {
|
||||
Self(ROOT_UID)
|
||||
}
|
||||
|
||||
pub const fn new(uid: u32) -> Self {
|
||||
Self(uid)
|
||||
}
|
||||
|
||||
pub const fn is_root(&self) -> bool {
|
||||
self.0 == ROOT_UID
|
||||
}
|
||||
|
||||
pub const fn as_u32(&self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct AtomicUid(AtomicU32);
|
||||
|
||||
impl AtomicUid {
|
||||
pub const fn new(uid: Uid) -> Self {
|
||||
Self(AtomicU32::new(uid.as_u32()))
|
||||
}
|
||||
|
||||
pub fn set(&self, uid: Uid) {
|
||||
self.0.store(uid.as_u32(), Ordering::Release)
|
||||
}
|
||||
|
||||
pub fn get(&self) -> Uid {
|
||||
Uid(self.0.load(Ordering::Acquire))
|
||||
}
|
||||
|
||||
pub fn is_root(&self) -> bool {
|
||||
self.get().is_root()
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for AtomicUid {
|
||||
fn clone(&self) -> Self {
|
||||
Self(AtomicU32::new(self.0.load(Ordering::Acquire)))
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user