Merge branch 'develop'
This commit is contained in:
commit
2160fcea46
|
@ -1,4 +1,4 @@
|
||||||
*
|
*
|
||||||
!CMakeLists.txt
|
!src
|
||||||
!setcap.c
|
!Cargo.toml
|
||||||
!config.h.in
|
!Cargo.lock
|
|
@ -1,2 +1,209 @@
|
||||||
/.vscode
|
# Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode,intellij+all,windows,linux,macos,rust,rust-analyzer
|
||||||
/build
|
# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode,intellij+all,windows,linux,macos,rust,rust-analyzer
|
||||||
|
|
||||||
|
### Intellij+all ###
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
# User-specific stuff
|
||||||
|
.idea/**/workspace.xml
|
||||||
|
.idea/**/tasks.xml
|
||||||
|
.idea/**/usage.statistics.xml
|
||||||
|
.idea/**/dictionaries
|
||||||
|
.idea/**/shelf
|
||||||
|
|
||||||
|
# AWS User-specific
|
||||||
|
.idea/**/aws.xml
|
||||||
|
|
||||||
|
# Generated files
|
||||||
|
.idea/**/contentModel.xml
|
||||||
|
|
||||||
|
# Sensitive or high-churn files
|
||||||
|
.idea/**/dataSources/
|
||||||
|
.idea/**/dataSources.ids
|
||||||
|
.idea/**/dataSources.local.xml
|
||||||
|
.idea/**/sqlDataSources.xml
|
||||||
|
.idea/**/dynamic.xml
|
||||||
|
.idea/**/uiDesigner.xml
|
||||||
|
.idea/**/dbnavigator.xml
|
||||||
|
|
||||||
|
# Gradle
|
||||||
|
.idea/**/gradle.xml
|
||||||
|
.idea/**/libraries
|
||||||
|
|
||||||
|
# Gradle and Maven with auto-import
|
||||||
|
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||||
|
# since they will be recreated, and may cause churn. Uncomment if using
|
||||||
|
# auto-import.
|
||||||
|
# .idea/artifacts
|
||||||
|
# .idea/compiler.xml
|
||||||
|
# .idea/jarRepositories.xml
|
||||||
|
# .idea/modules.xml
|
||||||
|
# .idea/*.iml
|
||||||
|
# .idea/modules
|
||||||
|
# *.iml
|
||||||
|
# *.ipr
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
cmake-build-*/
|
||||||
|
|
||||||
|
# Mongo Explorer plugin
|
||||||
|
.idea/**/mongoSettings.xml
|
||||||
|
|
||||||
|
# File-based project format
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
out/
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Cursive Clojure plugin
|
||||||
|
.idea/replstate.xml
|
||||||
|
|
||||||
|
# SonarLint plugin
|
||||||
|
.idea/sonarlint/
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
||||||
|
|
||||||
|
# Editor-based Rest Client
|
||||||
|
.idea/httpRequests
|
||||||
|
|
||||||
|
# Android studio 3.1+ serialized cache file
|
||||||
|
.idea/caches/build_file_checksums.ser
|
||||||
|
|
||||||
|
### Intellij+all Patch ###
|
||||||
|
# Ignore everything but code style settings and run configurations
|
||||||
|
# that are supposed to be shared within teams.
|
||||||
|
|
||||||
|
.idea/*
|
||||||
|
|
||||||
|
!.idea/codeStyles
|
||||||
|
!.idea/runConfigurations
|
||||||
|
|
||||||
|
### Linux ###
|
||||||
|
*~
|
||||||
|
|
||||||
|
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||||
|
.fuse_hidden*
|
||||||
|
|
||||||
|
# KDE directory preferences
|
||||||
|
.directory
|
||||||
|
|
||||||
|
# Linux trash folder which might appear on any partition or disk
|
||||||
|
.Trash-*
|
||||||
|
|
||||||
|
# .nfs files are created when an open file is removed but is still being accessed
|
||||||
|
.nfs*
|
||||||
|
|
||||||
|
### macOS ###
|
||||||
|
# General
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# Icon must end with two \r
|
||||||
|
Icon
|
||||||
|
|
||||||
|
|
||||||
|
# Thumbnails
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Files that might appear in the root of a volume
|
||||||
|
.DocumentRevisions-V100
|
||||||
|
.fseventsd
|
||||||
|
.Spotlight-V100
|
||||||
|
.TemporaryItems
|
||||||
|
.Trashes
|
||||||
|
.VolumeIcon.icns
|
||||||
|
.com.apple.timemachine.donotpresent
|
||||||
|
|
||||||
|
# Directories potentially created on remote AFP share
|
||||||
|
.AppleDB
|
||||||
|
.AppleDesktop
|
||||||
|
Network Trash Folder
|
||||||
|
Temporary Items
|
||||||
|
.apdisk
|
||||||
|
|
||||||
|
### macOS Patch ###
|
||||||
|
# iCloud generated files
|
||||||
|
*.icloud
|
||||||
|
|
||||||
|
### Rust ###
|
||||||
|
# Generated by Cargo
|
||||||
|
# will have compiled files and executables
|
||||||
|
debug/
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||||
|
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||||
|
Cargo.lock
|
||||||
|
|
||||||
|
# These are backup files generated by rustfmt
|
||||||
|
**/*.rs.bk
|
||||||
|
|
||||||
|
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||||
|
*.pdb
|
||||||
|
|
||||||
|
### rust-analyzer ###
|
||||||
|
# Can be generated by other build systems other than cargo (ex: bazelbuild/rust_rules)
|
||||||
|
rust-project.json
|
||||||
|
|
||||||
|
|
||||||
|
### VisualStudioCode ###
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
!.vscode/*.code-snippets
|
||||||
|
|
||||||
|
# Local History for Visual Studio Code
|
||||||
|
.history/
|
||||||
|
|
||||||
|
# Built Visual Studio Code Extensions
|
||||||
|
*.vsix
|
||||||
|
|
||||||
|
### VisualStudioCode Patch ###
|
||||||
|
# Ignore all local history of files
|
||||||
|
.history
|
||||||
|
.ionide
|
||||||
|
|
||||||
|
### Windows ###
|
||||||
|
# Windows thumbnail cache files
|
||||||
|
Thumbs.db
|
||||||
|
Thumbs.db:encryptable
|
||||||
|
ehthumbs.db
|
||||||
|
ehthumbs_vista.db
|
||||||
|
|
||||||
|
# Dump file
|
||||||
|
*.stackdump
|
||||||
|
|
||||||
|
# Folder config file
|
||||||
|
[Dd]esktop.ini
|
||||||
|
|
||||||
|
# Recycle Bin used on file shares
|
||||||
|
$RECYCLE.BIN/
|
||||||
|
|
||||||
|
# Windows Installer files
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msix
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# Windows shortcuts
|
||||||
|
*.lnk
|
||||||
|
|
||||||
|
# End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,intellij+all,windows,linux,macos,rust,rust-analyzer
|
||||||
|
|
||||||
|
/target
|
||||||
|
/setcap-static
|
|
@ -0,0 +1,27 @@
|
||||||
|
[package]
|
||||||
|
name = "setcap-static"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libc = { version = "0.2", default-features = false }
|
||||||
|
libc-print = "0.1.22"
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
# This isn't required for development builds, but makes development
|
||||||
|
# build behavior match release builds. To enable unwinding panics
|
||||||
|
# during development, simply remove this line.
|
||||||
|
panic = "abort"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
#opt-level = 'z' # Optimize for size.
|
||||||
|
lto = true # Enable Link Time Optimization
|
||||||
|
codegen-units = 1 # Reduce number of codegen units to increase optimizations.
|
||||||
|
panic = 'abort' # Abort on panic
|
||||||
|
strip = true # Strip symbols from binary*
|
||||||
|
debug-assertions = false
|
||||||
|
debug = false
|
||||||
|
rpath = false
|
||||||
|
incremental = false
|
36
Dockerfile
36
Dockerfile
|
@ -1,11 +1,29 @@
|
||||||
FROM harbor.repository.lb.home.dc.internal.amuz.es/infrastructure/alpine-base:3.19-latest AS build
|
#syntax=docker/dockerfile:1
|
||||||
RUN apk add --no-cache cmake make musl-dev gcc libcap-static libcap-dev
|
|
||||||
WORKDIR /build
|
##
|
||||||
COPY . .
|
## Build
|
||||||
RUN \
|
##
|
||||||
cmake -S . -B build -DCMAKE_BUILD_TYPE=MinSizeRel && \
|
FROM rust:1-alpine3.19 AS build
|
||||||
cmake --build build --config MinSizeRel && \
|
LABEL org.opencontainers.image.authors="Sangbum Kim <sangbumkim@amuz.es>"
|
||||||
strip build/setcap-static
|
|
||||||
|
# set the workdir and copy the source into it
|
||||||
|
WORKDIR /app
|
||||||
|
COPY . /app
|
||||||
|
|
||||||
|
ENV RUSTFLAGS='-C link-arg=-s -C link-arg=-fuse-ld=lld'
|
||||||
|
|
||||||
|
RUN set -x && \
|
||||||
|
apk add --no-cache \
|
||||||
|
libcap-static \
|
||||||
|
libcap-dev \
|
||||||
|
lld \
|
||||||
|
musl-dev &&\
|
||||||
|
cargo build --release && \
|
||||||
|
ldd target/release/setcap-static
|
||||||
|
|
||||||
|
# RUN --mount=type=bind,rw,source=.,target=/host \
|
||||||
|
# cp -avf target/release/setcap-static /host/setcap-static
|
||||||
|
|
||||||
|
|
||||||
FROM scratch
|
FROM scratch
|
||||||
COPY --from=build /build/build/setcap-static /setcap-static
|
COPY --from=build /app/target/release/setcap-static /setcap-static
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
#syntax=docker/dockerfile:1
|
||||||
|
|
||||||
|
##
|
||||||
|
## Build
|
||||||
|
##
|
||||||
|
FROM rust:1-slim AS build
|
||||||
|
LABEL org.opencontainers.image.authors="Sangbum Kim <sangbumkim@amuz.es>"
|
||||||
|
|
||||||
|
# set the workdir and copy the source into it
|
||||||
|
WORKDIR /app
|
||||||
|
COPY . /app
|
||||||
|
|
||||||
|
# ENV RUSTFLAGS='-C link-arg=-s -C linker=rust-lld -C link-arg=-fuse-ld=lld'
|
||||||
|
# ENV RUSTFLAGS='-C link-arg=-s -C link-arg=-fuse-ld=lld'
|
||||||
|
# ENV RUSTFLAGS='-C target-feature=+crt-static -C link-arg=-s -C link-args=-nostartfiles -C link-arg=-nostdlib'
|
||||||
|
# ENV RUSTFLAGS='-C target-feature=+crt-static -C link-arg=-s'
|
||||||
|
# ENV RUSTFLAGS='-C target-feature=+crt-static -C link-arg=-s'
|
||||||
|
# ENV RUSTFLAGS='-C target-feature=+crt-static -C link-arg=-static -C link-arg=-s'
|
||||||
|
# ENV RUSTFLAGS='-C target-feature=+crt-static -C link-arg=-static -C link-arg=-s -C link-arg=-fuse-ld=lld'
|
||||||
|
ENV RUSTFLAGS='-C target-feature=+crt-static -C link-arg=-s -C link-arg=-fuse-ld=lld'
|
||||||
|
|
||||||
|
# do a release build
|
||||||
|
RUN set -x && \
|
||||||
|
apt update && \
|
||||||
|
apt install -y \
|
||||||
|
# libcap2 \
|
||||||
|
lld \
|
||||||
|
libcap-dev \
|
||||||
|
&&\
|
||||||
|
cargo build --release && \
|
||||||
|
ldd target/release/rsetcap
|
||||||
|
|
||||||
|
RUN --mount=type=bind,rw,source=.,target=/host \
|
||||||
|
cp -avf target/release/rsetcap /host/rsetcap
|
||||||
|
|
||||||
|
|
||||||
|
# FROM scratch
|
||||||
|
# COPY --from=build /build/build/setcap-static /setcap-static
|
|
@ -0,0 +1,2 @@
|
||||||
|
*
|
||||||
|
!src
|
|
@ -0,0 +1,2 @@
|
||||||
|
/.vscode
|
||||||
|
/build
|
|
@ -0,0 +1,16 @@
|
||||||
|
FROM harbor.repository.lb.home.dc.internal.amuz.es/infrastructure/alpine-base:3.19-latest AS build
|
||||||
|
RUN apk add --no-cache cmake make musl-dev gcc libcap-static libcap-dev
|
||||||
|
WORKDIR /build
|
||||||
|
|
||||||
|
COPY src/ ./
|
||||||
|
|
||||||
|
RUN \
|
||||||
|
cmake -S . -B build -DCMAKE_BUILD_TYPE=MinSizeRel && \
|
||||||
|
cmake --build build --config MinSizeRel && \
|
||||||
|
strip build/setcap-static
|
||||||
|
|
||||||
|
RUN --mount=type=bind,rw,source=.,target=/host \
|
||||||
|
cp -avf build/setcap-static /host/setcap-static
|
||||||
|
|
||||||
|
FROM scratch
|
||||||
|
COPY --from=build /build/build/setcap-static /setcap-static
|
|
@ -0,0 +1,133 @@
|
||||||
|
use core::ffi::CStr;
|
||||||
|
use libc::c_char;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub struct Args {
|
||||||
|
argc: usize,
|
||||||
|
argv: *const *const u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Args {
|
||||||
|
///Creates new instance, but verifies that each string inside are UTF-8.
|
||||||
|
///
|
||||||
|
///On error returns pair: `(string index, Utf8Error)`
|
||||||
|
///
|
||||||
|
///The function is safe as long as you pass C style main function arguments.
|
||||||
|
pub unsafe fn new(
|
||||||
|
argc: isize,
|
||||||
|
argv: *const *const u8,
|
||||||
|
) -> Result<Self, (usize, core::str::Utf8Error)> {
|
||||||
|
assert!(argc > 0);
|
||||||
|
assert!(!argv.is_null());
|
||||||
|
|
||||||
|
let this = Args {
|
||||||
|
argc: argc as usize,
|
||||||
|
argv,
|
||||||
|
};
|
||||||
|
|
||||||
|
let args = this.as_slice();
|
||||||
|
for idx in 0..this.argc {
|
||||||
|
let arg = *args.get_unchecked(idx);
|
||||||
|
if let Err(error) = c_str_to_rust(arg) {
|
||||||
|
return Err((idx, error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
///Unchecked version of `Args::new`
|
||||||
|
///
|
||||||
|
///Do it on your own risk
|
||||||
|
pub unsafe fn new_unchecked(argc: isize, argv: *const *const u8) -> Self {
|
||||||
|
Args {
|
||||||
|
argc: argc as usize,
|
||||||
|
argv,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
///Returns slice of raw C strings
|
||||||
|
pub fn as_slice(&self) -> &[*const u8] {
|
||||||
|
unsafe { core::slice::from_raw_parts(self.argv, self.argc) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
///Retrieves string by index.
|
||||||
|
///
|
||||||
|
///No checks, 100% unsafe.
|
||||||
|
pub unsafe fn get_str_by_index(&self, index: usize) -> &str {
|
||||||
|
let elem = *self.as_slice().get_unchecked(index);
|
||||||
|
c_str_to_rust_unchecked(elem)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn get_cstr_by_index(&self, index: usize) -> &CStr {
|
||||||
|
let elem = *self.as_slice().get_unchecked(index);
|
||||||
|
CStr::from_ptr(elem as *const c_char)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> IntoIterator for &'a Args {
|
||||||
|
type Item = &'a str;
|
||||||
|
type IntoIter = IntoIter<'a>;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
Self::IntoIter {
|
||||||
|
inner: self,
|
||||||
|
index: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///Iterator over [Args](struct.Args.html)
|
||||||
|
///
|
||||||
|
///Comparing to normal iterators can be iterated back and forth.
|
||||||
|
pub struct IntoIter<'a> {
|
||||||
|
inner: &'a Args,
|
||||||
|
index: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for IntoIter<'a> {
|
||||||
|
type Item = &'a str;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if self.index >= self.inner.argc {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let elem = unsafe { self.inner.get_str_by_index(self.index) };
|
||||||
|
self.index += 1;
|
||||||
|
Some(elem)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
let count = self.inner.argc - self.index;
|
||||||
|
(count, Some(count))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn count(self) -> usize {
|
||||||
|
self.inner.argc - self.index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///Converts C string to Rust's, verifying it is UTF-8
|
||||||
|
///
|
||||||
|
///It is UB to pass non-C string as it requires \0
|
||||||
|
unsafe fn c_str_to_rust(ptr: *const u8) -> Result<&'static str, core::str::Utf8Error> {
|
||||||
|
let len = libc::strlen(ptr as *const i8);
|
||||||
|
let parts = core::slice::from_raw_parts(ptr, len);
|
||||||
|
core::str::from_utf8(parts)
|
||||||
|
}
|
||||||
|
|
||||||
|
///Converts C string to Rust's one assuming it is UTF-8
|
||||||
|
///
|
||||||
|
///It is UB to pass non-C string as it requires \0
|
||||||
|
unsafe fn c_str_to_rust_unchecked(ptr: *const u8) -> &'static str {
|
||||||
|
let len = libc::strlen(ptr as *const i8);
|
||||||
|
let parts = core::slice::from_raw_parts(ptr, len);
|
||||||
|
core::str::from_utf8_unchecked(parts)
|
||||||
|
}
|
|
@ -0,0 +1,129 @@
|
||||||
|
#![allow(
|
||||||
|
dead_code,
|
||||||
|
non_snake_case,
|
||||||
|
non_camel_case_types,
|
||||||
|
non_upper_case_globals
|
||||||
|
)]
|
||||||
|
|
||||||
|
use libc::{c_char, c_int, c_uint, c_void, uid_t};
|
||||||
|
|
||||||
|
#[repr(i32)]
|
||||||
|
pub(crate) enum Value {
|
||||||
|
CAP_CHOWN,
|
||||||
|
CAP_DAC_OVERRIDE,
|
||||||
|
CAP_DAC_READ_SEARCH,
|
||||||
|
CAP_FOWNER,
|
||||||
|
CAP_FSETID,
|
||||||
|
CAP_KILL,
|
||||||
|
CAP_SETGID,
|
||||||
|
CAP_SETUID,
|
||||||
|
CAP_SETPCAP,
|
||||||
|
CAP_LINUX_IMMUTABLE,
|
||||||
|
CAP_NET_BIND_SERVICE,
|
||||||
|
CAP_NET_BROADCAST,
|
||||||
|
CAP_NET_ADMIN,
|
||||||
|
CAP_NET_RAW,
|
||||||
|
CAP_IPC_LOCK,
|
||||||
|
CAP_IPC_OWNER,
|
||||||
|
CAP_SYS_MODULE,
|
||||||
|
CAP_SYS_RAWIO,
|
||||||
|
CAP_SYS_CHROOT,
|
||||||
|
CAP_SYS_PTRACE,
|
||||||
|
CAP_SYS_PACCT,
|
||||||
|
CAP_SYS_ADMIN,
|
||||||
|
CAP_SYS_BOOT,
|
||||||
|
CAP_SYS_NICE,
|
||||||
|
CAP_SYS_RESOURCE,
|
||||||
|
CAP_SYS_TIME,
|
||||||
|
CAP_SYS_TTY_CONFIG,
|
||||||
|
CAP_MKNOD,
|
||||||
|
CAP_LEASE,
|
||||||
|
CAP_AUDIT_WRITE,
|
||||||
|
CAP_AUDIT_CONTROL,
|
||||||
|
CAP_SETFCAP,
|
||||||
|
CAP_MAC_OVERRIDE,
|
||||||
|
CAP_MAC_ADMIN,
|
||||||
|
CAP_SYSLOG,
|
||||||
|
CAP_WAKE_ALARM,
|
||||||
|
CAP_BLOCK_SUSPEND,
|
||||||
|
CAP_AUDIT_READ,
|
||||||
|
CAP_PERFMON,
|
||||||
|
CAP_BPF,
|
||||||
|
CAP_CHECKPOINT_RESTORE,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<cap_value_t> for Value {
|
||||||
|
fn into(self) -> cap_value_t {
|
||||||
|
self as cap_value_t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(u32)]
|
||||||
|
pub(crate) enum Flag {
|
||||||
|
CAP_EFFECTIVE,
|
||||||
|
CAP_PERMITTED,
|
||||||
|
CAP_INHERITABLE,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<cap_flag_t> for Flag {
|
||||||
|
fn into(self) -> cap_flag_t {
|
||||||
|
self as cap_flag_t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(u32)]
|
||||||
|
pub(crate) enum FlagValue {
|
||||||
|
CAP_CLEAR,
|
||||||
|
CAP_SET,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<cap_flag_t> for FlagValue {
|
||||||
|
fn into(self) -> cap_flag_value_t {
|
||||||
|
self as cap_flag_value_t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub(crate) struct cap_t {
|
||||||
|
pub __user_cap_header_struct: cap_user_header_t,
|
||||||
|
pub __user_cap_data_struct: [cap_user_data_t; 2usize],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
|
||||||
|
pub(crate) struct cap_user_header_t {
|
||||||
|
pub version: u32,
|
||||||
|
pub pid: ::libc::c_int,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub(crate) struct cap_user_data_t {
|
||||||
|
pub effective: c_uint,
|
||||||
|
pub permitted: c_uint,
|
||||||
|
pub inheritable: c_uint,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) type cap_flag_t = c_uint;
|
||||||
|
pub(crate) type cap_value_t = c_int;
|
||||||
|
pub(crate) type cap_flag_value_t = c_uint;
|
||||||
|
|
||||||
|
// #[link(name = "cap", kind = "dylib")]
|
||||||
|
#[link(name = "cap", kind = "static")]
|
||||||
|
extern "C" {
|
||||||
|
pub(crate) fn cap_get_proc() -> *mut cap_t;
|
||||||
|
pub(crate) fn cap_from_text(arg1: *const c_char) -> *mut cap_t;
|
||||||
|
pub(crate) fn cap_set_nsowner(target_caps: *mut cap_t, uid: uid_t) -> c_int;
|
||||||
|
pub(crate) fn cap_set_flag(
|
||||||
|
arg1: *mut cap_t,
|
||||||
|
arg2: cap_flag_t,
|
||||||
|
arg3: ::libc::c_int,
|
||||||
|
arg4: *const cap_value_t,
|
||||||
|
arg5: cap_flag_value_t,
|
||||||
|
) -> ::libc::c_int;
|
||||||
|
pub(crate) fn cap_set_proc(arg1: *const cap_t) -> c_int;
|
||||||
|
pub(crate) fn cap_set_file(arg1: *const c_char, arg2: *const cap_t) -> c_int;
|
||||||
|
pub(crate) fn cap_free(arg1: *mut c_void) -> c_int;
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
#![allow(non_camel_case_types, dead_code)]
|
||||||
|
|
||||||
|
use libc::FILE;
|
||||||
|
|
||||||
|
#[link(name = "c")]
|
||||||
|
extern "C" {
|
||||||
|
static stdin: *mut FILE;
|
||||||
|
static stdout: *mut FILE;
|
||||||
|
static stderr: *mut FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
#[inline(never)]
|
||||||
|
#[cfg(not(test))]
|
||||||
|
unsafe fn panic_handler(_: &core::panic::PanicInfo) -> ! {
|
||||||
|
libc::exit(2)
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
#![allow(non_camel_case_types, dead_code)]
|
||||||
|
|
||||||
|
use libc::{c_int, exit, FILE};
|
||||||
|
|
||||||
|
#[repr(C, align(16))]
|
||||||
|
struct f128 {
|
||||||
|
a: [u8; 16],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn __letf2(_a: f128, _b: f128) -> c_int {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn __unordtf2(_a: f128, _b: f128) -> c_int {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
unsafe extern "C" fn _Unwind_Resume() -> ! {
|
||||||
|
exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn __gcc_personality_v0() {}
|
|
@ -0,0 +1,104 @@
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
mod args;
|
||||||
|
mod caps;
|
||||||
|
mod link;
|
||||||
|
|
||||||
|
use args::Args;
|
||||||
|
use libc::{c_int, c_void, unlink, EXIT_FAILURE, EXIT_SUCCESS};
|
||||||
|
use libc_print::std_name::eprintln;
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
unsafe extern "C" fn main(argc: c_int, argv: *const *const u8) -> c_int {
|
||||||
|
match argc {
|
||||||
|
3 => (),
|
||||||
|
1 => return EXIT_SUCCESS,
|
||||||
|
_ => {
|
||||||
|
eprintln!("Usage: setcap capabilities filename");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let arg = match Args::new(argc as isize, argv) {
|
||||||
|
Ok(arg) => arg,
|
||||||
|
Err((valid_up_to, err)) => {
|
||||||
|
match err.error_len() {
|
||||||
|
Some(err_len) => eprintln!(
|
||||||
|
"invalid utf-8 sequence of {} bytes from index {}",
|
||||||
|
err_len, valid_up_to
|
||||||
|
),
|
||||||
|
None => eprintln!("incomplete utf-8 byte sequence from index {}", valid_up_to),
|
||||||
|
};
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let my_caps = caps::cap_get_proc();
|
||||||
|
|
||||||
|
if my_caps.is_null() {
|
||||||
|
eprintln!("cap_get_proc");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
let target_caps = caps::cap_from_text(arg.get_cstr_by_index(1).as_ptr());
|
||||||
|
|
||||||
|
if target_caps.is_null() {
|
||||||
|
eprintln!(
|
||||||
|
"cap_from_text: failed to parse \"{}\"",
|
||||||
|
arg.get_str_by_index(1),
|
||||||
|
);
|
||||||
|
caps::cap_free(my_caps as *mut c_void);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ret = caps::cap_set_nsowner(target_caps, 0);
|
||||||
|
if ret != 0 {
|
||||||
|
eprintln!("cap_set_nsowner: {}", ret);
|
||||||
|
caps::cap_free(my_caps as *mut c_void);
|
||||||
|
caps::cap_free(target_caps as *mut c_void);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
let flag: caps::cap_value_t = caps::Value::CAP_SETFCAP.into();
|
||||||
|
let ret = caps::cap_set_flag(
|
||||||
|
my_caps,
|
||||||
|
caps::Flag::CAP_EFFECTIVE.into(),
|
||||||
|
1,
|
||||||
|
&flag,
|
||||||
|
caps::FlagValue::CAP_SET.into(),
|
||||||
|
);
|
||||||
|
|
||||||
|
if ret != 0 {
|
||||||
|
eprintln!("cap_set_flag(CAP_SETFCAP): {}", ret);
|
||||||
|
caps::cap_free(my_caps as *mut c_void);
|
||||||
|
caps::cap_free(target_caps as *mut c_void);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ret = caps::cap_set_proc(my_caps);
|
||||||
|
if ret != 0 {
|
||||||
|
eprintln!("cap_set_proc: {}", ret);
|
||||||
|
caps::cap_free(my_caps as *mut c_void);
|
||||||
|
caps::cap_free(target_caps as *mut c_void);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
caps::cap_free(my_caps as *mut c_void);
|
||||||
|
|
||||||
|
let ret = caps::cap_set_file(arg.get_cstr_by_index(2).as_ptr(), target_caps);
|
||||||
|
if ret != 0 {
|
||||||
|
eprintln!("cap_set_file: {}", ret);
|
||||||
|
caps::cap_free(target_caps as *mut c_void);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
caps::cap_free(target_caps as *mut c_void);
|
||||||
|
|
||||||
|
_ = match arg.get_cstr_by_index(0).to_bytes() {
|
||||||
|
[b'/', b'!', ..] => unlink(arg.get_cstr_by_index(0).as_ptr()),
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
EXIT_SUCCESS
|
||||||
|
}
|
Loading…
Reference in New Issue