sockroot.c (3648B)
1 #include <errno.h> 2 #include <signal.h> 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <string.h> 6 #include <sys/socket.h> 7 #include <sys/stat.h> 8 #include <sys/un.h> 9 #include <sys/wait.h> 10 #include <unistd.h> 11 12 #define SERVER_SOCK_FILE "sockroot.sock" 13 #define CHROOT "test/" 14 #define EXECUTE "/bin/sh" 15 #define SOCKET_LIMIT 64 16 17 int processes[SOCKET_LIMIT]; 18 int processes_size = 0; 19 20 void handle_client(int client) { 21 int pid; 22 23 if (processes_size == SOCKET_LIMIT) { 24 fprintf(stderr, "error: cannot accept client: process-limit reached\n"); 25 return; 26 } 27 28 while ((pid = fork()) == -1) { 29 fprintf(stderr, "warning: fork for process: %s, waiting 1sec...\n", strerror(errno)); 30 sleep(1); 31 } 32 33 if (pid == 0) { // is child 34 dup2(client, 0); 35 dup2(client, 1); 36 dup2(client, 2); 37 close(client); 38 39 if (chroot(CHROOT) == -1) { 40 fprintf(stderr, "error: cannot chroot to '" CHROOT "': %s\n", strerror(errno)); 41 _exit(1); 42 } 43 if (chdir("/") == -1) { 44 fprintf(stderr, "error: cannot chdir to '/': %s\n", strerror(errno)); 45 _exit(1); 46 } 47 48 execl(EXECUTE, EXECUTE, "-i", NULL); 49 fprintf(stderr, "error: cannot execute '" EXECUTE "': %s\n", strerror(errno)); 50 _exit(1); 51 } 52 53 close(client); 54 55 printf("new connection: %d\n", pid); 56 57 for (int i = 0; i < SOCKET_LIMIT; i++) { 58 if (processes[i] == 0) { 59 processes[i] = pid; 60 processes_size++; 61 return; 62 } 63 } 64 } 65 66 void on_child(int signal) { 67 (void) signal; 68 69 int pid, status; 70 if ((pid = wait(&status)) == -1) { 71 fprintf(stderr, "error: cannot await child: %s\n", strerror(errno)); 72 return; 73 } 74 printf("%d terminated\n", pid); 75 76 for (int i = 0; i < SOCKET_LIMIT; i++) { 77 if (processes[i] == pid) { 78 processes[i] = 0; 79 processes_size--; 80 return; 81 } 82 } 83 fprintf(stderr, "error: cannot find %d in process-table\n", pid); 84 } 85 86 void on_interrupt(int signal) { 87 (void) signal; 88 89 for (int i = 0; i < SOCKET_LIMIT; i++) { 90 if (processes[i] > 0 && kill(processes[i], SIGTERM) == -1) { 91 fprintf(stderr, "warning: unable to terminate %d: %s\n", processes[i], strerror(errno)); 92 } 93 } 94 95 while (processes_size > 0) { 96 printf("awaiting %d processes to stop\n", processes_size); 97 sleep(1); 98 } 99 100 if (processes_size > 0) { 101 printf("kill %d left over processes\n", processes_size); 102 for (int i = 0; i < SOCKET_LIMIT; i++) { 103 if (processes[i] > 0 && kill(processes[i], SIGKILL) == -1) { 104 fprintf(stderr, "warning: unable to kill %d: %s\n", processes[i], strerror(errno)); 105 } 106 } 107 sleep(1); 108 } 109 exit(0); 110 } 111 112 int main(void) { 113 if (unlink(SERVER_SOCK_FILE) == -1 && errno != ENOENT) { 114 fprintf(stderr, "error: cannot unlink socket: %s\n", strerror(errno)); 115 return 1; 116 } 117 118 int server; 119 120 if ((server = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { 121 fprintf(stderr, "error: cannot create socket: %s\n", strerror(errno)); 122 return 1; 123 } 124 125 umask(0); 126 127 // bind socket to address 128 struct sockaddr_un addr = { 0 }; 129 addr.sun_family = AF_UNIX; 130 strncpy(addr.sun_path, SERVER_SOCK_FILE, sizeof(addr.sun_path)); 131 if (bind(server, (struct sockaddr*) &addr, sizeof(addr)) == -1) { 132 fprintf(stderr, "error: cannot bind to socket: %s\n", strerror(errno)); 133 return 1; 134 } 135 136 // listen for connections 137 if (listen(server, 5) == -1) { 138 fprintf(stderr, "error: cannot listen socket: %s\n", strerror(errno)); 139 return 1; 140 } 141 142 for (int i = 0; i < SOCKET_LIMIT; i++) { 143 processes[i] = 0; 144 } 145 146 signal(SIGINT, on_interrupt); 147 signal(SIGCHLD, on_child); 148 149 while (1) { 150 int client_fd; 151 if ((client_fd = accept(server, NULL, NULL)) == -1) { 152 fprintf(stderr, "error: cannot accept client from socket: %s\n", strerror(errno)); 153 continue; 154 } 155 handle_client(client_fd); 156 } 157 158 return 0; 159 }