Я разрабатываю сетевое устройство, работающее под управлением Linux (CentOS 8), и для некоторой действительно базовой конфигурации на консоли VGA мы создали заблокированную учетную запись пользователя. Мы предоставили пару suid root-программ, которые выполняют такие действия, как установка IP-адреса и настройка NTP. (Все остальные настройки выполняются через Apache и некоторые веб-страницы.)
Несколько вещей, которые нам нужно сделать из этих программ: перезапустить NetworkManager.service, перезапустить chronyd.service, отключить питание и перезагрузить компьютер. И отключение питания, и перезагрузка работают отлично, но перезапуск служб не работает. Вместо этого мы получаем это:
Restarting ntp service
==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ====
Authentication is required to restart 'chronyd.service'.
Authenticating as: root
Password:
Я предполагаю, что systemctl пытается быть умным в отношении аутентификации и может определить, что пользователь, от которого он был запущен, не является пользователем root, даже если он имеет привилегии root. Можно ли каким-то образом изменить идентификатор пользователя, чтобы systemctl считал, что это root, который его вызывает?
Для справки, я приложил полный исходный код к одной из корневых программ suid ниже.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void print_usage()
{
printf("Usage: safeguard <option>\n");
printf("Options:\n");
printf(" poweroff\n");
printf(" reboot\n");
printf(" ntp [restarts NTP service]\n");
printf(" net [restarts NetworkManager service]\n");
}
int main(int argc, char *argv[])
{
if (argc < 2) {
print_usage();
return 0;
}
if (0==strcmp(argv[1], "poweroff")) {
printf("Executing poweroff\n");
system("poweroff");
return 0;
} else if (0==strcmp(argv[1], "reboot")) {
printf("Executing reboot\n");
system("reboot");
return 0;
} else if (0==strcmp(argv[1], "ntp")) {
printf("Restarting ntp service\n");
system("systemctl restart chronyd.service");
return 0;
} else if (0==strcmp(argv[1], "net")) {
printf("Restarting NetworkManager service\n");
system("systemctl restart NetworkManager.service");
return 0;
}
print_usage();
return 0;
}