#include #include #include #include #include #include #include #include #include #include static void __zoid_signal_handler(int signo); static int server_sock; /* * Function run at startup. Just installs the signal handler that zoidd * will later trigger, and a server-side unix domain socket. */ void __zoid_ciod_startup(void) __attribute__((constructor)); void __zoid_ciod_startup(void) { struct sigaction sa; struct sockaddr_un addr; sa.sa_handler = __zoid_signal_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; if (sigaction(SIGUSR1, &sa, NULL)) perror("installing signal handler"); if (!(server_sock = socket(PF_UNIX, SOCK_STREAM, 0))) { perror("create unix domain socket"); return; } addr.sun_family = AF_UNIX; strcpy(addr.sun_path, "/tmp/zoidd.socket"); if (bind(server_sock, (struct sockaddr*)&addr, sizeof(addr))) { perror("bind /tmp/zoidd.socket"); return; } if (listen(server_sock, 5) < 0) { perror("listen"); return; } } static void __zoid_signal_handler(int signo) { BGLPersonality personality; int fd; FILE* file; char buffer[1024]; int inode_8000 = -1, fd_8000 = -1; DIR* dir; struct dirent *de; struct msghdr msg = {0}; struct cmsghdr *cmsg; char msgbuf[CMSG_SPACE(sizeof(int))]; uid_t uid; int transfer_sock; struct iovec iov; char tmp; /* Get service node's IP address from personality. */ if ((fd = open("/proc/personality", O_RDONLY)) < 0) { perror("open /proc/personality"); return; } if (read(fd, &personality, sizeof(personality)) != sizeof(personality)) { perror("read personality"); return; } close(fd); /* Find the inode of the port 8000 connection to the service node, used by CIOD to forward stdout/stderr. */ if (!(file = fopen("/proc/net/tcp", "r"))) { perror("open /proc/net/tcp"); return; } while (fgets(buffer, sizeof(buffer), file) == buffer) { int local_port, remote_address, inode; if (sscanf(buffer, "%*d: %*x:%x %x:%*x %*x %*x:%*x %*x:%*x %*x %*d %*d %d", &local_port, &remote_address, &inode) == 3 && remote_address == personality.serviceNode && local_port == 8000) { inode_8000 = inode; break; } } fclose(file); if (inode_8000 < 0) { fprintf(stderr, "Socket connection to the service node not found!\n"); return; } /* Now locate the file descriptor that owns this socket. We need to switch back to root for a second to do that... */ uid = geteuid(); if (seteuid(0) < 0) { perror("seteuid"); return; } if (!(dir = opendir("/proc/self/fd"))) { perror("open /proc/self/fd"); return; } while ((de = readdir(dir))) { char buf2[1024]; int len; sprintf(buffer, "/proc/self/fd/%s", de->d_name); if ((len = readlink(buffer, buf2, sizeof(buf2))) > 0 && len < sizeof(buf2)) { buf2[len] = '\0'; if (strncmp(buf2, "socket:", strlen("socket:")) == 0) { int inode; char* endbuf; inode = strtol(buf2 + strlen("socket:["), &endbuf, 10); if (inode == inode_8000) { fd_8000 = strtol(de->d_name, NULL, 10); break; } } } } closedir(dir); if (seteuid(uid) < 0) { perror("seteuid"); return; } if (fd_8000 < 0) { fprintf(stderr, "Socket connection to the service node not found!\n"); return; } if ((transfer_sock = accept(server_sock, NULL, 0)) < 0) { perror("accept"); return; } /* This magic is taken from cmsg(3). */ iov.iov_base = &tmp; iov.iov_len = 1; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = msgbuf; msg.msg_controllen = sizeof(msgbuf); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN(sizeof(int)); memcpy(CMSG_DATA(cmsg), &fd_8000, sizeof(int)); msg.msg_controllen = cmsg->cmsg_len; if (sendmsg(transfer_sock, &msg, 0) < 0) { perror("sendmsg"); return; } close(transfer_sock); close(server_sock); kill(getpid(), SIGSTOP); }