Compare commits
2 Commits
71915916a0
...
3ef3a8b3aa
Author | SHA1 | Date | |
---|---|---|---|
3ef3a8b3aa | |||
6c0b7cb787 |
@ -1,3 +1,4 @@
|
|||||||
|
use crate::{bitflags::BitFlags, mode::Bit};
|
||||||
use super::Cmd;
|
use super::Cmd;
|
||||||
use clap::{Arg, Command};
|
use clap::{Arg, Command};
|
||||||
use std::{env, fs::File, io, os::unix::prelude::MetadataExt, path::PathBuf, process};
|
use std::{env, fs::File, io, os::unix::prelude::MetadataExt, path::PathBuf, process};
|
||||||
@ -60,10 +61,10 @@ fn which(command: &str, path: &[&str]) -> Option<String> {
|
|||||||
let myuid = unsafe { libc::geteuid() };
|
let myuid = unsafe { libc::geteuid() };
|
||||||
let mygroups = crate::pw::get_gids();
|
let mygroups = crate::pw::get_gids();
|
||||||
// we own the file and it has u+x
|
// we own the file and it has u+x
|
||||||
if myuid == meta.uid() && mode & 0o100 != 0 {
|
if myuid == meta.uid() && mode.contains(Bit::UExec) {
|
||||||
return Some(format!("{}", file.display()));
|
return Some(format!("{}", file.display()));
|
||||||
// file has ug+x
|
// file has ug+x
|
||||||
} else if mode & 0o110 != 0 {
|
} else if mode.contains(Bit::UExec | Bit::GExec) {
|
||||||
if let Ok(groups) = mygroups {
|
if let Ok(groups) = mygroups {
|
||||||
// one of our groups owns the file
|
// one of our groups owns the file
|
||||||
if groups.contains(&meta.gid()) {
|
if groups.contains(&meta.gid()) {
|
||||||
|
99
src/mode/bit.rs
Normal file
99
src/mode/bit.rs
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
use crate::bitflags::BitFlags;
|
||||||
|
use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign};
|
||||||
|
|
||||||
|
/// Unix permission bit flags
|
||||||
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
|
pub enum Bit {
|
||||||
|
Suid = 0o4000,
|
||||||
|
Sgid = 0o2000,
|
||||||
|
Sticky = 0o1000,
|
||||||
|
URead = 0o400,
|
||||||
|
UWrite = 0o200,
|
||||||
|
UExec = 0o100,
|
||||||
|
GRead = 0o40,
|
||||||
|
GWrite = 0o20,
|
||||||
|
GExec = 0o10,
|
||||||
|
ORead = 0o4,
|
||||||
|
OWrite = 0o2,
|
||||||
|
OExec = 0o1,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitAnd<u32> for Bit {
|
||||||
|
type Output = u32;
|
||||||
|
|
||||||
|
fn bitand(self, rhs: u32) -> Self::Output {
|
||||||
|
self as u32 & rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitAnd<Bit> for u32 {
|
||||||
|
type Output = u32;
|
||||||
|
|
||||||
|
fn bitand(self, rhs: Bit) -> Self::Output {
|
||||||
|
self & rhs as u32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitAnd for Bit {
|
||||||
|
type Output = u32;
|
||||||
|
|
||||||
|
fn bitand(self, rhs: Self) -> Self::Output {
|
||||||
|
self as u32 & rhs as u32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitAndAssign<Bit> for u32 {
|
||||||
|
fn bitand_assign(&mut self, rhs: Bit) {
|
||||||
|
*self = *self & rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitOr<u32> for Bit {
|
||||||
|
type Output = u32;
|
||||||
|
|
||||||
|
fn bitor(self, rhs: u32) -> Self::Output {
|
||||||
|
self as u32 | rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitOr<Bit> for u32 {
|
||||||
|
type Output = u32;
|
||||||
|
|
||||||
|
fn bitor(self, rhs: Bit) -> Self::Output {
|
||||||
|
self | rhs as u32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitOr for Bit {
|
||||||
|
type Output = u32;
|
||||||
|
|
||||||
|
fn bitor(self, rhs: Self) -> Self::Output {
|
||||||
|
self as u32 | rhs as u32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitOrAssign<Bit> for u32 {
|
||||||
|
fn bitor_assign(&mut self, rhs: Bit) {
|
||||||
|
*self = *self | rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Bit {
|
||||||
|
pub fn as_char(&self, mode: u32) -> char {
|
||||||
|
if mode & *self != 0 {
|
||||||
|
match self {
|
||||||
|
Self::Suid | Self::Sgid => 's',
|
||||||
|
Self::Sticky => 't',
|
||||||
|
Self::URead | Self::GRead | Self::ORead => 'r',
|
||||||
|
Self::UWrite | Self::GWrite | Self::OWrite => 'w',
|
||||||
|
Self::UExec if mode.contains(Self::Suid) => 's',
|
||||||
|
Self::GExec if mode.contains(Self::Sgid) => 's',
|
||||||
|
Self::OExec if mode.contains(Self::Sticky) => 't',
|
||||||
|
Self::UExec | Self::GExec | Self::OExec => 'x',
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
'-'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,10 @@
|
|||||||
//! Functions for parsing and managing permissions
|
//! Functions for parsing and managing permissions
|
||||||
|
mod bit;
|
||||||
mod parser;
|
mod parser;
|
||||||
use std::{
|
mod who;
|
||||||
fmt::{self, Write},
|
use std::fmt::{self, Write};
|
||||||
ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub use parser::{ParseError, Parser};
|
pub use {bit::Bit, parser::{ParseError, Parser}, who::Who};
|
||||||
|
|
||||||
/// Gets the umask for the current user
|
/// Gets the umask for the current user
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@ -15,42 +14,6 @@ pub fn get_umask() -> u32 {
|
|||||||
mask
|
mask
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unix permission bit flags
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
|
||||||
pub enum Bit {
|
|
||||||
Suid = 0o4000,
|
|
||||||
Sgid = 0o2000,
|
|
||||||
Sticky = 0o1000,
|
|
||||||
URead = 0o400,
|
|
||||||
UWrite = 0o200,
|
|
||||||
UExec = 0o100,
|
|
||||||
GRead = 0o40,
|
|
||||||
GWrite = 0o20,
|
|
||||||
GExec = 0o10,
|
|
||||||
ORead = 0o4,
|
|
||||||
OWrite = 0o2,
|
|
||||||
OExec = 0o1,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Bit {
|
|
||||||
fn as_char(&self, mode: u32) -> char {
|
|
||||||
if mode & *self != 0 {
|
|
||||||
match self {
|
|
||||||
Self::Suid | Self::Sgid => 's',
|
|
||||||
Self::Sticky => 't',
|
|
||||||
Self::URead | Self::GRead | Self::ORead => 'r',
|
|
||||||
Self::UWrite | Self::GWrite | Self::OWrite => 'w',
|
|
||||||
Self::UExec if mode & Self::Suid != 0 => 's',
|
|
||||||
Self::GExec if mode & Self::Sgid != 0 => 's',
|
|
||||||
Self::OExec if mode & Self::Sticky != 0 => 't',
|
|
||||||
Self::UExec | Self::GExec | Self::OExec => 'x',
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
'-'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Functions for extracting information about Unix modes
|
/// Functions for extracting information about Unix modes
|
||||||
pub trait Mode {
|
pub trait Mode {
|
||||||
/// Returns a string representing permissions in symbolic format
|
/// Returns a string representing permissions in symbolic format
|
||||||
@ -110,50 +73,6 @@ impl Mode for u32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BitAnd<u32> for Bit {
|
|
||||||
type Output = u32;
|
|
||||||
|
|
||||||
fn bitand(self, rhs: u32) -> Self::Output {
|
|
||||||
self as u32 & rhs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BitAnd<Bit> for u32 {
|
|
||||||
type Output = u32;
|
|
||||||
|
|
||||||
fn bitand(self, rhs: Bit) -> Self::Output {
|
|
||||||
self & rhs as u32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BitAndAssign<Bit> for u32 {
|
|
||||||
fn bitand_assign(&mut self, rhs: Bit) {
|
|
||||||
*self = *self & rhs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BitOr<u32> for Bit {
|
|
||||||
type Output = u32;
|
|
||||||
|
|
||||||
fn bitor(self, rhs: u32) -> Self::Output {
|
|
||||||
self as u32 | rhs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BitOr<Bit> for u32 {
|
|
||||||
type Output = u32;
|
|
||||||
|
|
||||||
fn bitor(self, rhs: Bit) -> Self::Output {
|
|
||||||
self | rhs as u32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BitOrAssign<Bit> for u32 {
|
|
||||||
fn bitor_assign(&mut self, rhs: Bit) {
|
|
||||||
*self = *self | rhs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use super::{get_umask, Bit};
|
use crate::bitflags::BitFlags;
|
||||||
|
use super::{get_umask, Bit, Who};
|
||||||
use std::{
|
use std::{
|
||||||
error,
|
error,
|
||||||
fmt::Display,
|
fmt::Display,
|
||||||
num::ParseIntError,
|
num::ParseIntError,
|
||||||
ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Errors which might occur when parsing Unix permissions from a string
|
/// Errors which might occur when parsing Unix permissions from a string
|
||||||
@ -46,45 +46,6 @@ enum Op {
|
|||||||
Equals,
|
Equals,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
|
||||||
/// The granularity of the given permissions
|
|
||||||
enum Who {
|
|
||||||
/// applies for the current user
|
|
||||||
User = 0o100,
|
|
||||||
/// applies for the current group
|
|
||||||
Group = 0o10,
|
|
||||||
/// applies for everyone else
|
|
||||||
Other = 0o1,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BitAnd<Who> for u32 {
|
|
||||||
type Output = u32;
|
|
||||||
|
|
||||||
fn bitand(self, rhs: Who) -> Self::Output {
|
|
||||||
self & rhs as u32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BitAndAssign<Who> for u32 {
|
|
||||||
fn bitand_assign(&mut self, rhs: Who) {
|
|
||||||
*self = *self & rhs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BitOr<Who> for u32 {
|
|
||||||
type Output = u32;
|
|
||||||
|
|
||||||
fn bitor(self, rhs: Who) -> Self::Output {
|
|
||||||
self | rhs as u32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BitOrAssign<Who> for u32 {
|
|
||||||
fn bitor_assign(&mut self, rhs: Who) {
|
|
||||||
*self = *self | rhs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A parser for octal and symbolic permissions. `Parser::default` creates an
|
/// A parser for octal and symbolic permissions. `Parser::default` creates an
|
||||||
/// instance which applies the given operations to the default setting for the
|
/// instance which applies the given operations to the default setting for the
|
||||||
/// current user's umask. `Parser::new` creates a parser which applies the given
|
/// current user's umask. `Parser::new` creates a parser which applies the given
|
||||||
@ -157,13 +118,13 @@ impl Parser {
|
|||||||
if self.op.is_none() {
|
if self.op.is_none() {
|
||||||
Err(ParseError::NoOpSet)
|
Err(ParseError::NoOpSet)
|
||||||
} else {
|
} else {
|
||||||
if self.who & 0o100 != 0 {
|
if self.who.contains(Who::User) {
|
||||||
self.bits |= Bit::URead;
|
self.bits |= Bit::URead;
|
||||||
}
|
}
|
||||||
if self.who & 0o10 != 0 {
|
if self.who.contains(Who::Group) {
|
||||||
self.bits |= Bit::GRead;
|
self.bits |= Bit::GRead;
|
||||||
}
|
}
|
||||||
if self.who & 0o1 != 0 {
|
if self.who.contains(Who::Other) {
|
||||||
self.bits |= Bit::ORead;
|
self.bits |= Bit::ORead;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -174,13 +135,13 @@ impl Parser {
|
|||||||
if self.op.is_none() {
|
if self.op.is_none() {
|
||||||
Err(ParseError::NoOpSet)
|
Err(ParseError::NoOpSet)
|
||||||
} else {
|
} else {
|
||||||
if self.who & 0o100 != 0 {
|
if self.who.contains(Who::User) {
|
||||||
self.bits |= Bit::UWrite;
|
self.bits |= Bit::UWrite;
|
||||||
}
|
}
|
||||||
if self.who & 0o10 != 0 {
|
if self.who.contains(Who::Group) {
|
||||||
self.bits |= Bit::GWrite;
|
self.bits |= Bit::GWrite;
|
||||||
}
|
}
|
||||||
if self.who & 0o1 != 0 {
|
if self.who.contains(Who::Other) {
|
||||||
self.bits |= Bit::OWrite;
|
self.bits |= Bit::OWrite;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -191,13 +152,13 @@ impl Parser {
|
|||||||
if self.op.is_none() {
|
if self.op.is_none() {
|
||||||
Err(ParseError::NoOpSet)
|
Err(ParseError::NoOpSet)
|
||||||
} else {
|
} else {
|
||||||
if self.who & 0o100 != 0 {
|
if self.who.contains(Who::User) {
|
||||||
self.bits |= Bit::UExec;
|
self.bits |= Bit::UExec;
|
||||||
}
|
}
|
||||||
if self.who & 0o10 != 0 {
|
if self.who.contains(Who::Group) {
|
||||||
self.bits |= Bit::GExec;
|
self.bits |= Bit::GExec;
|
||||||
}
|
}
|
||||||
if self.who & 0o1 != 0 {
|
if self.who.contains(Who::Other) {
|
||||||
self.bits |= Bit::OExec;
|
self.bits |= Bit::OExec;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -205,27 +166,27 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn push_suid_sgid(&mut self) -> Result<(), ParseError> {
|
fn push_suid_sgid(&mut self) -> Result<(), ParseError> {
|
||||||
if self.who == 0 || self.who & 0o1 != 0 {
|
if self.who == 0 || self.who.contains(Who::Other) {
|
||||||
return Err(ParseError::InvalidBit);
|
return Err(ParseError::InvalidBit);
|
||||||
} else if self.op.is_none() {
|
} else if self.op.is_none() {
|
||||||
return Err(ParseError::NoOpSet);
|
return Err(ParseError::NoOpSet);
|
||||||
}
|
}
|
||||||
if self.who & 0o100 != 0 {
|
if self.who.contains(Who::User) {
|
||||||
self.bits |= Bit::Suid;
|
self.bits |= Bit::Suid;
|
||||||
}
|
}
|
||||||
if self.who & 0o10 != 0 {
|
if self.who.contains(Who::Group) {
|
||||||
self.bits |= Bit::Sgid;
|
self.bits |= Bit::Sgid;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_sticky(&mut self) -> Result<(), ParseError> {
|
fn push_sticky(&mut self) -> Result<(), ParseError> {
|
||||||
if self.who == 0 || self.who & 0o100 != 0 || self.who & 0o10 != 0 {
|
if self.who == 0 || self.who.contains(Who::User) || self.who.contains(Who::Group) {
|
||||||
return Err(ParseError::InvalidBit);
|
return Err(ParseError::InvalidBit);
|
||||||
} else if self.op.is_none() {
|
} else if self.op.is_none() {
|
||||||
return Err(ParseError::NoOpSet);
|
return Err(ParseError::NoOpSet);
|
||||||
}
|
}
|
||||||
if self.who & 0o1 != 0 {
|
if self.who.contains(Who::Other) {
|
||||||
self.bits |= Bit::Sticky;
|
self.bits |= Bit::Sticky;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -244,13 +205,13 @@ impl Parser {
|
|||||||
Some(Op::Add) => self.add_bits(),
|
Some(Op::Add) => self.add_bits(),
|
||||||
Some(Op::Remove) => self.remove_bits(),
|
Some(Op::Remove) => self.remove_bits(),
|
||||||
Some(Op::Equals) => {
|
Some(Op::Equals) => {
|
||||||
if self.who & 0o100 != 0 {
|
if self.who.contains(Who::User) {
|
||||||
self.mode &= !(0o4700);
|
self.mode &= !(0o4700);
|
||||||
}
|
}
|
||||||
if self.who & 0o10 != 0 {
|
if self.who.contains(Who::Group) {
|
||||||
self.mode &= !(0o2070);
|
self.mode &= !(0o2070);
|
||||||
}
|
}
|
||||||
if self.who & 0o1 != 0 {
|
if self.who.contains(Who::Other) {
|
||||||
self.mode &= !(0o1007);
|
self.mode &= !(0o1007);
|
||||||
}
|
}
|
||||||
self.add_bits();
|
self.add_bits();
|
||||||
|
49
src/mode/who.rs
Normal file
49
src/mode/who.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign};
|
||||||
|
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
/// The granularity of the given permissions
|
||||||
|
pub enum Who {
|
||||||
|
/// applies for the current user
|
||||||
|
User = 0o100,
|
||||||
|
/// applies for the current group
|
||||||
|
Group = 0o10,
|
||||||
|
/// applies for everyone else
|
||||||
|
Other = 0o1,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitAnd<Who> for u32 {
|
||||||
|
type Output = u32;
|
||||||
|
|
||||||
|
fn bitand(self, rhs: Who) -> Self::Output {
|
||||||
|
self & rhs as u32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitAnd<u32> for Who {
|
||||||
|
type Output = u32;
|
||||||
|
|
||||||
|
fn bitand(self, rhs: u32) -> Self::Output {
|
||||||
|
self as u32 & rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitAndAssign<Who> for u32 {
|
||||||
|
fn bitand_assign(&mut self, rhs: Who) {
|
||||||
|
*self = *self & rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitOr<Who> for u32 {
|
||||||
|
type Output = u32;
|
||||||
|
|
||||||
|
fn bitor(self, rhs: Who) -> Self::Output {
|
||||||
|
self | rhs as u32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitOrAssign<Who> for u32 {
|
||||||
|
fn bitor_assign(&mut self, rhs: Who) {
|
||||||
|
*self = *self | rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user