miniroon

Simplistic macaroon-based authorization for Unix systems
git clone https://ccx.te2000.cz/git/miniroon
Log | Files | Refs

cmd_read.c (4854B)


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