diff options
author | Mattias Andrée <m@maandree.se> | 2025-01-29 21:07:06 +0100 |
---|---|---|
committer | Mattias Andrée <m@maandree.se> | 2025-01-29 21:07:06 +0100 |
commit | fde1d802203869236ae5678082626cca55f1f50d (patch) | |
tree | 8bd6f5c1ebbf8acd6932fe6f22abfe367dcd7de5 | |
download | nokeyrings-fde1d802203869236ae5678082626cca55f1f50d.tar.gz nokeyrings-fde1d802203869236ae5678082626cca55f1f50d.tar.bz2 nokeyrings-fde1d802203869236ae5678082626cca55f1f50d.tar.xz |
First commit
Signed-off-by: Mattias Andrée <m@maandree.se>
-rw-r--r-- | .gitignore | 15 | ||||
-rw-r--r-- | LICENSE | 15 | ||||
-rw-r--r-- | Makefile | 41 | ||||
-rw-r--r-- | README | 42 | ||||
-rw-r--r-- | config.mk | 8 | ||||
-rw-r--r-- | nokeyrings.1 | 96 | ||||
-rw-r--r-- | nokeyrings.c | 127 |
7 files changed, 344 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9b9a5e7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*\#* +*~ +*.o +*.a +*.lo +*.su +*.so +*.so.* +*.dll +*.dylib +*.gch +*.gcov +*.gcno +*.gcda +/nokeyrings @@ -0,0 +1,15 @@ +ISC License + +© 2025 Mattias Andrée <m@maandree.se> + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f691e40 --- /dev/null +++ b/Makefile @@ -0,0 +1,41 @@ +.POSIX: + +CONFIGFILE = config.mk +include $(CONFIGFILE) + +OBJ =\ + nokeyrings.o + +HDR = + +all: nokeyrings +$(OBJ): $(HDR) + +.c.o: + $(CC) -c -o $@ $< $(CFLAGS) $(CPPFLAGS) + +nokeyrings: $(OBJ) + $(CC) -o $@ $(OBJ) $(LDFLAGS) + +install: nokeyrings + mkdir -p -- "$(DESTDIR)$(PREFIX)/bin" + mkdir -p -- "$(DESTDIR)$(MANPREFIX)/man1/" + cp -- nokeyrings "$(DESTDIR)$(PREFIX)/bin/" + cp -- nokeyrings.1 "$(DESTDIR)$(MANPREFIX)/man1/" + +post-install: + chown -- '0:0' "$(DESTDIR)$(PREFIX)/bin/nokeyrings" + chmod -- 4755 "$(DESTDIR)$(PREFIX)/bin/nokeyrings" + +uninstall: + -rm -f -- "$(DESTDIR)$(PREFIX)/bin/nokeyrings" + -rm -f -- "$(DESTDIR)$(MANPREFIX)/man1/nokeyrings.1" + +clean: + -rm -f -- *.o *.a *.lo *.su *.so *.so.* *.gch *.gcov *.gcno *.gcda + -rm -f -- nokeyrings + +.SUFFIXES: +.SUFFIXES: .o .c + +.PHONY: all install post-install uninstall clean @@ -0,0 +1,42 @@ +NAME + nokeyrings - Spawn a new program and hide the user's keyrings from it + +SYNOPSIS + nokeyrings utility [argument] ... + +DESCRIPTION + The nokeyrings utility runs a specified utility, but mounts + /var/empty over ~/.local/share/keyrings, if both directories + exist, (failure is ignored) for that process and its children, + effectively hiding the + user's keyrings. + +OPTIONS + No options are supported. + +OPERANDS + The following operands are supported: + + utility + The name of the utility to be invoked. + + argument + A string to pass as an argument for the invoked utility. + +EXIT STATUS + If utility is invoked, the exit status of nokeyrings is the exit + status of utility; otherwise, the nokeyrings utility exits with + one of the following values: + + 125 An error occurred in the nokeyrings utility. + + 126 The utility specified by utility was found but could + not be invoked. + + 127 The utility sspecified by utility could not be found. + +RATIONALE + The nokeyrings utility can be used as a wrapper around programs + that nags the user about entering his password to access a + keyring, if he does it use it but the keyring is tightly + integrated into the OS distribution and cannot easily be removed. diff --git a/config.mk b/config.mk new file mode 100644 index 0000000..aeb8cec --- /dev/null +++ b/config.mk @@ -0,0 +1,8 @@ +PREFIX = /usr +MANPREFIX = $(PREFIX)/share/man + +CC = c99 + +CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_GNU_SOURCE +CFLAGS = +LDFLAGS = -lsimple diff --git a/nokeyrings.1 b/nokeyrings.1 new file mode 100644 index 0000000..984b7d8 --- /dev/null +++ b/nokeyrings.1 @@ -0,0 +1,96 @@ +.TH NOKEYRINGS 1 NOKEYRINGS +.SH NAME +nokeyrings - Spawn a new program and hide the user's keyrings from it + +.SH SYNOPSIS +.B nokeyrings +.I utility +.RI [ argument "] ..." + +.SH DESCRIPTION +The +.B nokeyrings +utility runs a specified +.IR utility , +but mounts +.I /var/empty +over +.IR ~/.local/share/keyrings , +if both directories exist, (failure is ignored) +for that process and its children, effectively +hiding the user's keyrings. + +.SH OPTIONS +No options are supported. + +.SH OPERANDS +The following operands are supported: +.TP +.I utility +The name of the utility to be invoked. +.TP +.I argument +A string to pass as an argument for the invoked utility. + +.SH STDIN +Not used. + +.SH INPUT FILES +None. + +.SH ENVIRONMENT VARIABLES +The following environment variables affect +the execution of +.BR nokeyrings : +.TP +.B PATH +Determine the location of the +.IR utility , +as described in the Base Definitions volume of POSIX.1‐2017, +.IR "Chapter 8, Environment Variables" . + +.SH STDOUT +Not used. + +.SH STDERR +The standard error is be used only for diagnostic messages. + +.SH OUTPUT FILES +None. + +.SJ EXIT STATUS +If +.I utility +is invoked, the exit status of +.B nokeyrings +is the exit status of +.IR utility ; +otherwise, the +.B nokeyrings +utility exits with one of the following values: +.TP +125 +An error occurred in the +.B nokeyrings +utility. +.TP +126 +The utility specified by +.I utility +was found but could not be invoked. +.TP +127 +The utility sspecified by +.I utility +could not be found. + +.SH RATIONALE +The +.B nokeyrings +utility can be used as a wrapper around programs +that nags the user about entering his password to access a +keyring, if he does it use it but the keyring is tightly +integrated into the OS distribution and cannot easily be removed. + +.SH SEE ALSO +None. diff --git a/nokeyrings.c b/nokeyrings.c new file mode 100644 index 0000000..aaa32c7 --- /dev/null +++ b/nokeyrings.c @@ -0,0 +1,127 @@ +/* See LICENSE file for copyright and license details. */ +#include <sys/mount.h> +#ifndef OPEN_TREE_CLONE +# define MISSING_OPEN_TREE +#endif +#ifndef MOVE_MOUNT_F_EMPTY_PATH +# define MISSING_MOVE_MOUNT +#endif +#if defined(MISSING_OPEN_TREE) || defined(MISSING_MOVE_MOUNT) +# include <linux/mount.h> +# include <sys/syscall.h> +#endif +#include <sched.h> +#include <libsimple.h> +#include <libsimple-arg.h> + +NUSAGE(125, "utility [argument] ..."); + + + +#ifdef MISSING_OPEN_TREE +static int +open_tree(int dirfd, const char *path, int flags) +{ + return syscall(SYS_open_tree, dirfd, path, flags); +} +#endif + + +#ifdef MISSING_MOVE_MOUNT +static int +move_mount(int dirfd1, const char *path1, int dirfd2, const char *path2, int flags) +{ + return syscall(SYS_move_mount, dirfd1, path1, dirfd2, path2, flags); +} +#endif + + +int +main(int argc, char *argv[]) +{ + struct stat st; + int emptyfd = -1; + int keyringsfd = -1; + char *path = NULL; + struct passwd *pwd; + + libsimple_default_failure_exit = 125; + + ARGBEGIN { + default: + usage(); + } ARGEND; + + if (!argc) + usage(); + + errno = 0; + pwd = getpwuid(getuid()); + if (!pwd) { + if (!errno) { + eprintf("your user does not exist"); + } else if (errno == EIO) { + weprintf("getpwuid <real user>:"); + eprintf("this usually indicates that the user not exist"); + } else { + eprintf("getpwuid <real user>:"); + } + } + if (!pwd->pw_dir || !*pwd->pw_dir) + eprintf("your user does not have a home directory"); + + path = emalloc(strlen(pwd->pw_dir) + sizeof("/.local/share/keyrings")); + stpcpy(stpcpy(path, pwd->pw_dir), "/.local/share/keyrings"); + + keyringsfd = open(path, O_DIRECTORY); + if (keyringsfd < 0) { + if (errno != ENOENT) + weprintf("open %s O_DIRECTORY:", path); + goto exec; + } + + if (unshare(CLONE_NEWNS)) { + weprintf("unshare CLONE_NEWNS:"); + goto exec; + } + if (mount("none", "/", NULL, MS_REC | MS_SLAVE, NULL)) { + weprintf("mount none / NULL MS_REC|MS_SLAVE NULL:"); + goto exec; + } + + emptyfd = open_tree(AT_FDCWD, "/var/empty", OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC); + if (emptyfd < 0) { + weprintf("open_tree AT_FDCWD /var/empty OPEN_TREE_CLONE|OPEN_TREE_CLOEXEC:"); + goto exec; + } + + if (fstatat(emptyfd, "", &st, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW)) { + weprintf("fstatat /var/empty \"\" <buffer> AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW:"); + goto exec; + } + if (!S_ISDIR(st.st_mode)) { + weprintf("/var/empty exists but is not a directory:"); + goto exec; + } + + if (move_mount(emptyfd, "", AT_FDCWD, path, MOVE_MOUNT_F_EMPTY_PATH)) { + weprintf("move_mount /var/empty \"\" AT_FDCWD %s MOVE_MOUNT_F_EMPTY_PATH:", path); + goto exec; + } + +exec: + free(path); + if (emptyfd >= 0) + close(emptyfd); + if (keyringsfd >= 0) + close(keyringsfd); + + if (setegid(getgid())) + eprintf("setegid <real group>:"); + if (seteuid(getuid())) + eprintf("seteuid <real user>:"); + + execvp(argv[0], argv); + enprintf(errno == ENOENT ? 127 : 126, "execvp %s:", argv[0]); + return 0; +} |