util/sockroot

src/exec/sockroot.c in master
Repositories | Summary | Log | Files

sockroot.c (3648B) download


  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
 17int processes[SOCKET_LIMIT];
 18int processes_size = 0;
 19
 20void 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
 66void 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
 86void 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
112int 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}