qmail-popup.c (4011B)
1 #include "commands.h" 2 #include "fd.h" 3 #include "sig.h" 4 #include "stralloc.h" 5 #include "substdio.h" 6 #include "alloc.h" 7 #include "wait.h" 8 #include "str.h" 9 #include "byte.h" 10 #include "now.h" 11 #include "fmt.h" 12 #include "exit.h" 13 #include "noreturn.h" 14 #include "readwrite.h" 15 #include "timeoutread.h" 16 #include "timeoutwrite.h" 17 18 void _noreturn_ die() { _exit(1); } 19 20 GEN_SAFE_TIMEOUTREAD(saferead,1200,fd,die()) 21 GEN_SAFE_TIMEOUTWRITE(safewrite,1200,fd,die()) 22 23 char ssoutbuf[128]; 24 substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof(ssoutbuf)); 25 26 char ssinbuf[128]; 27 substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof(ssinbuf)); 28 29 void puts(s) char *s; 30 { 31 substdio_puts(&ssout,s); 32 } 33 void flush() 34 { 35 substdio_flush(&ssout); 36 } 37 void err(s) char *s; 38 { 39 puts("-ERR "); 40 puts(s); 41 puts("\r\n"); 42 flush(); 43 } 44 45 void _noreturn_ die_usage() { err("usage: popup hostname subprogram"); die(); } 46 void _noreturn_ die_nomem() { err("out of memory"); die(); } 47 void _noreturn_ die_pipe() { err("unable to open pipe"); die(); } 48 void _noreturn_ die_write() { err("unable to write pipe"); die(); } 49 void _noreturn_ die_fork() { err("unable to fork"); die(); } 50 void die_childcrashed() { err("aack, child crashed"); } 51 void die_badauth() { err("authorization failed"); } 52 53 void err_syntax() { err("syntax error"); } 54 void err_wantuser() { err("USER first"); } 55 void err_authoriz(arg) char *arg; { err("authorization first"); } 56 57 void okay(arg) char *arg; { puts("+OK \r\n"); flush(); } 58 void _noreturn_ pop3_quit(char *arg) { okay(0); die(); } 59 60 61 char unique[FMT_ULONG + FMT_ULONG + 3]; 62 char *hostname; 63 stralloc username = {0}; 64 int seenuser = 0; 65 char **childargs; 66 substdio ssup; 67 char upbuf[128]; 68 69 70 void _noreturn_ doanddie(char *user, 71 unsigned int userlen, /* including 0 byte */ 72 char *pass) 73 { 74 int child; 75 int wstat; 76 int pi[2]; 77 78 close(3); 79 if (pipe(pi) == -1) die_pipe(); 80 if (pi[0] != 3) die_pipe(); 81 switch(child = fork()) { 82 case -1: 83 die_fork(); 84 case 0: 85 close(pi[1]); 86 sig_pipedefault(); 87 execvp(*childargs,childargs); 88 _exit(1); 89 } 90 close(pi[0]); 91 substdio_fdbuf(&ssup,write,pi[1],upbuf,sizeof(upbuf)); 92 if (substdio_put(&ssup,user,userlen) == -1) die_write(); 93 if (substdio_put(&ssup,pass,str_len(pass) + 1) == -1) die_write(); 94 if (substdio_puts(&ssup,"<") == -1) die_write(); 95 if (substdio_puts(&ssup,unique) == -1) die_write(); 96 if (substdio_puts(&ssup,hostname) == -1) die_write(); 97 if (substdio_put(&ssup,">",2) == -1) die_write(); 98 if (substdio_flush(&ssup) == -1) die_write(); 99 close(pi[1]); 100 byte_zero(pass,str_len(pass)); 101 byte_zero(upbuf,sizeof(upbuf)); 102 if (wait_pid(&wstat,child) == -1) die(); 103 if (wait_crashed(wstat)) die_childcrashed(); 104 if (wait_exitcode(wstat)) die_badauth(); 105 die(); 106 } 107 void pop3_greet() 108 { 109 char *s; 110 s = unique; 111 s += fmt_uint(s,getpid()); 112 *s++ = '.'; 113 s += fmt_ulong(s,(unsigned long) now()); 114 *s++ = '@'; 115 *s++ = 0; 116 puts("+OK <"); 117 puts(unique); 118 puts(hostname); 119 puts(">\r\n"); 120 flush(); 121 } 122 void pop3_user(arg) char *arg; 123 { 124 if (!*arg) { err_syntax(); return; } 125 okay(0); 126 seenuser = 1; 127 if (!stralloc_copys(&username,arg)) die_nomem(); 128 if (!stralloc_0(&username)) die_nomem(); 129 } 130 void pop3_pass(arg) char *arg; 131 { 132 if (!seenuser) { err_wantuser(); return; } 133 if (!*arg) { err_syntax(); return; } 134 doanddie(username.s,username.len,arg); 135 } 136 void pop3_apop(arg) char *arg; 137 { 138 char *space; 139 space = arg + str_chr(arg,' '); 140 if (!*space) { err_syntax(); return; } 141 *space++ = 0; 142 doanddie(arg,space - arg,space); 143 } 144 145 struct commands pop3commands[] = { 146 { "user", pop3_user, 0 } 147 , { "pass", pop3_pass, 0 } 148 , { "apop", pop3_apop, 0 } 149 , { "quit", pop3_quit, 0 } 150 , { "noop", okay, 0 } 151 , { 0, err_authoriz, 0 } 152 } ; 153 154 int main(int argc, char **argv) 155 { 156 sig_alarmcatch(die); 157 sig_pipeignore(); 158 159 hostname = argv[1]; 160 if (!hostname) die_usage(); 161 childargs = argv + 2; 162 if (!*childargs) die_usage(); 163 164 pop3_greet(); 165 commands(&ssin,pop3commands); 166 die(); 167 }