// // libsyd: Rust-based C library for syd interaction via /dev/syd // lib/examples/shell_server.c: syd API C Library Shell Server Example // // Copyright (c) 2023 Ali Polatel // // SPDX-License-Identifier: GPL-3.0 /* * Compile this with: * cc -fPIC -fPIE shell_server.c -oshell_server -static-pie -lsyd * Run with: * syd -pcontainer ./shell_server * This binds to port 127.0.0.1:65432 */ /* * SAFETY: This server code is insecure. * It passes the command without any validation * to /bin/sh -c "$command". * This is done with the intention to display syd' abilities. */ #include #include #include #include #include #include #include #include #include #define PORT 65432 // Port number for the server #define BUFFER_SIZE 1024 // Size of the buffer for incoming messages int main() { int server_fd, new_socket; struct sockaddr_in address; int r, opt = 1; int addrlen = sizeof(address); char buffer[BUFFER_SIZE] = {0}; bool should_quit = false; // Flag to indicate if the server should quit char *sh = realpath("/bin/busybox", NULL); if (!sh) { err(1, "Failed to determine real path to /bin/busybox"); } if ((r = syd_check()) != 0) { errno = -r; err(1, "Not running under syd"); } // Creating socket file descriptor if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { err(1, "socket failed"); } // Forcefully attaching socket to the port 65432 if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) { err(1, "setsockopt"); } address.sin_family = AF_INET; address.sin_addr.s_addr = htonl(INADDR_LOOPBACK); address.sin_port = htons(PORT); if ((r = syd_allow_net_bind_add("LOOPBACK!65432")) != 0) { errno = -r; err(1, "Failed to allow LOOPBACK!65432"); } // Binding the socket to the port 65432 if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { err(1, "bind failed"); } if ((r = syd_allow_net_bind_del("LOOPBACK!65432")) != 0) { errno = -r; err(1, "Failed to allow LOOPBACK!65432"); } if ((r = syd_allow_exec_add(sh)) != 0) { errno = -r; err(1, "Failed to allow %s for exec", sh); } if ((r = syd_allow_stat_add(sh)) != 0) { errno = -r; err(1, "Failed to allow %s for stat", sh); } if ((r = syd_lock(LOCK_ON)) != 0) { errno = -r; err(1, "Failed to lock syd"); } // Listening for incoming connections if (listen(server_fd, 3) < 0) { err(1, "listen"); } for (;;) { printf("*** Waiting for a connection...\n"); // Accepting an incoming connection if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) { err(1, "accept"); } printf("*** Connection established\n"); // Read data from the client, execute it, and send back the output ssize_t read_bytes; while ((read_bytes = read(new_socket, buffer, BUFFER_SIZE - 1)) > 0) { buffer[read_bytes] = '\0'; // Null-terminate the string if (strncmp(buffer, "QUIT", 4) == 0) { printf("Received 'QUIT', exiting.\n"); should_quit = 1; // Set the flag to break out of the outer loop break; } FILE *fp; char command_output[BUFFER_SIZE]; char command[BUFFER_SIZE + 10]; snprintf(command, sizeof(command), "/bin/busybox sh -c \"%s\" 2>&1", buffer); fp = popen(command, "r"); if (fp == NULL) { printf("Failed to run command\n"); continue; } // Read the output of the command while (fgets(command_output, sizeof(command_output), fp) != NULL) { write(new_socket, command_output, strlen(command_output)); } pclose(fp); memset(buffer, 0, BUFFER_SIZE); // Clear the buffer } if (read_bytes < 0) { err(1, "read"); } close(new_socket); printf("Connection closed\n"); if (should_quit) { break; // Exit the outer loop if "QUIT" was received } } printf("*** Shutting down server.\n"); close(server_fd); return 0; }