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