Ответ 1
Вы ищете эту статью:
POS36-C. Соблюдайте правильный порядок отзыва, отказываясь от привилегий
Не уверен, как наилучшим образом разместить некоторую информацию без дублирования содержимого этой страницы...
У меня есть демон, который запускается как root (поэтому он может связываться с низкими портами). После инициализации я бы очень хотел, чтобы он сбросил права root по соображениям безопасности.
Может ли кто-нибудь указать мне на известную правильную часть кода в C, которая сделает это?
Я читал страницы руководства, я рассматривал различные реализации этого в разных приложениях, и они все разные, и некоторые из них действительно сложны. Это код, связанный с безопасностью, и я действительно не хочу изобретать те же ошибки, что и другие люди. То, что я ищу, - это лучшая практика, известная хорошая портативная библиотечная функция, которую я могу использовать, зная, что все будет правильно. Существует ли такая вещь?
Для справки: я начинаю с root; Мне нужно изменить, чтобы работать под другим uid и gid; Я должен правильно настроить дополнительные группы; После этого мне не нужно менять права root.
Вы ищете эту статью:
POS36-C. Соблюдайте правильный порядок отзыва, отказываясь от привилегий
Не уверен, как наилучшим образом разместить некоторую информацию без дублирования содержимого этой страницы...
Чтобы отказаться от всех привилегий (пользователя и группы), вам необходимо отбросить группу перед пользователем. Учитывая, что userid
и groupid
содержат идентификаторы пользователя и группы, к которой вы хотите перейти, и считая, что эффективные идентификаторы также являются корневыми, это достигается путем вызова setuid() и setgid():
if (getuid() == 0) {
/* process is running as root, drop privileges */
if (setgid(groupid) != 0)
fatal("setgid: Unable to drop group privileges: %s", strerror(errno));
if (setuid(userid) != 0)
fatal("setuid: Unable to drop user privileges: %S", strerror(errno));
}
Если вы параноик, вы можете попытаться вернуть свои привилегии root, что должно завершиться неудачей. Если это не сработает, вы получите помощь:
if (setuid(0) != -1)
fatal("ERROR: Managed to regain root privileges?");
Кроме того, если вы все еще параноик, вы можете seteuid() и setegid(), но это не обязательно, поскольку setuid() и setgid() уже установили все идентификаторы, если процесс принадлежит root.
Список дополнительных групп - проблема, потому что нет функции POSIX для установки дополнительных групп (есть getgroups(), но нет групп групп()). Существует расширение BSD и Linux setgroups(), которое вы можете использовать, это вас касается.
Вы также должны chdir("/")
или в любой другой каталог, чтобы процесс не оставался в корневом каталоге.
Поскольку ваш вопрос касается Unix вообще, это очень общий подход. Обратите внимание: в Linux это уже не предпочтительный подход. В текущих версиях Linux вы должны установить CAP_NET_BIND_SERVICE
возможность в исполняемом файле и запустить его как обычного пользователя. Нет необходимости в корневом доступе.
Вот что я мог сделать лучше всего:
#define _GNU_SOURCE // for secure_getenv()
int drop_root_privileges(void) { // returns 0 on success and -1 on failure
gid_t gid;
uid_t uid;
// no need to "drop" the privileges that you don't have in the first place!
if (getuid() != 0) {
return 0;
}
// when your program is invoked with sudo, getuid() will return 0 and you
// won't be able to drop your privileges
if ((uid = getuid()) == 0) {
const char *sudo_uid = secure_getenv("SUDO_UID");
if (sudo_uid == NULL) {
printf("environment variable `SUDO_UID` not found\n");
return -1;
}
errno = 0;
uid = (uid_t) strtoll(sudo_uid, NULL, 10);
if (errno != 0) {
perror("under-/over-flow in converting `SUDO_UID` to integer");
return -1;
}
}
// again, in case your program is invoked using sudo
if ((gid = getgid()) == 0) {
const char *sudo_gid = secure_getenv("SUDO_GID");
if (sudo_gid == NULL) {
printf("environment variable `SUDO_GID` not found\n");
return -1;
}
errno = 0;
gid = (gid_t) strtoll(sudo_gid, NULL, 10);
if (errno != 0) {
perror("under-/over-flow in converting `SUDO_GID` to integer");
return -1;
}
}
if (setgid(gid) != 0) {
perror("setgid");
return -1;
}
if (setuid(uid) != 0) {
perror("setgid");
return -1;
}
// change your directory to somewhere else, just in case if you are in a
// root-owned one (e.g. /root)
if (chdir("/") != 0) {
perror("chdir");
return -1;
}
// check if we successfully dropped the root privileges
if (setuid(0) == 0 || seteuid(0) == 0) {
printf("could not drop root privileges!\n");
return -1;
}
return 0;
}