diff --git a/.gitignore b/.gitignore index ceb16cb..2cee832 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /privlx +/unprivlx diff --git a/compile b/compile index 2d0d37a..8ed8ca9 100755 --- a/compile +++ b/compile @@ -2,4 +2,5 @@ set -e SCRIPT_DIR="$(dirname "$(realpath -s "$BASH_SOURCE")")" source "$SCRIPT_DIR/env" -"$CC" -std=gnu89 -Werror -Wall -Os -D APP_NAME="\"$APP_NAME\"" -D APP_CONF="\"$APP_CONF\"" "$SCRIPT_DIR/src/main.c" -o "$SCRIPT_DIR/$APP_NAME" $CFLAGS +"$CC" -std=gnu89 -Werror -Wall -Os -D APP_NAME="\"$APP_NAME\"" -D APP_CONF="\"$APP_CONF\"" "$SCRIPT_DIR/src/priv.c" -o "$SCRIPT_DIR/$APP_NAME" $CFLAGS +"$CC" -std=gnu89 -Werror -Wall -Os -D APP_NAME="\"$APP_NAME\"" -D APP_CONF="\"$APP_CONF\"" "$SCRIPT_DIR/src/unpriv.c" -o "$SCRIPT_DIR/un$APP_NAME" $CFLAGS diff --git a/env b/env index 9f3fa27..3d09e8c 100644 --- a/env +++ b/env @@ -1,4 +1,4 @@ APP_NAME="${APP_NAME:=privlx}" -APP_BIN="${APP_BIN:=/usr/local/bin/$APP_NAME}" +APP_BIN="${APP_BIN:=/usr/local/bin}" APP_CONF="${APP_CONF:=/etc/$APP_NAME}" CC="${CC:=cc}" diff --git a/install b/install index f66f1cb..42a4346 100755 --- a/install +++ b/install @@ -2,13 +2,18 @@ set -e SCRIPT_DIR="$(dirname "$(realpath -s "$BASH_SOURCE")")" source "$SCRIPT_DIR/env" -mkdir -p "$(dirname "$APP_BIN")" -cp "$SCRIPT_DIR/$APP_NAME" "$APP_BIN" -chown 0 "$APP_BIN" -chgrp 0 "$APP_BIN" -chmod 755 "$APP_BIN" -chmod u+s "$APP_BIN" -chmod g+s "$APP_BIN" +mkdir -p "$APP_BIN" +cp "$SCRIPT_DIR/$APP_NAME" "$APP_BIN/$APP_NAME" +chown 0 "$APP_BIN/$APP_NAME" +chgrp 0 "$APP_BIN/$APP_NAME" +chmod 755 "$APP_BIN/$APP_NAME" +chmod u+s "$APP_BIN/$APP_NAME" +chmod g+s "$APP_BIN/$APP_NAME" + +cp "$SCRIPT_DIR/un$APP_NAME" "$APP_BIN/un$APP_NAME" +chown 0 "$APP_BIN/un$APP_NAME" +chgrp 0 "$APP_BIN/un$APP_NAME" +chmod 755 "$APP_BIN/un$APP_NAME" mkdir -p "$APP_CONF" if ! [ -f "$APP_CONF/commands.conf" ]; then diff --git a/readme.txt b/readme.txt index 5a2932a..2ed1519 100644 --- a/readme.txt +++ b/readme.txt @@ -4,7 +4,8 @@ Allow unprivileged users to run executables for privileged users. NOTE: Some features are still coming, until then expect the ABI to break. * Syntax: -privlx +privlx - Get privileges and run command +unprivlx - Drop privileges and run command * Config: Add commands you want to allow users to run as root in /etc/privlx/commands.conf, one per line. @@ -24,8 +25,8 @@ Allow the user to access power management tools. Be warned, poweroff and reboot Before compiling or installing, you may set these environment variables, either in a shell, or inside of ./env: - CC: Your C compiler (default: cc) - CFLAGS: Compilation flags (default: none) -- APP_NAME: What the app is called. This is used for outputting errors (default: privlx) -- APP_BIN: Where the app's binary is stored (default: /usr/local/$APP_NAME) +- APP_NAME: What the app is called. This is used for naming the binaries and outputting errors (default: privlx) +- APP_BIN: Where the app's binaries are stored (default: /usr/local/bin) - APP_CONF: Where the app's configuration files are stored (default: /etc/$APP_NAME) * Compilation: diff --git a/src/main.c b/src/priv.c similarity index 99% rename from src/main.c rename to src/priv.c index e8f6161..848f053 100644 --- a/src/main.c +++ b/src/priv.c @@ -19,7 +19,7 @@ void *emalloc(void *ptr, size_t size) { int main(int argc, char **argv) { if (clearenv() != 0) { // Clear environment to boost security fprintf(stderr,"["APP_NAME"] Error 254: Clearing environment failed\n"); - exit(254); + return 254; } uid_t uid = getuid(); // User who's calling the program diff --git a/src/unpriv.c b/src/unpriv.c new file mode 100644 index 0000000..a84e0fb --- /dev/null +++ b/src/unpriv.c @@ -0,0 +1,103 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +void *emalloc(void *ptr, size_t size) { + void *m = realloc(ptr,size); + if (size != 0 && m == NULL) { + fprintf(stderr,"[un"APP_NAME"] Error 255: realloc() failed\n"); + exit(255); + } + return m; +} + +int main(int argc, char **argv) { + char * env; + char * endptr; + + // UID + env = getenv("SUDO_UID"); + if (env == NULL) { + fprintf(stderr,"[un"APP_NAME"] Error 254: Could not query SUDO_UID (errno %d: %s)\n",errno,strerror(errno)); + return 254; + } + uid_t euid = strtol(env,&endptr,0); + if (errno != 0) { + fprintf(stderr,"[un"APP_NAME"] Error 253: Could not convert SUDO_UID to number (errno %d: %s)\n",errno,strerror(errno)); + return 253; + } + + // GID + env = getenv("SUDO_GID"); + if (env == NULL) { + fprintf(stderr,"[un"APP_NAME"] Error 254: Could not query SUDO_GID (errno %d: %s)\n",errno,strerror(errno)); + return 254; + } + gid_t egid = strtol(env,&endptr,0); + if (errno != 0) { + fprintf(stderr,"[un"APP_NAME"] Error 253: Could not convert SUDO_GID to number (errno %d: %s)\n",errno,strerror(errno)); + return 253; + } + + // Clear env + if (clearenv() != 0) { + fprintf(stderr,"[un"APP_NAME"] Error 252: Clearing environment failed\n"); + return 252; + } + + // Clear + char passwStore[sizeof(struct passwd)]; + sprintf(passwStore,"%d",euid); + setenv("UID",passwStore,1); + sprintf(passwStore,"%d",egid); + setenv("GID",passwStore,1); + struct passwd * pw = getpwuid(euid); + if (pw == NULL) { + fprintf(stderr,"[un"APP_NAME"] Error 253: Failed to get user information (errno: %d: %s)\n",errno,strerror(errno)); + return 253; + } + setenv("USER",pw -> pw_name,1); + setenv("HOME",pw -> pw_dir,1); + setenv("SHELL",pw -> pw_shell,1); + + // ENV + // PATH + if (euid == 0) { + setenv("PATH","/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",1); + } else { + setenv("PATH","/usr/local/bin:/usr/bin:/bin",1); + } + + // Strip first argument, and move them by 1 + char **cmd; + if (argc > 1) { + cmd = emalloc(NULL,argc * sizeof(char*)); + int i = 1; + while (i < argc) { + cmd[i - 1] = argv[i]; + ++i; + } + cmd[argc - 1] = NULL; + } else { + fprintf(stderr,"[un"APP_NAME"] Error 252: Invalid syntax, use: %s ...\n",argv[0]); + return 252; + } + + // Get permissions + if (setreuid(euid,egid) == -1) { + fprintf(stderr,"[un"APP_NAME"] Error 247: Failed to un-elevate user (errno %d: %s)\n",errno,strerror(errno)); + return 247; + } + + // Run progrem + if (execvp(cmd[0],cmd) == -1) { + fprintf(stderr,"[un"APP_NAME"] Error 246: Failed launching process (errno %d: %s)\n",errno,strerror(errno)); + return 246; + } + return 0; +}