s6-sudoc.c (4005B)
1 /* ISC license. */ 2 3 #include <string.h> 4 #include <stdint.h> 5 #include <errno.h> 6 #include <fcntl.h> 7 #include <signal.h> 8 #include <sys/uio.h> 9 #include <sys/wait.h> 10 11 #include <skalibs/types.h> 12 #include <skalibs/sgetopt.h> 13 #include <skalibs/buffer.h> 14 #include <skalibs/stralloc.h> 15 #include <skalibs/strerr.h> 16 #include <skalibs/djbunix.h> 17 #include <skalibs/tai.h> 18 #include <skalibs/env.h> 19 #include <skalibs/unix-timed.h> 20 #include <skalibs/unixmessage.h> 21 22 #include "s6-sudo.h" 23 24 #define USAGE "s6-sudoc [ -e ] [ -t timeoutconn ] [ -T timeoutrun ] [ args... ]" 25 #define dieusage() strerr_dieusage(100, USAGE) 26 #define dienomem() strerr_diefu1sys(111, "stralloc_catb") 27 28 int main (int argc, char const *const *argv, char const *const *envp) 29 { 30 char buf6[64] ; 31 buffer b6 = BUFFER_INIT(&buffer_read, 6, buf6, 64) ; 32 unixmessage_sender b7 = UNIXMESSAGE_SENDER_INIT(7) ; 33 subgetopt l = SUBGETOPT_ZERO ; 34 unsigned int t = 0, T = 0 ; 35 int doenv = 1 ; 36 37 tain deadline = TAIN_INFINITE_RELATIVE ; 38 PROG = "s6-sudoc" ; 39 for (;;) 40 { 41 int opt = subgetopt_r(argc, argv, "et:T:", &l) ; 42 if (opt < 0) break ; 43 switch (opt) 44 { 45 case 'e' : doenv = 0 ; break ; 46 case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ; 47 case 'T' : if (!uint0_scan(l.arg, &T)) dieusage() ; break ; 48 default : dieusage() ; 49 } 50 } 51 argc -= l.ind ; argv += l.ind ; 52 if (t) tain_from_millisecs(&deadline, t) ; 53 if ((ndelay_on(6) < 0) || (ndelay_on(7) < 0)) 54 strerr_diefu1sys(111, "make socket non-blocking") ; 55 if (!fd_sanitize() || !fd_ensure_open(2, 1)) 56 strerr_diefu1sys(111, "sanitize stdin/stdout/stderr") ; 57 58 tain_now_set_stopwatch_g() ; 59 tain_add_g(&deadline, &deadline) ; 60 { 61 size_t r ; 62 char tmp[S6_SUDO_BANNERB_LEN] ; 63 r = buffer_timed_get_g(&b6, tmp, S6_SUDO_BANNERB_LEN, &deadline) ; 64 if (!r) 65 strerr_diefu1x(111, "connect to the s6-sudod server - check that you have appropriate permissions") ; 66 if (r < S6_SUDO_BANNERB_LEN) 67 strerr_diefu1sys(111, "read banner from s6-sudod") ; 68 if (strncmp(tmp, S6_SUDO_BANNERB, S6_SUDO_BANNERB_LEN)) 69 strerr_dief1x(100, "wrong banner - check that you are connecting to a s6-sudod server") ; 70 } 71 { 72 int fds[3] = { 0, 1, 2 } ; 73 char pack[16] ; 74 struct iovec v[4] = { 75 { .iov_base = S6_SUDO_BANNERA, .iov_len = S6_SUDO_BANNERA_LEN }, 76 { .iov_base = pack, .iov_len = 16 }, 77 { .iov_base = 0, .iov_len = 0 }, 78 { .iov_base = 0, .iov_len = 0 } } ; 79 unixmessagev mv = { .v = v, .vlen = 4, .fds = fds, .nfds = 3 } ; 80 stralloc sa = STRALLOC_ZERO ; 81 size_t envlen = doenv ? env_len(envp) : 0 ; 82 uint32_pack_big(pack, (uint32_t)argc) ; 83 uint32_pack_big(pack + 4, (uint32_t)envlen) ; 84 if (!env_string(&sa, argv, argc)) dienomem() ; 85 v[2].iov_len = sa.len ; 86 uint32_pack_big(pack + 8, (uint32_t)v[2].iov_len) ; 87 if (doenv) 88 { 89 if (!env_string(&sa, envp, envlen)) dienomem() ; 90 v[3].iov_len = sa.len - v[2].iov_len ; 91 } 92 uint32_pack_big(pack + 12, (uint32_t)v[3].iov_len) ; 93 v[2].iov_base = sa.s ; 94 v[3].iov_base = sa.s + v[2].iov_len ; 95 if (!unixmessage_putv_and_close(&b7, &mv, (unsigned char const *)"\003")) 96 strerr_diefu1sys(111, "unixmessage_putv") ; 97 stralloc_free(&sa) ; 98 } 99 if (!unixmessage_sender_timed_flush_g(&b7, &deadline)) 100 strerr_diefu1sys(111, "send args to server") ; 101 unixmessage_sender_free(&b7) ; 102 { 103 char c ; 104 if (buffer_timed_get_g(&b6, &c, 1, &deadline) < 1) 105 strerr_diefu1sys(111, "get confirmation from server") ; 106 if (c) 107 { 108 errno = c ; 109 strerr_diefu1sys(111, "start privileged program: server answered: ") ; 110 } 111 } 112 113 if (T) tain_from_millisecs(&deadline, T) ; else deadline = tain_infinite_relative ; 114 tain_add_g(&deadline, &deadline) ; 115 { 116 char pack[UINT_PACK] ; 117 if (buffer_timed_get_g(&b6, pack, UINT_PACK, &deadline) < UINT_PACK) 118 strerr_diefu1sys(111, "get exit status from server") ; 119 uint_unpack_big(pack, &t) ; 120 } 121 return wait_estatus(t) ; 122 }