Import fastforward 0.51
[fastforward] / newaliases.c
1 #include "substdio.h"
2 #include "strerr.h"
3 #include "stralloc.h"
4 #include "getln.h"
5 #include "open.h"
6 #include "readwrite.h"
7 #include "token822.h"
8 #include "control.h"
9 #include "auto_qmail.h"
10 #include "case.h"
11 #include "cdbmss.h"
12
13 #define FATAL "newaliases: fatal: "
14
15 void nomem()
16 {
17 strerr_die2x(111,FATAL,"out of memory");
18 }
19 void nulbyte()
20 {
21 strerr_die2x(100,FATAL,"NUL bytes are not permitted");
22 }
23 void longaddress()
24 {
25 strerr_die2x(100,FATAL,"addresses over 800 bytes are not permitted");
26 }
27 void writeerr()
28 {
29 strerr_die2sys(111,FATAL,"unable to write to /etc/aliases.tmp: ");
30 }
31 void readerr()
32 {
33 strerr_die2sys(111,FATAL,"unable to read /etc/aliases: ");
34 }
35 void die_control()
36 {
37 strerr_die2sys(111,FATAL,"unable to read controls: ");
38 }
39
40 stralloc me = {0};
41 stralloc defaulthost = {0};
42 stralloc defaultdomain = {0};
43 stralloc plusdomain = {0};
44
45 void readcontrols()
46 {
47 int r;
48 int fddir;
49
50 fddir = open_read(".");
51 if (fddir == -1)
52 strerr_die2sys(111,FATAL,"unable to open current directory: ");
53
54 if (chdir(auto_qmail) == -1)
55 strerr_die4sys(111,FATAL,"unable to chdir to ",auto_qmail,": ");
56
57 r = control_readline(&me,"control/me");
58 if (r == -1) die_control();
59 if (!r) if (!stralloc_copys(&me,"me")) nomem();
60
61 r = control_readline(&defaultdomain,"control/defaultdomain");
62 if (r == -1) die_control();
63 if (!r) if (!stralloc_copy(&defaultdomain,&me)) nomem();
64
65 r = control_readline(&defaulthost,"control/defaulthost");
66 if (r == -1) die_control();
67 if (!r) if (!stralloc_copy(&defaulthost,&me)) nomem();
68
69 r = control_readline(&plusdomain,"control/plusdomain");
70 if (r == -1) die_control();
71 if (!r) if (!stralloc_copy(&plusdomain,&me)) nomem();
72
73 if (fchdir(fddir) == -1)
74 strerr_die2sys(111,FATAL,"unable to set current directory: ");
75 }
76
77 stralloc target = {0};
78 stralloc fulltarget = {0};
79 stralloc instr = {0};
80
81 stralloc cbuf = {0};
82 token822_alloc toks = {0};
83 token822_alloc tokaddr = {0};
84 stralloc address = {0};
85
86 void gotincl()
87 {
88 token822_reverse(&tokaddr);
89 if (token822_unquote(&address,&tokaddr) != 1) nomem();
90 tokaddr.len = 0;
91
92 if (!address.len)
93 strerr_die2x(111,FATAL,"empty :include: filenames not permitted");
94 if (byte_chr(address.s,address.len,'\0') < address.len)
95 strerr_die2x(111,FATAL,"NUL not permitted in :include: filenames");
96
97 if ((address.s[0] != '.') && (address.s[0] != '/'))
98 if (!stralloc_cats(&instr,"./")) nomem();
99 if (!stralloc_cat(&instr,&address)) nomem();
100 if (!stralloc_cats(&instr,".bin")) nomem();
101 if (!stralloc_0(&instr)) nomem();
102 }
103
104 void gotaddr()
105 {
106 int i;
107 int j;
108 int flaghasat;
109
110 token822_reverse(&tokaddr);
111 if (token822_unquote(&address,&tokaddr) != 1) nomem();
112
113 if (!address.len)
114 strerr_die2x(111,FATAL,"empty recipient addresses not permitted");
115
116 flaghasat = 0;
117 for (i = 0;i < tokaddr.len;++i)
118 if (tokaddr.t[i].type == TOKEN822_AT)
119 flaghasat = 1;
120
121 tokaddr.len = 0;
122
123 if (!address.len) return;
124
125 if (!flaghasat)
126 if (address.s[0] == '/') {
127 if (!stralloc_0(&address)) nomem();
128 strerr_die4x(111,FATAL,"file delivery ",address.s," not supported");
129 }
130 if (!flaghasat)
131 if (address.s[0] == '|') {
132 if (byte_chr(address.s,address.len,'\0') < address.len)
133 strerr_die2x(111,FATAL,"NUL not permitted in program names");
134 if (!stralloc_cats(&instr,"!")) nomem();
135 if (!stralloc_catb(&instr,address.s + 1,address.len - 1)) nomem();
136 if (!stralloc_0(&instr)) nomem();
137 return;
138 }
139
140
141 if (target.len) {
142 if (!stralloc_cats(&instr,"&")) nomem();
143 if (!stralloc_cat(&instr,&fulltarget)) nomem();
144 if (!stralloc_0(&instr)) nomem();
145 }
146
147 if (!flaghasat)
148 if (!stralloc_cats(&address,"@")) nomem();
149
150 if (!stralloc_copy(&target,&address)) nomem();
151 if (!stralloc_copy(&fulltarget,&address)) nomem();
152
153 if (fulltarget.s[fulltarget.len - 1] == '@')
154 if (!stralloc_cat(&fulltarget,&defaulthost)) nomem();
155 if (fulltarget.s[fulltarget.len - 1] == '+') {
156 fulltarget.s[fulltarget.len - 1] = '.';
157 if (!stralloc_cat(&fulltarget,&plusdomain)) nomem();
158 }
159
160 j = 0;
161 for (i = 0;i < fulltarget.len;++i) if (fulltarget.s[i] == '@') j = i;
162 for (i = j;i < fulltarget.len;++i) if (fulltarget.s[i] == '.') break;
163 if (i == fulltarget.len) {
164 if (!stralloc_cats(&fulltarget,".")) nomem();
165 if (!stralloc_cat(&fulltarget,&defaultdomain)) nomem();
166 }
167
168 if (fulltarget.len > 800) longaddress();
169 if (byte_chr(fulltarget.s,fulltarget.len,'\0') < fulltarget.len)
170 strerr_die2x(111,FATAL,"NUL not permitted in recipient addresses");
171 }
172
173 stralloc line = {0};
174 stralloc newline = {0};
175 int match;
176
177 void parseerr()
178 {
179 if (!stralloc_0(&line)) nomem();
180 strerr_die3x(111,FATAL,"unable to parse this line: ",line.s);
181 }
182
183 void parseline()
184 {
185 int wordok;
186 struct token822 *t;
187 struct token822 *beginning;
188
189 switch(token822_parse(&toks,&line,&cbuf)) {
190 case -1: nomem();
191 case 0: parseerr();
192 }
193
194 beginning = toks.t;
195 t = toks.t + toks.len;
196 wordok = 1;
197
198 if (!token822_readyplus(&tokaddr,1)) nomem();
199 tokaddr.len = 0;
200
201 while (t > beginning)
202 switch((--t)->type) {
203 case TOKEN822_SEMI:
204 break; /*XXX*/
205 case TOKEN822_COLON:
206 if (t >= beginning + 2)
207 if (t[-2].type == TOKEN822_COLON)
208 if (t[-1].type == TOKEN822_ATOM)
209 if (t[-1].slen == 7)
210 if (!byte_diff(t[-1].s,7,"include")) {
211 gotincl();
212 t -= 2;
213 }
214 break; /*XXX*/
215 case TOKEN822_RIGHT:
216 if (tokaddr.len) gotaddr();
217 while ((t > beginning) && (t[-1].type != TOKEN822_LEFT))
218 if (!token822_append(&tokaddr,--t)) nomem();
219 gotaddr();
220 if (t <= beginning) parseerr();
221 --t;
222 while ((t > beginning) && ((t[-1].type == TOKEN822_COMMENT) || (t[-1].type == TOKEN822_ATOM) || (t[-1].type == TOKEN822_QUOTE) || (t[-1].type == TOKEN822_AT) || (t[-1].type == TOKEN822_DOT)))
223 --t;
224 wordok = 0;
225 continue;
226 case TOKEN822_ATOM: case TOKEN822_QUOTE: case TOKEN822_LITERAL:
227 if (!wordok) if (tokaddr.len) gotaddr();
228 wordok = 0;
229 if (!token822_append(&tokaddr,t)) nomem();
230 continue;
231 case TOKEN822_COMMENT:
232 /* comment is lexically a space; shouldn't affect wordok */
233 break;
234 case TOKEN822_COMMA:
235 if (tokaddr.len) gotaddr();
236 wordok = 1;
237 break;
238 default:
239 wordok = 1;
240 if (!token822_append(&tokaddr,t)) nomem();
241 continue;
242 }
243 if (tokaddr.len) gotaddr();
244 }
245
246 char inbuf[1024];
247 substdio ssin;
248 struct cdbmss cdbmss;
249 stralloc key = {0};
250
251 void doit()
252 {
253 if (!instr.len) {
254 if (target.len) parseerr();
255 return;
256 }
257
258 if (!target.len) parseerr();
259
260 if (stralloc_starts(&target,"owner-")) {
261 if (!stralloc_copys(&key,"?")) nomem();
262 if (!stralloc_catb(&key,target.s + 6,target.len - 6)) nomem();
263 case_lowerb(key.s,key.len);
264 if (cdbmss_add(&cdbmss,key.s,key.len,fulltarget.s,fulltarget.len) == -1) writeerr();
265 }
266
267 if (!stralloc_copys(&key,":")) nomem();
268 if (!stralloc_cat(&key,&target)) nomem();
269 case_lowerb(key.s,key.len);
270 if (cdbmss_add(&cdbmss,key.s,key.len,instr.s,instr.len) == -1) writeerr();
271 }
272
273 void main()
274 {
275 int fd;
276
277 umask(033);
278 readcontrols();
279
280 fd = open_read("/etc/aliases");
281 if (fd == -1) readerr();
282 substdio_fdbuf(&ssin,read,fd,inbuf,sizeof inbuf);
283
284 fd = open_trunc("/etc/aliases.tmp");
285 if (fd == -1) strerr_die2sys(111,FATAL,"unable to create /etc/aliases.tmp: ");
286 if (cdbmss_start(&cdbmss,fd) == -1) writeerr();
287
288 if (!stralloc_copys(&line,"")) nomem();
289
290 for (;;) {
291 if (getln(&ssin,&newline,&match,'\n') != 0) readerr();
292
293 if (match && (newline.s[0] == '\n')) continue;
294
295 if (match && ((newline.s[0] == ' ') || (newline.s[0] == '\t'))) {
296 if (!stralloc_cat(&line,&newline)) nomem();
297 continue;
298 }
299
300 if (line.len)
301 if (line.s[0] != '#') {
302 if (!stralloc_copys(&target,"")) nomem();
303 if (!stralloc_copys(&fulltarget,"")) nomem();
304 if (!stralloc_copys(&instr,"")) nomem();
305 parseline();
306 doit();
307 }
308
309 if (!match) break;
310 if (!stralloc_copy(&line,&newline)) nomem();
311 }
312
313 if (cdbmss_finish(&cdbmss) == -1) writeerr();
314 if (fsync(fd) == -1) writeerr();
315 if (close(fd) == -1) writeerr(); /* NFS stupidity */
316
317 if (rename("/etc/aliases.tmp","/etc/aliases.cdb") == -1)
318 strerr_die2sys(111,FATAL,"unable to move /etc/aliases.tmp to /etc/aliases.cdb: ");
319
320 _exit(0);
321 }