Разрешить другому пользователю запускать определенный скрипт в качестве идентификатора

У меня есть сценарий где-то в моем домашнем каталоге. Мне нужно предоставить другим пользователям или групповым разрешениям, чтобы при выполнении этого конкретного скрипта он выполнялся, как если бы я был вошел в систему и имел все разрешения, которые имеет мой идентификатор. Я не хочу использовать sudo или su и перебирать их как sudoers или вводить пароли.

С помощью sudo вы можете получить очень подробные разрешения. Если вы хотите дать пользователю разрешение только на запуск своего скрипта, и ничто другое вы не можете добавить эту строку в ваш / etc / sudoers:

user ALL=(yourusername) NOPASSWD: /path/to/your/script 

Затем, как и другое использование, вы запускаете:

 sudo -u yourusername /path/to/your/script 

Использование sudo – самый простой способ. Но для этого требуется сотрудничество системного администратора.

Если вы хотите сделать это без особых привилегий, вы можете использовать исполняемый файл setuid , но вам нужно быть осторожным, чтобы не позволять вызывающему абоненту делать больше, чем вы планировали.

Большинство вариантов Unix запрещают скрипты оболочки setuid ; например, в Linux, ядро ​​всегда игнорирует бит setuid в скрипте. Итак, вам нужна оболочка в собственном коде.

Позаботьтесь о том, чтобы обертка удаляла все, что могло позволить пользователю вызвать его для запуска кода. Например, переменные среды белого списка; все, что не известно в безопасности (например, TERM ), должно идти.

Вот предложение для оболочки setuid, которая сохраняет только переменную среды TERM . Остерегайтесь, что я не просмотрел его или не протестировал его; приветствуем приветствие.

 /* Compilation command: c99 -DTARGET='"/absolute/path/to/script"' -o setuid-wrapper setuid-wrapper.c */ #include <ctype.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <unistd.h> void die(const char *argv0, const char *obj, const char *msg) { if (msg == NULL) msg = strerror(errno); fprintf(stderr, "%s: %s: %s\n", argv0, obj, msg); exit(127); } int env_want(const char *entry) { size_t n; for (n = 0; entry[n]; n++) { if (entry[n] == '=') { break; } else if (!(isalnum(entry[n]) || entry[n] == '_')) { return 0; } } if ((n == 7 && !strncmp(entry, "DISPLAY", n)) || (n == 10 && !strncmp(entry, "XAUTHORITY", n))) { return 1; } if ((n == 4 && !strncmp(entry, "LANG", n)) || (n >= 3 && !strncmp(entry, "LC_", 3)) || (n == 2 && !strncmp(entry, "TZ", n))) { return !strpbrk(entry, "/%"); } return 0; } int main(int argc, char *argv[], char **environ) { size_t i, j; const char *program_name = argv[0]; if (program_name == NULL) program_name = "setuid-wrapper"; /* Drop privileges */ if (setgid(getegid())) die(program_name, "setgid", NULL); /*if (setgroups(0, NULL)) die(program_name, "setgroups", NULL);*/ if (setuid(geteuid())) die(program_name, "setuid", NULL); /* Sanitize the environment */ for (i = j = 0; environ[i]; i++) { if (env_want(environ[i])) { environ[j] = environ[i]; j++; } } environ[j] = NULL; /* Execute the command */ execle(TARGET, TARGET, NULL, environ); die(program_name, TARGET, NULL); } 

Обратите внимание, что целевая программа будет работать с дополнительными группами вызывающего, потому что вы не можете отбрасывать дополнительные группы без использования root.

Альтернативным подходом было бы запустить сервер (например, веб-сервер) и вызвать ваш скрипт с этого сервера. Существует множество крошечных HTTP-серверов, поддерживающих CGI-скрипты. Основным преимуществом этого подхода является то, что его легче защитить, поскольку сервер работает в контексте, выбранном целевым объектом (стороной, в контексте безопасности которого выполняется код), а не клиентом.

Вариантом такого подхода будет запуск сценария через файловую систему FUSE . Например, установите каталог scriptfs, содержащий ваш скрипт, с параметром allow_other mount. Для этого необходимо user_allow_other параметр /etc/fuse.conf в /etc/fuse.conf .