2010-07-28 4 views
45

J'ai un démon démarré en tant que root (il peut donc se lier aux ports bas). Après l'initialisation, j'aimerais beaucoup avoir des privilèges root pour des raisons de sécurité.Suppression des privilèges root

Quelqu'un peut-il me pointer à un connu morceau de code en C qui fera cela? J'ai lu les pages de manuel, j'ai regardé différentes implémentations de cela dans différentes applications, et elles sont toutes différentes, et certaines d'entre elles sont vraiment complexes. C'est un code lié à la sécurité, et je ne veux vraiment pas réinventer les mêmes erreurs que les autres. Ce que je cherche, c'est une bonne pratique, une bonne bibliothèque portable, que je peux utiliser en sachant que tout va bien se passer. Est-ce qu'une telle chose existe?

Pour référence: je commence en tant que root; J'ai besoin de changer pour courir sous un autre uid et gid; J'ai besoin d'avoir les groupes supplémentaires mis en place correctement; Je n'ai pas besoin de revenir aux privilèges root par la suite.

+5

Cela varie beaucoup entre les unixes - y en a-t-il en particulier? Si vous avez besoin d'une solution "portable", cela va être désordonné, et vous feriez mieux d'en saisir par exemple. la fonction continuous_set_uid() de OpenSSH - dans le uidswap.c fichier – nos

Répondre

43

Afin de 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 le groupe que vous souhaitez déposer, et en supposant que les ID efficaces sont également racine, cela se fait 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 elle ne manque pas, vous plan de sauvetage:

if (setuid(0) != -1) 
    fatal("ERROR: Managed to regain root privileges?"); 

De plus, si vous êtes toujours paranoïaque, vous pouvez seteuid() et setegid() aussi, mais il ne devrait pas être nécessaire, étant donné que setuid() et setgid() déjà défini tous les ID si le processus appartient à root.

La liste de groupes supplémentaires est un problème, car il n'existe aucune fonction POSIX pour définir des groupes supplémentaires (il existe getgroups(), mais pas setgroups()). Il y a une extension BSD et Linux setgroups() que vous pouvez utiliser, cela vous concerne.

Vous devez également chdir("/") ou tout autre répertoire, afin que le processus ne reste pas dans un répertoire racine.

Puisque votre question porte sur Unix en général, c'est une approche très générale. Notez que sous Linux, ce n'est plus l'approche préférée. Dans les versions actuelles de Linux, vous devez définir CAP_NET_BIND_SERVICE capability sur l'exécutable et l'exécuter en tant qu'utilisateur normal. Aucun accès root n'est nécessaire.

+1

Vous voudriez aussi définir le gid - et ceci pourrait varier légèrement d'unix à l'autre en ce qui concerne setuid/setgid avec les identifiants réels et sauvés aussi – nos

+1

Cela doit effectivement être une solution portable, donc pas de Linux La capacité est autorisée, j'en ai peur. Et j'ai en effet essayé l'approche simple avec setuid() et setgid(); il ne définit pas les groupes correctement (et si vous n'appelez pas setgroups(), vous pouvez apparemment toujours être membre de certains groupes de root!). –

+0

@nos Merci. Développé pour couvrir les groupes. Si le processus est détenu par root (comme l'OP mentionné) ou s'il est setuid-root, alors setuid() et setgid() définissent déjà tous les IDs (réels, effectifs et sauvegardés). C'est dans la spécification. Sinon, l'implémentation ne serait pas conforme à POSIX. – Juliano

1

C'était ce que je pouvais faire meilleur:

#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; 
} 
Questions connexes