Commit | Line | Data |
---|---|---|
8d5530c4 MW |
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 | } |