Uplift Privileges on FreeBSD

Wait 5 sec.

There are many tools to uplift privileges for a regular user on FreeBSD to either different account or to the root rights with all possible power. For a start on any FreeBSD system any admin user needs to be in the wheel group to be even able to switch to root with su(1) command.From su(1) man page:PAM is used to set the policy su(1) will use. In particular, by default only users in the “wheel” group can switch to UID 0 (“root“). This group requirement may be changed by modifying the “pam_group” section of /etc/pam.d/su. See pam_group(8) for details on how to modify this setting.One can use other groups for other limited privileges. For example I use group network to provide access to manipulate network connections on FreeBSD with mine network.sh script. More about that – FreeBSD Network Management with network.sh Script – here.Most sysadmins usually turn to sudo(8) or doas(1) tools – but these are also other and native tools for that on FreeBSD. mdo(1)No need to install anything – its all provided by the Mandatory Access Control that part of FreeBSD.After configured it behaves like sudo(8) or doas(1) tools. You can add -i argument to switch to root user or use -i USER to switch to another user.Here is how it works. First you need to load mac_do(4) kernel module. Make sure its also loaded at boot in the /etc/rc.conf file or in the /boot/loader.conf file.# kldload mac_do# grep mac_do /etc/rc.conf kld_list="${kld_list} mac_do"Next you need to make sure its enable and define the rules. Keep the rules in /etc/sysctl.conf for next reboots.# sysctl security.mac.do.enabledsecurity.mac.do.enabled: 1# sysctl security.mac.do.rules='gid=0>uid=0;uid=1000>uid=80,gid=80'security.mac.do.rules: -> gid=0>uid=0;uid=1000>uid=80,gid=80# grep mac.do /etc/sysctl.conf# SETTINGS FOR mac_do(4) MODULE security.mac.do.rules='gid=0>uid=0'Now the setup is done and you can use mdo tool to switch to root super user.% mdo -i# whoamiroot… or to switch to other user … but only to the one that is configured. You can switch to www user but You can not switch to hast user for example.% whoamivermaden% mdo -u hastmdo: calling setcred() failed: Operation not permitted% mdo -u www% iduid=80(www) gid=80(www) groups=80(www)The syntax of security.mac.do.rules is quite simple – its RULE;RULE;RULE and have two rules defines. One allows us to become root super user – gid=0>uid=0 – and the other one grands us the permission to switch to www user – uid=1000>uid=80,gid=80 – as simple as that.The mac_do(4) is a lot more – it also has a solutions for FreeBSD Jails – but that one already been covered by Olivier Certner in his recent Credentials Transitions with mdo(1) and mac_do(4) [PDF] that was also published in FreeBSD Journal recently. doas(1)This is what I really like about OpenBSD team – they see the problem – they come with BSD licensed more open solution – they even have entire page of all their stuff – OpenBSD Innovations – available here. Things like tmux(1)/openntpd(8)/carp(4)/pf(4)/ssh(1)/doas(1)/openrsync(1)/… and many more. I am glad that most of them eventfully land in FreeBSD.Install and setup of doas(1) requires adding doas package and configuring /usr/local/etc/doas.conf config.# pkg install -y doas# cat /usr/local/etc/doas.conf# CORE permit nopass keepenv root as root permit nopass keepenv :wheel as root# THE network.sh SCRIPT # pw groupmod network -m YOURUSERNAME # cat /usr/local/etc/doas.conf permit nopass :network as root cmd /etc/rc.d/netif args onerestart permit nopass :network as root cmd /etc/rc.d/routing args onerestart permit nopass :network as root cmd /usr/sbin/service args squid onerestart permit nopass :network as root cmd dhclient permit nopass :network as root cmd ifconfig permit nopass :network as root cmd killall permit nopass :network as root cmd killall args -9 dhclient permit nopass :network as root cmd killall args -9 ppp permit nopass :network as root cmd killall args -9 wpa_supplicant permit nopass :network as root cmd ppp permit nopass :network as root cmd route permit nopass :network as root cmd tee args -a /etc/resolv.conf permit nopass :network as root cmd tee args /etc/resolv.conf permit nopass :network as root cmd umount permit nopass :network as root cmd vm args switch address permit nopass :network as root cmd wpa_supplicantThe # CORE part is one can say pretty default for all doas configurations. The # THE network.sh SCRIPT section is for my network.sh script to manage networking – it will even print all needed doas(1) configuration needed.% network.sh doas # pw groupmod network -m YOURUSERNAME # cat /usr/local/etc/doas.conf permit nopass :network as root cmd /etc/rc.d/netif args onerestart permit nopass :network as root cmd /etc/rc.d/routing args onerestart permit nopass :network as root cmd /usr/sbin/service args squid onerestart permit nopass :network as root cmd dhclient permit nopass :network as root cmd ifconfig permit nopass :network as root cmd killall permit nopass :network as root cmd killall args -9 dhclient permit nopass :network as root cmd killall args -9 ppp permit nopass :network as root cmd killall args -9 wpa_supplicant permit nopass :network as root cmd ppp permit nopass :network as root cmd route permit nopass :network as root cmd tee args -a /etc/resolv.conf permit nopass :network as root cmd tee args /etc/resolv.conf permit nopass :network as root cmd umount permit nopass :network as root cmd vm args switch address permit nopass :network as root cmd wpa_supplicantThe doas(1) command does not have -i argument but one can overcome that with starting new shell with uplifted rights.% whoamivermaden% doas -idoas: illegal option -- iusage: doas [-nSs] [-a style] [-C config] [-u user] command [args]% doas zsh# whoamirootSame as sudo(8) the doas(1) provides vidoas(1) to safely edit the config – it also respects the EDITOR variable so you may overwrite your default editor on the fly.# env EDITOR=ee vidoasOne needs to remember that doas(1) is a really tiny and very secure solution with less then 5000 lines of code. Compare that with little less then 640000 for sudo(8) command. sudo(8)One of the most popular ones is still Linux originated sudo(8) command. It way more complicated and but also has more features … and less good security history If you do not need those additional features – use mdo(1) or doas(1) instead.Install and setup of sudo(8) requires adding sudo package and configuring /usr/local/etc/sudoers config.# pkg install -y sudo# grep '^[^#]' /usr/local/etc/sudoers root ALL=(ALL) ALL %wheel ALL=(ALL) NOPASSWD: ALL %network ALL = NOPASSWD: /etc/rc.d/netif onerestart %network ALL = NOPASSWD: /etc/rc.d/routing onerestart %network ALL = NOPASSWD: /sbin/dhclient * %network ALL = NOPASSWD: /sbin/ifconfig * %network ALL = NOPASSWD: /sbin/ifconfig * up %network ALL = NOPASSWD: /sbin/route * %network ALL = NOPASSWD: /sbin/umount -f * %network ALL = NOPASSWD: /usr/bin/killall -9 dhclient %network ALL = NOPASSWD: /usr/bin/killall -9 ppp %network ALL = NOPASSWD: /usr/bin/killall -9 wpa_supplicant %network ALL = NOPASSWD: /usr/bin/killall * %network ALL = NOPASSWD: /usr/bin/tee -a /etc/resolv.conf %network ALL = NOPASSWD: /usr/bin/tee /etc/resolv.conf %network ALL = NOPASSWD: /usr/local/sbin/vm switch address * %network ALL = NOPASSWD: /usr/sbin/ppp * %network ALL = NOPASSWD: /usr/sbin/service squid onerestart %network ALL = NOPASSWD: /usr/sbin/wpa_supplicant *I intentionally omitted all comment lines from /usr/local/etc/sudoers as its not needed here.Besides that – its really similar to doas(1) config – just different syntax.You can use visudo(1) to safely edit the config – it respects the EDITOR variable.# env EDITOR=ee visudo sudo-rs(8)If Rust is your poison then you will like that sudo(8) has been rewritten into sudo-rs(8). It is also almost 4 times smaller then the original sudo(8) code base.Install and setup of sudo(8) requires adding sudo-rs package and configuring /usr/local/etc/sudoers config.# pkg install -y sudo-rsKeep in mind that sudo-rs(8) is a drop in replacement for sudo(8) so you will have to choose which one to use because they both install files in conflicting locations.I will not paste here again a /usr/local/etc/sudoers example as its available section above. doso(1)I bet you never heard about doso(1) … probably because I wrote it myself and did not shared it yet From the good news – its the smallest solution of them all with less then 40 lines of C code.From the bad news – I am not a professional programmer – I am sysadmin – so I am not best at writing C code – so be warned about this theoretical solution and do not try it at home :pNow … once in a day I was thinking – knowing how many times doas(1) is smaller then sudo(8) I was wondering – how small can you go – and doso(1) is the answer to that question.In the code above user with UID of 1000 will be able to switch to root user. One can also modify it to ‘pickup’ the wheel group membership instead.I should do a Makefile but for such a small tiny thing I ended up with just commands gathered in a shell script.% cat ./doso.shrm -f ./doso.staticcc -O2 -o ./doso.static -static ./doso.cdoas chmod +x ./doso.staticdoas chmod u+s ./doso.staticdoas chown 0:0 ./doso.staticrm -f ./dosocc -O2 -o ./doso ./doso.cdoas chmod +x ./dosodoas chmod u+s ./dosodoas chown 0:0 ./doso% ./doso.sh% ls -l doso doso.static-rwsr-xr-x 1 root wheel 11744 Mar 1 02:41 doso-rwsr-xr-x 1 root wheel 3579320 Mar 1 02:41 doso.staticI build both dynamic and static versions as You see.… and it works as desired.% ./doso zsh# whoamirootOf course I tried to make sure to make it as secure as possible – but anyone with bigger C coding experience – please come up with fixes and upgrades  pfexec(8)Not a FreeBSD solution – a brother from Illumos/Solaris land – adding here as honorable mention to make article more complete. run0(1)… and run0(1) from the (un)famous systemd(1) solution on Linux systems. SummaryI think this will conclude this article – feel free to share your thoughts.EOF