#include #include #include #include #include #include #include #include #include #include #include #include static int send_fd(int s, int fd) { struct iovec iov = {.iov_base = "", .iov_len = 1}; union { char buf[CMSG_SPACE(sizeof(fd))]; struct cmsghdr align; } u; struct msghdr msg = {.msg_iov = &iov, .msg_iovlen = 1, .msg_control = u.buf, .msg_controllen = sizeof(u.buf)}; struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); *cmsg = (struct cmsghdr){.cmsg_level = SOL_SOCKET, .cmsg_type = SCM_RIGHTS, .cmsg_len = CMSG_LEN(sizeof(fd))}; bcopy(&fd, CMSG_DATA(cmsg), sizeof(fd)); return sendmsg(s, &msg, 0); } static int recv_fd(int s) { int fd; char b0[1]; struct iovec iov; struct msghdr msg; union { char buf[CMSG_SPACE(sizeof(fd))]; struct cmsghdr align; } u; struct cmsghdr *cmsg; bzero(&msg, sizeof(msg)); iov.iov_base = b0; iov.iov_len = 1; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = u.buf; msg.msg_controllen = sizeof(u.buf); if(recvmsg(s, &msg, 0)<0) { fprintf(stderr, "recvmsg() error %d (%s)\n", errno, strerror(errno)); return -1; } if(msg.msg_controllen!=sizeof(u.buf)) { fprintf(stderr, "wrong recv\n"); return -1; } if(!(cmsg = CMSG_FIRSTHDR(&msg))) { fprintf(stderr, "wrong recv 2\n"); return -1; } if(cmsg->cmsg_level!=SOL_SOCKET || cmsg->cmsg_type!=SCM_RIGHTS || cmsg->cmsg_len!=CMSG_LEN(sizeof(fd))) { fprintf(stderr, "wrong recv 2\n"); return -1; } bcopy(CMSG_DATA(cmsg), &fd, sizeof(fd)); return fd; } static int do_listen(char const * spath, char const * fpath) { int lfd, afd, fd; struct sockaddr_un sa; struct stat sb; bzero(&sa, sizeof(sa)); sa.sun_family = AF_UNIX; strcpy(sa.sun_path,spath); if(lstat(spath,&sb)>=0 && S_ISSOCK(sb.st_mode)) unlink(spath); if((lfd = socket(PF_UNIX, SOCK_STREAM, 0))<0) { fprintf(stderr, "socket() error %d (%s)\n", errno, strerror(errno)); return -1; } if(bind(lfd, (struct sockaddr*)&sa, sizeof(sa))<0) { fprintf(stderr, "bind() error %d (%s)\n", errno, strerror(errno)); return -1; } if(listen(lfd, 1)<0) { fprintf(stderr, "listen() error %d (%s)\n", errno, strerror(errno)); return -1; } if((fd = open(fpath,O_RDONLY))<0) { fprintf(stderr, "open() error %d (%s)\n", errno, strerror(errno)); return -1; } while(1) { if((afd = accept(lfd, NULL, NULL))<0) { fprintf(stderr, "accept() error %d (%s)\n", errno, strerror(errno)); sleep(1); continue; } if(send_fd(afd, fd)<0) fprintf(stderr, "send_fd() error %d (%s)\n", errno, strerror(errno)); sleep(1); close(afd); } } static int do_connect(char const * spath) { int fd; struct sockaddr_un sa; bzero(&sa, sizeof(sa)); sa.sun_family = AF_UNIX; strcpy(sa.sun_path,spath); if((fd = socket(PF_UNIX, SOCK_STREAM, 0))<0) { fprintf(stderr, "socket() error %d (%s)\n", errno, strerror(errno)); return -1; } if(connect(fd, (struct sockaddr*)&sa, sizeof(sa))<0) { fprintf(stderr, "connect() error %d (%s)\n", errno, strerror(errno)); return -1; } return fd; } static int do_read(int fd) { char buf[1024]; int l; while((l=read(fd,buf,sizeof(buf)))>0) write(1,buf,l); if(l<0) { fprintf(stderr, "read error %d (%s)\n", errno, strerror(errno)); return -1; } return 0; } static int do_ls(int fd, char const * path) { DIR * dp; struct dirent * de; if(path && (fd=openat(fd,path,O_RDONLY))<0) { fprintf(stderr, "open(%s) error %d (%s)\n", path, errno, strerror(errno)); return -1; } if(!(dp=fdopendir(fd))) { fprintf(stderr, "fdopendir error %d (%s)\n", errno, strerror(errno)); return -1; } while(errno=0,de=readdir(dp)) { printf("%s\n", de->d_name); } if(errno) { fprintf(stderr, "readdir error %d (%s)\n", errno, strerror(errno)); return -1; } return 0; } int main(int argc, char * * argv) { int fd, rfd; if(argc==4 && !strcmp(argv[1],"listen")) return do_listen(argv[2],argv[3]); if(argc!=3 || !strcmp(argv[1],"listen")) return -1; if((fd = do_connect(argv[2]))<0) return -1; if((rfd = recv_fd(fd))<0) return -1; fprintf(stderr, "rfd = %d\n", rfd); if(!strcmp(argv[1],"read")) do_read(rfd); if(!strcmp(argv[1],"ls")) do_ls(rfd,NULL); if(!strncmp(argv[1],"ls:",3)) do_ls(rfd,argv[1]+3); if(!strcmp(argv[1],"sleep")) while(1) sleep(1); if(!strcmp(argv[1],"sh")) { if(fchdir(rfd)<0) { fprintf(stderr, "fchdir() error %d (%s)\n", errno, strerror(errno)); return -1; } system("/bin/sh"); } return 0; }