J'ai un démon qui démarre en tant que root (donc il peut se lier aux ports bas). Après l'initialisation, j'aimerais beaucoup qu'il supprime les privilèges root pour des raisons de sécurité.
Quelqu'un peut-il me pointer vers un correct correct morceau de code en C qui fera cela?
J'ai lu les pages de manuel, j'ai examiné diverses implémentations de ceci dans différentes applications, et elles sont toutes différentes, et certaines d'entre elles sont vraiment complexes. Il s'agit d'un code lié à la sécurité, et je ne veux vraiment pas réinventer les mêmes erreurs que les autres font. Ce que je recherche, c'est une meilleure pratique, une bonne fonction de bibliothèque portable connue que je peux utiliser en sachant que cela va faire les choses correctement. Une telle chose existe-t-elle?
Pour référence: je commence en tant que root; J'ai besoin de changer pour fonctionner sous un uid et un gid différents; J'ai besoin que les groupes supplémentaires soient correctement installés; Je n'ai pas besoin de revenir aux privilèges root par la suite.
Vous recherchez cet article:
POS36-C. Observez l'ordre de révocation correct tout en abandonnant les privilèges
Vous ne savez pas comment y mettre au mieux des informations sans dupliquer le contenu de cette page ...
Pour supprimer tous les privilèges (utilisateur et groupe), vous devez supprimer le groupe avant l'utilisateur. Étant donné que userid
et groupid
contient les ID de l'utilisateur et du groupe vers lequel vous souhaitez déposer, et en supposant que les ID effectifs sont également root, ceci est accompli en appelant setuid () et 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));
}
Si vous êtes paranoïaque, vous pouvez essayer de récupérer vos privilèges root, ce qui devrait échouer. Si cela échoue, vous renflouez:
if (setuid(0) != -1)
fatal("ERROR: Managed to regain root privileges?");
De plus, si vous êtes toujours paranoïaque, vous voudrez peut-être aussi seteuid () et setegid () , mais cela ne devrait pas être nécessaire, car setuid () et setgid ( ) a déjà défini tous les ID si le processus appartient à root.
La liste des groupes supplémentaires est un problème, car il n'y a pas de fonction POSIX pour définir des groupes supplémentaires (il y a getgroups () , mais pas de setgroups ()). Il existe une extension BSD et Linux setgroups () que vous pouvez utiliser, cela vous concerne.
Vous devez également chdir("/")
ou dans tout autre répertoire, afin que le processus ne reste pas dans un répertoire appartenant à la racine.
Puisque votre question concerne Unix en général, c'est l'approche très générale. Notez que sous Linux, ce n'est plus l'approche préférée. Dans les versions Linux actuelles, vous devez définir la fonction CAP_NET_BIND_SERVICE
sur l'exécutable et l'exécuter en tant qu'utilisateur normal. Aucun accès root n'est nécessaire.
C'est ce que je pouvais faire de mieux:
#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;
}