Не всегда легко найти замену функции system(). Первый вариант -
использовать системные вызовы такие как execl() или
execle(). Однако это будет совсем не то, так как внешняя программа
будет вызываться не как подпрограмма, а будет заменять текущий процесс. Вам
придется создать новый процесс при помощи fork и проанализировать аргументы
командной строки. Таким образом программа:
pid_t pid;
int status;
if ((pid = fork()) < 0) {
perror("fork");
return (-1);
}
if (pid == 0) {
/* дочерний процесс */
execl ("/bin/lpr", "lpr", "-Plisting", "stats.txt", NULL);
perror ("execl");
exit (-1);
}
/* родительский процесс */
waitpid (pid, & status, 0);
if ((! WIFEXITED (status)) || (WEXITSTATUS (status) != 0)) {
perror ("Printing");
return (-1);
}
Очевидно, код стал тяжелее! В некоторых ситуациях он
становиться довольно сложным, например, когда вам надо перенаправить стандартный
вход приложения, как например:
system ("mail root < stat.txt");
То есть перенаправление обозначенное <
делается оболочкой. Вы можете делать то же используя сложную последовательность
такую как fork(), open(), dup2(),
execl() и т.д. В таком случае, приемлемым решением будет
использование функции system(), но с предварительной конфигурацией
всего окружения.
Под Linux переменные окружения хранятся в форме указателя на таблицу
символов: char ** environ. Эта таблица заканчивается NULL. Строки
хранятся в форме "ИМЯ=значение".
Мы начинаем удаление окружения при помощи Gnu расширения:
int clearenv (void);
или присваивая указателю
extern char ** environ;
значение NULL. Далее инициализируются важные переменные
окружения, используя контролируемые значения, при помощи функций:
int setenv (const char * name, const char * value, int remove)
int putenv(const char *string)
Если необходимо, вы можете сохранить содержимое некоторых
полезных переменных перед очищением окружения (HOME,
LANG, TERM, TZ и т.д.). Содержимое, форма
представления, размер этих переменных должны быть строго проверены. Это важно,
что вы очищаете все окружение перед переопределением нужных переменных. Дыра в
suidperl не появилась бы, если должным образом было бы очищено
окружение.
По аналогии, защита машины в сети, во-первых, предпологает запрет всякого
подключения. Затем, сисадмин активизирует необходимые или полезные сервисы. Тем
же методом, при программировании Set-UID приложения окружение должно быть
очищено, а затем заполнено нужными переменными.
Проверка формата параметра происходит при помощи сравнения ожидаемого
значения с разрешенными форматами. Если сравнение успешно, параметр принимается.
Иначе он отвергается. Если вы запускаете тест, используя список неправильных
значений формата, возрастает риск передачи неправильного значения, что может
привести к краху системы.
Мы должны понимать, не забывая о переменной PATH, что опасность
использования system() сохраняется при использовании некоторых
производных функций таких как popen() или системных вызовов,
например, execlp() или execvp().