site  contact  subhomenews

Light-weight replacement for sudo

June 26, 2023 — BarryK

I posted a couple of days ago, taken out the 'sudo' package and just using 'su':

https://bkhome.org/news/202306/goodbye-sudo-package.html

On reflection, that has various limitations and potential issues, so had a rethink and came up with something else, that does not use 'su'. Starting from the beginning, a script, say /usr/sbin/bootmanager now has this at the beginning:

if [ "$(whoami)" != "root" ];then
if [ -x /usr/bin/sudo-sh ];then
exec sudo-sh ${PPID} ${0} ${@}
else
exec sudo -A ${0} ${@}
fi
fi

This checks for the existence of a binary executable, /usr/bin/sudo-sh and if exists will use it install of the normal sudo. 'sudo-sh' is a wrapper for a script, /usr/bin/sudo.sh. I got the idea from reading the posts here:

https://unix.stackexchange.com/questions/364/allow-setuid-on-shell-scripts

I came up with what looks like a secure way to run a script, 'sudo.sh'. This is the binary executable, /usr/bin/sudo-sh:

//wrapper to run sudo.sh, see /usr/sbin/bootmanager example.
//sudo-sh must be root:root 4711 (setuid). sudo.sh root:root 0700
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[], char *envp[]) {
setuid(0);
//execv("/usr/bin/sudo.sh",argv);
//the above works, but maybe, very maybe, a security weakness:
// https://unix.stackexchange.com/questions/364/allow-setuid-on-shell-scripts
//so do it this way, run the ash interpreter here...
//also, don't pass envp...

extern char **environ;
char *lang;
lang=getenv("LANG");
char langenv[] = "LANG=";
strcat(langenv,lang);
char *display;
display=getenv("DISPLAY");
char displayenv[] = "DISPLAY=";
strcat(displayenv,display);

char *envp2[] = { displayenv,
"XDG_CACHE_HOME=/root/.cache",
"XDG_CONFIG_DIRS=/etc/xdg",
"XDG_CONFIG_HOME=/root/.config",
"XDG_DATA_DIRS=/usr/share:/usr/local/share",
"XDG_DATA_HOME=/root/.local/share",
"XLIB_SKIP_ARGB_VISUALS=1",
"QT5DIR=/usr",
"QT_QPA_PLATFORMTHEME=gtk2",
"QT_XFT=true",
"RGBDEF=/usr/share/X11/rgb.txt",
"SHELL=/bin/bash",
"PULSE_RUNTIME_PATH=/run/pulse",
"PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin",
"OSTYPE=linux-gnu",
"MOZILLA_FIVE_HOME=/usr/lib/seamonkey",
"MOZ_DISABLE_PANGO=1",
"MOZ_PLUGIN_PATH=/usr/lib/mozilla/plugins",
"NO_AT_BRIDGE=1",
"OOO_FORCE_DESKTOP=gnome",
"LS_COLORS=bd=33:cd=33",
"LIBASOUND_THREAD_SAFE=0",
"INPUTRC=/etc/inputrc",
"GTK2_RC_FILES=/root/.gtkrc-2.0",
"G_FILENAME_ENCODING=@locale",
langenv,
NULL};

//i don't know C well enough to do this for an arbitrary # of params...
//note, argv[0] has name of this script. argv[1] has pid of caller-of-caller
char binash[] = "/bin/ash";
char ash[] = "ash";
char sudosh[] = "/usr/bin/sudo.sh";
//if (argc==2) execle(binash,ash,sudosh,argv[1],(char*) NULL,envp2);
if (argc==3) execle(binash,ash,sudosh,argv[1],argv[2],(char*) NULL,envp2);
if (argc==4) execle(binash,ash,sudosh,argv[1],argv[2],argv[3],(char*) NULL,envp2);
if (argc==5) execle(binash,ash,sudosh,argv[1],argv[2],argv[3],argv[4],(char*) NULL,envp2);
if (argc==6) execle(binash,ash,sudosh,argv[1],argv[2],argv[3],argv[4],argv[5],(char*) NULL,envp2);
if (argc==7) execle(binash,ash,sudosh,argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],(char*) NULL,envp2);
}

'sudo-sh' has 4711 permissions, 'sudo.sh' has 0700. The binary passes control to the script, which can be seen here:

https://github.com/bkauler/woofq/commit/4abb23e6ce56495973cd0ab8508293c09e050501

If a non-root app tries to run 'bootmanager', this window will popup:

img1

...the help button explains how permission to run bootmanager without password can be reverted, if you change your mind.

This is pretty neat. The default is to always ask for a password. Another example is the /usr/bin/xdg-open script -- if a non-root app tries to run it, that window will pop up.

An interesting point about xdg-open. If it is used to open the browser, administrator password is requested; however, the browser itself will still run non-root. Chromium as user 'chromium.    

Tags: easy