miniroon-read.c (5115B)
1 #include <errno.h> 2 #include <unistd.h> 3 #include <sys/select.h> 4 #include <stdlib.h> 5 #include <assert.h> 6 7 #include <skalibs/types.h> 8 #include <skalibs/strerr.h> 9 #include <skalibs/djbunix.h> 10 #include <skalibs/exec.h> 11 #include <skalibs/netstring.h> 12 #include <skalibs/stralloc.h> 13 #include <skalibs/env.h> 14 15 #include "netstring.h" 16 #include "miniroon-header.h" 17 18 #define USAGE "miniroon-read directory" 19 #define PROG "miniroon-read" 20 21 #define input_fd 0 22 #define payload_size_max 1024*1024 23 #define MAX_CAVEATS 256 24 #define MAX_ENV_ALLOW 256 25 26 27 void fd_block(int fd) { 28 int flags = fcntl(fd, F_GETFL); 29 if(flags == -1) { 30 strerr_dief1sys(111, "fcntl() getfd"); 31 } 32 if(fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) < 0) { 33 strerr_dief1sys(111, "fcntl() setfd"); 34 } 35 } 36 37 size_t read_payload_size(int fd) { 38 char read_char; 39 size_t payload_size = 0; 40 41 fd_block(fd); 42 43 while(payload_size < payload_size_max) { 44 switch(read(fd, &read_char, 1)) { 45 case 0: 46 strerr_dief1x(111, "EOF before netstring size was read"); 47 break; 48 case 1: 49 if(read_char == ':') { 50 return payload_size; 51 } else if(read_char >= '0' && read_char <= '9') { 52 payload_size *= 10; 53 payload_size += read_char - '0'; 54 } else { 55 strerr_dief1x(111, "Malformed netstring on input"); 56 } 57 break; 58 case -1: 59 if(errno != EINTR) { 60 strerr_dief1sys(111, "read() length"); 61 } 62 break; 63 default: 64 strerr_dief1x(110, "Unexpected return value from read()"); 65 break; 66 } 67 } 68 69 strerr_dief1x(111, "Input netstring too big"); 70 } 71 72 void read_payload(const bytebuffer bb) { 73 char *read_next = bb.data; 74 ssize_t read_size; 75 while(read_next - bb.data < bb.len) { 76 read_size = read(input_fd, read_next, bb.len - (read_next - bb.data)); 77 if(read_size == 0) { 78 strerr_dief1x(111, "EOF before full netstring payload was read"); 79 } 80 if(read_size == -1) { 81 if(errno != EINTR) { 82 strerr_dief1sys(111, "read() payload"); 83 } 84 continue; 85 } 86 read_next += read_size; 87 } 88 if(bb.data[bb.len - 1] != ',') { 89 strerr_dief1x(111, "Invalid netstring terminator"); 90 } 91 } 92 93 void process_header(miniroon_header *header, const bytebuffer source) { 94 parse_header(header, source); 95 96 char id[header->id.len + 1]; 97 for(size_t i=0; i<header->id.len; i++) { 98 id[i] = header->id.data[i]; 99 if(id[i] == '-') { continue; } 100 if(id[i] >= '0' && id[i] <= '9') { continue; } 101 if(id[i] >= 'a' && id[i] <= 'z') { continue; } 102 strerr_dief1x(111, "Invalid character in miniroon ID"); 103 } 104 id[header->id.len] = 0; 105 106 if (chdir(id) != 0) { 107 strerr_dief1sys(111, "chdir(id)"); 108 } 109 } 110 111 void exec_verify_and_write_payload (const bytebuffer payload); 112 void process_payload(const bytebuffer payload) { 113 miniroon_header header; 114 netstring_chunk c; 115 netstring_chunk_init(&c, payload); 116 117 if(!netstring_chunk_next(&c)) { 118 strerr_dief1x(111, "Mising miniroon header"); 119 } 120 process_header(&header, c.inner); 121 exec_verify_and_write_payload(payload); 122 } 123 124 void exec_verify_and_write_payload (const bytebuffer payload) { 125 pid_t pid1=0, pid2=0; 126 int wstat ; 127 int p[2] ; 128 129 if(pipe(p) == -1) { 130 strerr_diefu1sys(111, "create pipe"); 131 } 132 133 pid1 = fork(); 134 switch(pid1) { 135 case -1: 136 strerr_diefu1sys(111, "first fork()"); 137 break; 138 case 0: /* child */ 139 fd_close(p[0]); 140 pid2 = fork(); 141 switch(pid2) { 142 case -1: 143 strerr_diefu1sys(111, "second fork()"); 144 break; 145 case 0: /* child */ 146 ssize_t payload_write = fd_write(p[1], payload.data, payload.len); 147 if(payload_write < 0 ) { 148 strerr_dief1sys(111, "write(payload)"); 149 } 150 if(payload_write != payload.len) { 151 strerr_dief1x(111, "could not write whole payload"); 152 } 153 exit(0); 154 break; 155 default: /* parent */ 156 exit(0); 157 break; 158 } 159 break; 160 default: /* parent */ 161 waitpid_nointr(pid1, &wstat, 0); 162 if(!WIFEXITED(wstat) || WEXITSTATUS(wstat) != 0) { 163 strerr_dief1x(111, "child terminated abnormally"); 164 } 165 166 char cmd[] = "./verify"; 167 char fmt_fd[UINT64_FMT], fmt_len[UINT64_FMT]; 168 fmt_fd[uint64_fmt(fmt_fd, (uint64_t)p[0])] = 0; 169 fmt_len[uint64_fmt(fmt_len, (uint64_t)payload.len)] = 0; 170 const char *cmd_argv[4] = {cmd, fmt_fd, fmt_len, 0}; 171 172 fd_close(p[1]); 173 xexec(cmd_argv); 174 break; 175 } 176 } 177 178 int main (int argc, char const *const *argv) 179 { 180 181 if (argc != 2) { 182 strerr_dieusage(100, USAGE); 183 } 184 185 if (chdir(argv[1]) != 0) { 186 strerr_dief1sys(111, "chdir()"); 187 } 188 size_t payload_size = read_payload_size(input_fd); 189 char payload_data[payload_size + 1]; 190 bytebuffer payload = {payload_data, payload_size + 1}; 191 read_payload(payload); 192 payload.len -= 1; /* strip final netstring terminator */ 193 dbg_print_bb1("Got payload", payload); 194 process_payload(payload); 195 assert(0); 196 strerr_dief1x(110, "Internal logic error, should not get here"); 197 return 110; 198 } 199 200 /* vim: sts=2 sw=2 et 201 */