chiark / gitweb /
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 }