2012-02-15 2 views
6

У меня есть процесс с разрешениями 4750. В моей системе Linux есть два пользователя. Пользователь root и пользователь appz. Процесс наследует разрешения диспетчера процессов, который работает как пользователь «appz».правильный способ запускать программы setuid в C

У меня есть две основные процедуры:

void do_root (void) 
{ 
     int status; 
     status = seteuid (euid); 
     if (status < 0) { 
     exit (status); 
     }  
} 

/* undo root permissions */ 
void undo_root (void) 
{ 
int status; 
     status = seteuid (ruid); 
     if (status < 0) { 
       exit (status); 
     } 
     status = setuid(ruid); 
     if (status < 0) { 
       exit (status); 
     } 
} 

Мой поток следующее:

int main() { 
undo_root(); 
do some stuff; 
do_root(); 
bind(port 80); //needs root perm 
undo_root(); 
while(1) { 

    accept commads() 
    if (commands needs root user access) 
    { 
     do_root(); 
     execute(); 
     undo_root(); 

    } 

} 

Как вы можете видеть, что я хочу, чтобы выполнить некоторые команды, как корень. Я пытаюсь временно удалить разрешения, и если задачам нужен доступ с правами root, я завершаю команду между вызовом do_root и undo_root.

Однако, похоже, что моя программа не работает.

Что такое канонический способ сделать это?

+0

Вместо того, чтобы просто выйти из строя при сбое seteuid, вызовите функцию perror() и ваша программа расскажет вам, почему она терпит неудачу. –

+4

Как только вы отбросите права root, вы не сможете их вернуть! – Petesh

+0

Технически это файл с программой, которая имеет разрешение 4750, а не процесс. Вы прямо не говорите, что разрешения «root: group: 4750' - это безопасный вывод? –

ответ

5

старой школы путь в обоих do_root и undo_root использовать setreuid(), чтобы поменять местами RUID и EUID:

setreuid(geteuid(), getuid()); 

Это вполне приемлемо, если программа достаточно мал, чтобы сделать полный аудит безопасности ,

Путь к новой школе намного сложнее и включает в себя fork() от дочернего элемента, который принимает директивы для того, что делать как root, а затем выполняет setuid (getuid()), чтобы в корне полностью оставить корень. ребенок отвечает за проверку всех директив, которые он получает. Для достаточно большой программы это уменьшает количество кода, который должен быть проверен системой безопасности, и позволяет пользователю управлять процессом с помощью управления заданиями или убивать его и т. Д.

+0

Что вы имеете в виду? Просто скопируйте и вставьте код в обе функции? – cateof

+0

Да. __________ – Joshua

2

setuid человек страница говорит следующее:

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

Это означает, что вы не можете использовать setuid(). Вы должны использовать seteuid() и, возможно, setreuid(). См. Setuid Program Example для более подробной информации.

+0

Моя программа основана именно на этой странице GNU. Вместо do_setuid, я изначально сделал do_root. – cateof

+0

@cateof: Я вижу, что вы используете функцию setuid в коде, который вы опубликовали. Это билет в один конец. –

5

Существует статья «Setuid Demystified» Хао Чена, Дэвида Вагнера и Дрю Дин. Он был представлен в USENIX 2002. Он описывает, как setuid() и переходы работают очень подробно (с 2002 года). Стоит прочитать (несколько раз - я должен быть год или два просрочены по перечитыванию).

Фундаментально, а Petesh отметил в комментарии, когда процесс с EUID 0 делает setuid(nuid) с nuid != 0, нет пути назад к root (EUID 0) привилегий. И действительно, очень важно, чтобы это было так. В противном случае при входе в систему процесс root, который регистрирует вас, не может ограничивать ваши собственные привилегии - вы сможете вернуться к root. Сохраненный UID усложняет ситуацию, но я не считаю, что это влияет на одностороннюю ловушку EUID 0, делая setuid().

 Смежные вопросы

  • Нет связанных вопросов^_^