История изменений
Исправление firkax, (текущая версия) :
Первый способ - вызов статической команды шелла
#include <stdlib.h>
int main(int argc, char **argv) {
system("echo 123");
reutrn 0;
}
Второй способ - вызов команды шелла с меняющимися аргументами
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
char buf[10000];
snprintf(buf, sizeof(buf), "echo %d", atoi(argv[1]));
if(strlen(buf)>=sizeof(buf)-1) { fprintf(stderr, "cmd too long\n"); return -1; }
system(buf);
reutrn 0;
}
1) делать тупо printf всего подряд нельзя, если хочешь передать строку, предоставленную юзером - её надо экранировать (это отдельная возня), иначе юзер может передать строку типа " ; echo qwe > /etc/passwd" которую шелл (функция system вызывает его) распарсит как команду
2) надо следить чтобы не переполнился буфер
Вобщем, не рекомендую этот способ, он чреват дырами, поэтому см. третий.
Третий способ - вызов нужной программы или скрипта без шелла
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
extern char **environ;
int main(int argc, char **argv) {
argv[0] = "/usr/local/sbin/wrapped_script.sh";
execve("/usr/local/sbin/wrapped_script.sh", argv, environ);
fprintf(stderr, "execve(/usr/local/sbin/wrapped_script.sh) error %d (%s)\n", errno, strerror(errno));
return -1;
}
Тут программа просто запускает скрипт и передаёт ему все свои аргументы как есть. Опасности того, что на этом этапе что-то не так распарсится, нет - никакого парсинга тут не происходит. Вся ответственность за парсинг будет лежать на скрипте. На такую программу уже можно поставить setuid-root, в отличие от шелл-скрипта.
Но как скрипту в такой схеме узнать какой юзер его запустил я не знаю. Возможно там есть какой-нить аналог getuid().
Исходная версия firkax, :
Первый способ - вызов статической команды шелла
#include <stdlib.h>
int main(int argc, char **argv) {
system("echo 123");
reutrn 0;
}
Второй способ - вызов команды шелла с меняющимися аргументами
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
char buf[10000];
snprintf(buf, sizeof(buf), "echo %d", atoi(argv[1]));
if(strlen(buf)>=sizeof(buf)-1) { fprintf(stderr, "cmd too long\n"); return -1; }
system(buf);
reutrn 0;
}
1) делать тупо printf всего подряд нельзя, если хочешь передать строку, предоставленную юзером - её надо экранировать (это отдельная возня), иначе юзер может передать строку типа " ; echo qwe > /etc/passwd" которую шелл (функция system вызывает его) распарсит как команду
2) надо следить чтобы не переполнился буфер
Вобщем, не рекомендую этот способ, он чреват дырами, поэтому см. третий.
Третий способ - вызов нужной программы или скрипта без шелла
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
extern char **environ;
int main(int argc, char **argv) {
argv[0] = "/usr/local/sbin/wrapped_script.sh";
execve("/usr/local/sbin/wrapped_script.sh", argv, environ);
fprintf(stderr, "execve(/usr/local/sbin/wrapped_script.sh) error %d (%s)\n", errno, strerror(errno));
return -1;
}
Тут программа просто запускает скрипт и передаёт ему все свои аргументы как есть. Опасности того, что на этом этапе что-то не так распарсится, нет - никакого парсинга тут не происходит. Вся ответственность за парсинг будет лежать на скрипте. На такую программу уже можно поставить setuid-root, в отличие от шелл-скрипта.