2016-02-01 6 views
5

Ecco una sorgente completo di un programma che illustra il mio problema (il sistema operativo è Ubuntu 14.04 a 32 bit se è importante):risultato strano quando si esegue un programma come una radice

#include <stdio.h> 
#include <string.h> 
#include <errno.h> 
#include <fcntl.h> 
#include <unistd.h> 

int main(int argc, const char *argv[]) 
{ 
    int status, fd; 

    printf("CURRENT UID: %d, CURRENT GID: %d\n", getuid(), getgid()); 

    fd = open("/dev/ttyS0", O_WRONLY); 
    if(fd < 0) 
    { 
     printf("Error opening /dev/ttyS0: %s\n", strerror(errno)); 
     return 1; 
    } 
    printf("Successfully opened /dev/ttyS0\n"); 
    close(fd); 

    /* DROP PRIVILEGES */ 

    setgid(1000); 
    setuid(1000); 

    printf("CURRENT UID: %d, CURRENT GID: %d\n", getuid(), getgid()); 

    fd = open("/dev/ttyS0", O_WRONLY); 
    if(fd < 0) 
    { 
     printf("Error opening /dev/ttyS0: %s\n", strerror(errno)); 
     return 1; 
    } 
    printf("Successfully opened /dev/ttyS0\n"); 
    return 0; 
} 

ci sono due utenti in il sistema: root e un utente normale, non root (chiamiamolo "ubuntu") con id = 1000. Il programma di cui sopra sta cercando di aprire una porta seriale (/ dev/ttyS0) due volte: la prima volta come root o ubuntu (a seconda di come viene invocato) e la seconda volta sempre come ubuntu. Il primo tentativo fallito causa l'abortire del programma. L'utente ubuntu è un membro del gruppo dialout quindi, in teoria, ha le autorizzazioni necessarie per aprire/dev/ttyS0. Invoco il programma in quattro modi diversi:

1) gestito direttamente come ubuntu

invocazione:

< percorso per il mio programma >

2) eseguito come Ubuntu, ma l'uso di sudo

invocazione:

sudo -u ubuntu < percorso al mio programma >

3) eseguito come root, ma con privilegi sceso a quelli di ubuntu (così, in modo efficace, eseguito come ubuntu):

invocazione:

sudo su
sudo -u ubuntu < percorso al mio programma >

In tutti e tre i casi ottengo il seguente risultato atteso:

CURRENT UID: 1000, CURRENT GID: 1000 
Successfully opened /dev/ttyS0 

CURRENT UID: 1000, CURRENT GID: 1000 
Successfully opened /dev/ttyS0 

In quest'ultimo caso, però, accade qualcosa di strano:

4) gestiti direttamente come root

invocazione:

sudo su
< percorso per il mio programma >

risultato:

CURRENT UID: 0, CURRENT GID: 0 
Successfully opened /dev/ttyS0 

CURRENT UID: 1000, CURRENT GID: 1000 
Error opening /dev/ttyS0: Permission denied 

Ovviamente sono le ultime due righe dell'output che non capisco: questa volta, quando root elimina i suoi privilegi, risulta che ubuntu ha privilegi insufficienti per aprire/dev/ttyS0, ma perché? In che modo questo caso è diverso dai casi 1-3?

Un'ultima cosa vale la pena menzionare: se cambio questa riga del mio codice:

setgid(1000); 

a questo:

setgid(20); /* 20 is the id of dialout group */ 

poi l'ultimo tentativo di aprire/dev/ttyS0 è successo pure .

Significa che le informazioni su Ubuntu come membro del gruppo dialout vengono perse per qualche motivo quando eseguo il programma come root e poi rilasciamo i privilegi a quelli di ubuntu cambiando uid e gid a 1000? Potete per favore fornirmi una spiegazione dettagliata di cosa succede nel caso 4 del mio esempio e perché il risultato è diverso da quanto mi aspettassi?

+0

"ID utente reale ed effettivo". Oppure [vedi questo] (http://stackoverflow.com/questions/32455684/difference-between-real-user-id-effective-user-id-and-saved-user-id). –

+0

Vedete gli stessi risultati usando 'seteuid' e' setegid'? – tkausl

+0

Se sostituisco tutte le occorrenze di UID, GID, getuid(), getgid(), setuid (1000) e setgid (1000) con EUID, EGID, geteuid(), getegid(), seteuid (1000) e setegid (1000), rispettivamente, il risultato rimane esattamente lo stesso in tutti e quattro i casi. – Peter

risposta

2

Impostazione ID utente e groupid fa non insieme tutti i gruppi supplementari (cioè tutti i gruppi, che non sono il gruppo principale dell'utente ma affidatigli /etc/groups) automagically. Prova a utilizzare

initgroups("ubuntu", 1000); 

prima del setgid() -call. Quindi il processo dovrebbe disporre dei privilegi del dialout .

+0

Grazie, questo deve essere il motivo esatto per cui il mio approccio è fallito. A quanto pare, i suggerimenti di David Schwartz e di tkausi che aveva qualcosa a che fare con euid/egid erano sbagliati. – Peter