Good Morning Guys,
I have the following suggestion to restrict the permissions to only the necessary by having a single little c programm:
It has multiple symbolic links pointing at a single binary called ‘osmcctrl’, for different tasks. Thats the way also busybox is implemented.
It keeps all code together in one cozy c-file. Here what it looks like in the filesystem:
osmc@osmc:~/osmcctrl$ ls -la
total 32
drwxr-xr-x 2 osmc osmc 4096 Feb 2 14:43 .
drwxr-xr-x 23 osmc osmc 4096 Feb 2 14:41 ..
-rw-r--r-- 1 osmc osmc 549 Feb 1 22:09 Makefile
lrwxrwxrwx 1 osmc osmc 8 Feb 1 22:14 osmc_reboot -> osmcctrl
lrwxrwxrwx 1 osmc osmc 8 Feb 1 22:14 osmc_servicedisable -> osmcctrl
lrwxrwxrwx 1 osmc osmc 8 Feb 1 22:14 osmc_serviceenable -> osmcctrl
lrwxrwxrwx 1 osmc osmc 8 Feb 1 22:14 osmc_servicestart -> osmcctrl
lrwxrwxrwx 1 osmc osmc 8 Feb 1 22:14 osmc_servicestop -> osmcctrl
lrwxrwxrwx 1 osmc osmc 8 Feb 1 22:14 osmc_sethostname -> osmcctrl
lrwxrwxrwx 1 osmc osmc 8 Feb 1 22:14 osmc_setlocale -> osmcctrl
lrwxrwxrwx 1 osmc osmc 8 Feb 1 22:14 osmc_settimezone -> osmcctrl
-rwsr-xr-x 1 root root 8732 Feb 1 22:14 osmcctrl
Note that the SUID bit is set on osmccctrl and its owned by root.
sudo chown root:root osmcctrl && sudo chmod 4755 osmcctrl
So far the following functionality has been implemented:
- Rebooting by calling “osmc_reboot”
- Setting the timezone by calling “osmc_setimezone Europe/Berlin”
- Setting the hostname “osmc_sethostname marvin”
- Start/Stop/En-/Disable a service calling e.g:
“osmc_enable ssh”
“osmc_disable ssh”
…
BTW: Quering the status or is-enabled of a system service is in general not restricted to root. So to figure out if a service is running: “systemctl status ssh” or also “systemctl is-enabled ssh” can be issued as user osmc. A wrapper is not needed.
Having all “sudo” hacks in one file actually builds something like an interface. It makes it easy to track which components are messing with the system. It also makes it easy to adopt to future needs.
Now, for the tiny implementation… And finally tell me if you would consider this solution!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/reboot.h>
void
osmcSetTimezone (int argc, char **argv)
{
if (argc != 2)
{
fprintf (stderr, "no timezone given!\n");
exit (-1);
}
printf ("Setting timezone to '%s'\n", argv[1]);
/* Keep /etc/timezone in sync */
FILE *fp = fopen ("/tmp/timezone", "w");
if (fp)
{
fprintf (fp, "%s\n", argv[1]);
fclose (fp);
int res = system ("/bin/mv /tmp/timezone /etc/timezone"); /* We need this to update a root owned file */
if (res == 0)
{
char *command;
asprintf (&command, "%s%s%s", "/bin/cp /usr/share/zoneinfo/",
argv[1], " /etc/localtime.dpkg-new");
system (command);
system ("/bin/mv /etc/localtime.dpkg-new /etc/localtime");
}
}
}
void
osmcSetLocale (int argc, char **argv)
{
printf ("Setting locale... TODO\n");
}
void
osmcSetHostname (int argc, char **argv)
{
if (argc != 2)
{
fprintf (stderr, "no hostname given!\n");
exit (-1);
}
printf ("Setting hostname\n");
FILE *fp;
fp = fopen ("/tmp/hostname", "w");
if (fp)
{
fprintf (fp, "%s", argv[1]);
fclose (fp);
}
else
return;
system ("/bin/mv /tmp/hostname /etc/hostname");
system ("/bin/hostname -F /etc/hostname");
}
void
osmcReboot (int argc, char **argv)
{
reboot (LINUX_REBOOT_CMD_RESTART);
}
void
osmcServiceCmd (char *cmd, int argc, char **argv)
{
char syscmd[128 * 2];
if (argc != 2)
{
fprintf (stderr, "no servicename given!\n");
exit (-1);
}
if (strlen (argv[1]) > 128)
{
fprintf (stderr, "servicename too long!\n");
exit (-1);
}
sprintf (syscmd, "systemctl %s %s", cmd, argv[1]);
system (syscmd);
}
void
osmcExec (int argc, char **argv)
{
system(argv[1]);
}
int
main (int argc, char **argv)
{
printf ("Called: %s\n", argv[0]);
// besides suid we need to have root group and user id
uid_t uid = 0;
gid_t gid = 0;
setuid(uid);
setgid(gid);
if (strstr (argv[0], "osmc_settimezone"))
osmcSetTimezone (argc, argv);
else if (strstr (argv[0], "osmc_setlocale"))
osmcSetLocale (argc, argv);
else if (strstr (argv[0], "osmc_sethostname"))
osmcSetHostname (argc, argv);
else if (strstr (argv[0], "osmc_reboot"))
osmcReboot (argc, argv);
else if (strstr (argv[0], "osmc_serviceenable"))
osmcServiceCmd ("enable", argc, argv);
else if (strstr (argv[0], "osmc_servicedisable"))
osmcServiceCmd ("disable", argc, argv);
else if (strstr (argv[0], "osmc_servicestart"))
osmcServiceCmd ("start", argc, argv);
else if (strstr (argv[0], "osmc_servicestop"))
osmcServiceCmd ("stop", argc, argv);
#ifdef MYDEBUG
else if (strstr (argv[0], "osmc_exec"))
osmcExec ( argc, argv);
#endif
else
fprintf (stderr, "Command not found\n");
}