0
|
1 /* Distributed Checksum Clearinghouse |
|
2 * |
|
3 * Copyright (c) 2008 by Rhyolite Software, LLC |
|
4 * |
|
5 * This agreement is not applicable to any entity which sells anti-spam |
|
6 * solutions to others or provides an anti-spam solution as part of a |
|
7 * security solution sold to other entities, or to a private network |
|
8 * which employs the DCC or uses data provided by operation of the DCC |
|
9 * but does not provide corresponding data to other users. |
|
10 * |
|
11 * Permission to use, copy, modify, and distribute this software without |
|
12 * changes for any purpose with or without fee is hereby granted, provided |
|
13 * that the above copyright notice and this permission notice appear in all |
|
14 * copies and any distributed versions or copies are either unchanged |
|
15 * or not called anything similar to "DCC" or "Distributed Checksum |
|
16 * Clearinghouse". |
|
17 * |
|
18 * Parties not eligible to receive a license under this agreement can |
|
19 * obtain a commercial license to use DCC by contacting Rhyolite Software |
|
20 * at sales@rhyolite.com. |
|
21 * |
|
22 * A commercial license would be for Distributed Checksum and Reputation |
|
23 * Clearinghouse software. That software includes additional features. This |
|
24 * free license for Distributed ChecksumClearinghouse Software does not in any |
|
25 * way grant permision to use Distributed Checksum and Reputation Clearinghouse |
|
26 * software |
|
27 * |
|
28 * THE SOFTWARE IS PROVIDED "AS IS" AND RHYOLITE SOFTWARE, LLC DISCLAIMS ALL |
|
29 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES |
|
30 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RHYOLITE SOFTWARE, LLC |
|
31 * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES |
|
32 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, |
|
33 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, |
|
34 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS |
|
35 * SOFTWARE. |
|
36 * |
|
37 * Rhyolite Software DCC 1.3.103-1.71 $Revision$ |
|
38 */ |
|
39 |
|
40 #include "dcc_ck.h" |
|
41 #include "dcc_xhdr.h" |
|
42 |
|
43 |
|
44 const char * |
|
45 wf_fnm(const DCC_WF *wf, int fno) |
|
46 { |
|
47 if (!fno) { |
|
48 return wf->ascii_nm; |
|
49 } else { |
|
50 return wf->wtbl->hdr.white_incs[fno-1].nm; |
|
51 } |
|
52 } |
|
53 |
|
54 |
|
55 |
|
56 const char * |
|
57 wf_fnm_lno(DCC_FNM_LNO_BUF *buf, const DCC_WF *wf) |
|
58 { |
|
59 int fno; |
|
60 |
|
61 if (!wf) |
|
62 return ""; |
|
63 |
|
64 fno = wf->fno; |
|
65 if (!fno) |
|
66 return fnm_lno(buf, wf->ascii_nm, wf->lno); |
|
67 |
|
68 snprintf(buf->b, sizeof(buf->b), |
|
69 DCC_FNM_LNO_PAT" included from %s", |
|
70 wf->lno, path2fnm(wf->wtbl->hdr.white_incs[fno-1].nm), |
|
71 wf->ascii_nm); |
|
72 return buf->b; |
|
73 } |
|
74 |
|
75 |
|
76 |
|
77 DCC_TGTS |
|
78 dcc_str2thold(DCC_CK_TYPES type, const char *str) |
|
79 { |
|
80 u_long l; |
|
81 char *p; |
|
82 |
|
83 l = strtoul(str, &p, 10); |
|
84 if (*p != '\0') { |
|
85 if (*p == '%') { |
|
86 if (*++p != '\0' || type != DCC_CK_REP_BULK) |
|
87 return DCC_TGTS_INVALID; |
|
88 } else if (!strcasecmp(str, DCC_XHDR_TOO_MANY)) { |
|
89 l = DCC_TGTS_TOO_MANY; |
|
90 } else if (!strcasecmp(str, DCC_XHDR_THOLD_NEVER)) { |
|
91 l = DCC_THOLD_NEVER; |
|
92 } else { |
|
93 return DCC_TGTS_INVALID; |
|
94 } |
|
95 } |
|
96 |
|
97 if (l <= DCC_TGTS_TOO_MANY) { |
|
98 /* You cannot have a reputation worse than 100%. |
|
99 * Use "never" to turn off reputation rejections or logging */ |
|
100 if (type == DCC_CK_REP_BULK && l > 100) |
|
101 return DCC_TGTS_INVALID; |
|
102 /* the reputation threshold for "bulk" must be finite */ |
|
103 if (type == DCC_CK_REP_TOTAL && l >= DCC_TGTS_TOO_MANY) |
|
104 return DCC_TGTS_INVALID; |
|
105 } |
|
106 |
|
107 return l; |
|
108 } |
|
109 |
|
110 |
|
111 |
|
112 /* look for a word followed by whitespace */ |
|
113 static const char * |
|
114 ck_word_white(const char *p, |
|
115 const char *word, |
|
116 int word_len) |
|
117 { |
|
118 int sps; |
|
119 |
|
120 if (strncasecmp(p, word, word_len)) |
|
121 return 0; |
|
122 |
|
123 p += word_len; |
|
124 sps = strspn(p, DCC_WHITESPACE); |
|
125 if (sps == 0) |
|
126 return 0; |
|
127 |
|
128 return p+sps; |
|
129 } |
|
130 |
|
131 |
|
132 |
|
133 /* parse DCC thresholds */ |
|
134 static u_char |
|
135 whitefile_option_thold(DCC_EMSG emsg, |
|
136 DCC_WF *wf, |
|
137 const char *opt, |
|
138 DCC_FNM_LNO_BUF *fnm_buf, |
|
139 DCC_FNM_LNO_BUF *thold_fnm_buf) |
|
140 { |
|
141 const char *thold_type, *thold; |
|
142 DCC_TGTS thold_tgts; |
|
143 DCC_CK_TYPES type, t2; |
|
144 u_char result; |
|
145 |
|
146 thold_type = ck_word_white(opt, "threshold", LITZ("threshold")); |
|
147 if (!thold_type) { |
|
148 /* it is not a threshold setting */ |
|
149 dcc_pemsg(EX_DATAERR, emsg, |
|
150 "unrecognized \"option %s\"%s", |
|
151 opt, wf_fnm_lno(fnm_buf, wf)); |
|
152 return 0; |
|
153 } |
|
154 |
|
155 thold = strchr(thold_type, ','); |
|
156 if (!thold_type) { |
|
157 dcc_pemsg(EX_DATAERR, emsg, |
|
158 "no comma in \"option %s\"%s", |
|
159 opt, wf_fnm_lno(fnm_buf, wf)); |
|
160 return 0; |
|
161 } |
|
162 |
|
163 type = dcc_str2type_thold(thold_type, thold - thold_type); |
|
164 if (type == DCC_CK_INVALID) { |
|
165 dcc_pemsg(EX_DATAERR, emsg, |
|
166 "unknown checksum type in \"option %s\"%s", |
|
167 opt, wf_fnm_lno(fnm_buf, wf)); |
|
168 return 0; |
|
169 } |
|
170 thold_tgts = dcc_str2thold(type, ++thold); |
|
171 if (thold_tgts == DCC_TGTS_INVALID) { |
|
172 dcc_pemsg(EX_DATAERR, emsg, |
|
173 "unrecognized threshold in \"option %s\"%s", |
|
174 opt, wf_fnm_lno(fnm_buf, wf)); |
|
175 return 0; |
|
176 } |
|
177 |
|
178 |
|
179 wf_fnm_lno(thold_fnm_buf, wf); |
|
180 result = 1; |
|
181 for (t2 = DCC_CK_TYPE_FIRST; t2 <= DCC_CK_TYPE_LAST; ++t2) { |
|
182 if (!(t2 == type |
|
183 || (type == SET_ALL_THOLDS && IS_ALL_CKSUM(t2)) |
|
184 || (type == SET_CMN_THOLDS && IS_CMN_CKSUM(t2)))) |
|
185 continue; |
|
186 if (wf->wtbl->hdr.tholds_rej[t2] != DCC_THOLD_UNSET |
|
187 && wf->wtbl->hdr.tholds_rej[t2] != thold_tgts) { |
|
188 if (result) |
|
189 dcc_pemsg(EX_DATAERR, emsg, |
|
190 "conflicting threshold setting%s", |
|
191 thold_fnm_buf->b); |
|
192 result = 0; |
|
193 } else { |
|
194 wf->wtbl->hdr.tholds_rej[t2] = thold_tgts; |
|
195 } |
|
196 } |
|
197 |
|
198 return result; |
|
199 } |
|
200 |
|
201 |
|
202 |
|
203 /* honor controls in client whitelists of the forms: |
|
204 * option log-{all,normal} |
|
205 * option log-subdirectory-{day,hour,minute} |
|
206 * option greylist-{on,off,log-on,log-off} |
|
207 * option DCC-{on,off} |
|
208 * option DCC-rep-{on,off} |
|
209 * option dnsbl {1,2,3}-{on,off} |
|
210 * option dnsbl-{on,off} obsolete |
|
211 * option MTA-{first,last} |
|
212 * option forced-discard-ok |
|
213 * option no-forced-discard |
|
214 * option forced-discard-nok obsolete |
|
215 * option threshold CKSUM,THOLD |
|
216 * option spam-trap-accept |
|
217 * option spam-trap-reject |
|
218 * change the sample whiteclnt file when this changes |
|
219 */ |
|
220 static u_char |
|
221 parse_option(DCC_EMSG emsg, |
|
222 DCC_WF *wf, |
|
223 const char *opt, |
|
224 DCC_FNM_LNO_BUF *fnm_buf, |
|
225 DCC_FNM_LNO_BUF *thold_fnm_buf) |
|
226 { |
|
227 static const struct { |
|
228 const char *str; |
|
229 int len; |
|
230 DCC_WHITE_FGS on; /* turn on this bit */ |
|
231 DCC_WHITE_FGS conflicts; /* conflict with these bits */ |
|
232 } *tp, *tp1, tbl[] = { |
|
233 # define DE(s,on,conflicts) {s, LITZ(s), on, conflicts}, |
|
234 DE("log-all", |
|
235 DCC_WHITE_FG_LOG_ALL, |
|
236 DCC_WHITE_FG_LOG_NORMAL) |
|
237 DE("log-normal", |
|
238 DCC_WHITE_FG_LOG_NORMAL, |
|
239 DCC_WHITE_FG_LOG_ALL) |
|
240 |
|
241 DE("log-subdirectory-day", |
|
242 DCC_WHITE_FG_LOG_D, |
|
243 DCC_WHITE_FG_LOG_H | DCC_WHITE_FG_LOG_M) |
|
244 DE("log-subdirectory-hour", |
|
245 DCC_WHITE_FG_LOG_H, |
|
246 DCC_WHITE_FG_LOG_D | DCC_WHITE_FG_LOG_M) |
|
247 DE("log-subdirectory-minute", |
|
248 DCC_WHITE_FG_LOG_M, |
|
249 DCC_WHITE_FG_LOG_D | DCC_WHITE_FG_LOG_H) |
|
250 |
|
251 DE("greylist-on", |
|
252 DCC_WHITE_FG_GREY_ON, |
|
253 DCC_WHITE_FG_GREY_OFF) |
|
254 DE("greylist-off", |
|
255 DCC_WHITE_FG_GREY_OFF, |
|
256 DCC_WHITE_FG_GREY_ON) |
|
257 |
|
258 DE("greylist-log-on", |
|
259 DCC_WHITE_FG_GREY_LOG_ON, |
|
260 DCC_WHITE_FG_GREY_LOG_OFF) |
|
261 DE("greylist-log-off", |
|
262 DCC_WHITE_FG_GREY_LOG_OFF, |
|
263 DCC_WHITE_FG_GREY_LOG_ON) |
|
264 |
|
265 DE("DCC-on", |
|
266 DCC_WHITE_FG_DCC_ON, |
|
267 DCC_WHITE_FG_DCC_OFF) |
|
268 DE("DCC-off", |
|
269 DCC_WHITE_FG_DCC_OFF, |
|
270 DCC_WHITE_FG_DCC_ON) |
|
271 |
|
272 DE("forced-discard-ok", |
|
273 DCC_WHITE_FG_DISCARD_OK, |
|
274 DCC_WHITE_FG_NO_DISCARD) |
|
275 DE("no_forced-discard", |
|
276 DCC_WHITE_FG_NO_DISCARD, |
|
277 DCC_WHITE_FG_DISCARD_OK) |
|
278 DE("forced-discard-nok", /* obsolete */ |
|
279 DCC_WHITE_FG_NO_DISCARD, |
|
280 DCC_WHITE_FG_DISCARD_OK) |
|
281 |
|
282 DE("MTA-first", |
|
283 DCC_WHITE_FG_MTA_FIRST, |
|
284 DCC_WHITE_FG_MTA_LAST) |
|
285 DE("MTA-last", |
|
286 DCC_WHITE_FG_MTA_LAST, |
|
287 DCC_WHITE_FG_MTA_FIRST) |
|
288 |
|
289 DE("DCC-rep-on", |
|
290 DCC_WHITE_FG_REP_ON, |
|
291 DCC_WHITE_FG_REP_OFF) |
|
292 DE("DCC-rep-off", |
|
293 DCC_WHITE_FG_REP_OFF, |
|
294 DCC_WHITE_FG_REP_ON) |
|
295 DE("DCC-reps-on", /* obsolete */ |
|
296 DCC_WHITE_FG_REP_ON, |
|
297 DCC_WHITE_FG_REP_OFF) |
|
298 DE("DCC-reps-off", /* obsolete */ |
|
299 DCC_WHITE_FG_REP_OFF, |
|
300 DCC_WHITE_FG_REP_ON) |
|
301 |
|
302 DE("DNSBL-on", /* obsolete */ |
|
303 DCC_WHITE_FG_DNSBL_ON(0), |
|
304 DCC_WHITE_FG_DNSBL_OFF(0)) |
|
305 DE("DNSBL1-on", |
|
306 DCC_WHITE_FG_DNSBL_ON(0), |
|
307 DCC_WHITE_FG_DNSBL_OFF(0)) |
|
308 DE("DNSBL-off", /* obsolete */ |
|
309 DCC_WHITE_FG_DNSBL_OFF(0), |
|
310 DCC_WHITE_FG_DNSBL_ON(0)) |
|
311 DE("DNSBL1-off", |
|
312 DCC_WHITE_FG_DNSBL_OFF(0), |
|
313 DCC_WHITE_FG_DNSBL_ON(0)) |
|
314 |
|
315 DE("DNSBL2-on", |
|
316 DCC_WHITE_FG_DNSBL_ON(1), |
|
317 DCC_WHITE_FG_DNSBL_OFF(1)) |
|
318 DE("DNSBL2-off", |
|
319 DCC_WHITE_FG_DNSBL_OFF(1), |
|
320 DCC_WHITE_FG_DNSBL_ON(1)) |
|
321 |
|
322 DE("DNSBL3-on", |
|
323 DCC_WHITE_FG_DNSBL_ON(2), |
|
324 DCC_WHITE_FG_DNSBL_OFF(2)) |
|
325 DE("DNSBL3-off", |
|
326 DCC_WHITE_FG_DNSBL_OFF(2), |
|
327 DCC_WHITE_FG_DNSBL_ON(2)) |
|
328 |
|
329 DE(DCC_XHDR_TRAP_ACC, |
|
330 DCC_WHITE_FG_TRAP_ACC, |
|
331 DCC_WHITE_FG_TRAP_REJ) |
|
332 |
|
333 DE(DCC_XHDR_TRAP_REJ, |
|
334 DCC_WHITE_FG_TRAP_REJ, |
|
335 DCC_WHITE_FG_TRAP_ACC) |
|
336 |
|
337 # undef DE |
|
338 }; |
|
339 |
|
340 int i; |
|
341 DCC_WHITE_FGS conflicts; |
|
342 |
|
343 i = strlen(opt); |
|
344 for (tp = tbl; ; ++tp) { |
|
345 /* try a threshold if not a boolean option */ |
|
346 if (tp > LAST(tbl)) |
|
347 return whitefile_option_thold(emsg, wf, opt, |
|
348 fnm_buf, thold_fnm_buf); |
|
349 if (i == tp->len && !strcasecmp(tp->str, opt)) |
|
350 break; |
|
351 } |
|
352 |
|
353 conflicts = (wf->wtbl_flags & tp->conflicts); |
|
354 if (conflicts != 0) { |
|
355 for (tp1 = tbl; tp1 <= LAST(tbl); ++tp1) { |
|
356 if ((tp1->on & conflicts) != 0) { |
|
357 dcc_pemsg(EX_DATAERR, emsg, |
|
358 "\"option %s\"%s conflicts with " |
|
359 "\"option %s\"", |
|
360 opt, wf_fnm_lno(fnm_buf, wf), |
|
361 tp1->str); |
|
362 return 0; |
|
363 } |
|
364 } |
|
365 dcc_pemsg(EX_DATAERR, emsg, |
|
366 "conflicting \"option %s\"%s", |
|
367 opt, wf_fnm_lno(fnm_buf, wf)); |
|
368 return 0; |
|
369 } |
|
370 |
|
371 wf->wtbl->hdr.flags = (wf->wtbl_flags |= tp->on); |
|
372 return 1; |
|
373 } |
|
374 |
|
375 |
|
376 |
|
377 int /* -1=fatal 0=problems 1=ok */ |
|
378 dcc_parse_whitefile(DCC_EMSG emsg, |
|
379 DCC_WF *wf, |
|
380 int main_fd, /* main file */ |
|
381 DCC_PARSED_CK_FNC add_fnc, |
|
382 DCC_PARSED_CK_CIDR_FNC cidr_fnc) |
|
383 { |
|
384 struct f { |
|
385 int fd; |
|
386 char *start; |
|
387 char *eob; |
|
388 DCC_PATH path; |
|
389 char c[1024]; |
|
390 } main_buf, inc_buf, *cur_buf; |
|
391 char tgts_buf[16]; |
|
392 char *bol, *eol, *type_nm, *ck; |
|
393 const char *nmp, *opt; |
|
394 DCC_FNM_LNO_BUF fnm_buf; |
|
395 DCC_FNM_LNO_BUF white_fnm_buf; |
|
396 DCC_FNM_LNO_BUF thold_fnm_buf; |
|
397 DCC_TGTS new_tgts; |
|
398 DCC_CK_TYPES type; |
|
399 struct stat sb; |
|
400 int white_fno; |
|
401 int main_lno; |
|
402 u_char result, hex; |
|
403 int i, j; |
|
404 |
|
405 result = 1; |
|
406 white_fnm_buf.b[0] = '\0'; |
|
407 thold_fnm_buf.b[0] = '\0'; |
|
408 main_buf.fd = main_fd; |
|
409 main_buf.eob = main_buf.c; |
|
410 main_buf.start = main_buf.c; |
|
411 cur_buf = &main_buf; |
|
412 wf->fno = white_fno = 0; |
|
413 wf->lno = main_lno = 0; |
|
414 new_tgts = DCC_TGTS_INVALID; |
|
415 for (;;) { |
|
416 next_line:; |
|
417 /* Each substantive line has one of the forms: |
|
418 * tgts [hex] type string |
|
419 * [hex] type string |
|
420 * include pathname |
|
421 * option ... |
|
422 * A missing number of targets means the line has the |
|
423 * same number of targets as the previous line */ |
|
424 |
|
425 ++wf->lno; |
|
426 for (;;) { |
|
427 /* continue getting more text until we have an |
|
428 * end-of-line in the buffer */ |
|
429 if (cur_buf->start < cur_buf->eob) { |
|
430 eol = memchr(cur_buf->start, '\n', |
|
431 cur_buf->eob - cur_buf->start); |
|
432 if (eol) |
|
433 break; |
|
434 } |
|
435 |
|
436 if (cur_buf->start != cur_buf->c) { |
|
437 i = cur_buf->eob - cur_buf->start; |
|
438 if (i > 0) |
|
439 memmove(cur_buf->c, cur_buf->start, i); |
|
440 cur_buf->start = cur_buf->c; |
|
441 cur_buf->eob = &cur_buf->c[i]; |
|
442 } |
|
443 j = &cur_buf->c[sizeof(cur_buf->c)] - cur_buf->eob; |
|
444 if (j <= 0) { |
|
445 dcc_pemsg(EX_DATAERR, emsg, |
|
446 "line too long%s", |
|
447 wf_fnm_lno(&fnm_buf, wf)); |
|
448 result = 0; |
|
449 } else { |
|
450 i = read(cur_buf->fd, cur_buf->eob, j); |
|
451 if (i > 0) { |
|
452 cur_buf->eob += i; |
|
453 continue; |
|
454 } |
|
455 |
|
456 if (i < 0) { |
|
457 dcc_pemsg(EX_IOERR, emsg, |
|
458 "read(%s, %d): %s", |
|
459 wf_fnm(wf, wf->fno), j, |
|
460 ERROR_STR()); |
|
461 result = 0; |
|
462 } |
|
463 /* act as if the last line in the file ends |
|
464 * with '\n' even if it does not */ |
|
465 if (cur_buf->start < cur_buf->eob) { |
|
466 eol = cur_buf->eob++; |
|
467 break; |
|
468 } |
|
469 } |
|
470 if (cur_buf == &main_buf) |
|
471 return result; |
|
472 if (0 > close(cur_buf->fd)) { |
|
473 dcc_pemsg(EX_IOERR, emsg, "close(%s): %s", |
|
474 wf_fnm(wf, wf->fno), ERROR_STR()); |
|
475 result = 0; |
|
476 } |
|
477 /* return to the main file at end of included file */ |
|
478 cur_buf = &main_buf; |
|
479 wf->fno = 0; |
|
480 wf->lno = main_lno; |
|
481 new_tgts = DCC_TGTS_INVALID; |
|
482 continue; |
|
483 } |
|
484 bol = cur_buf->start; |
|
485 cur_buf->start = eol+1; |
|
486 |
|
487 /* trim trailing blanks */ |
|
488 do { |
|
489 *eol-- = '\0'; |
|
490 } while (eol > bol |
|
491 && (*eol == ' ' || *eol == '\t' || *eol == '\r')); |
|
492 |
|
493 /* Ignore blank lines and lines starting with '#' */ |
|
494 type_nm = bol+strspn(bol, DCC_WHITESPACE); |
|
495 if (*type_nm == '\0' || *type_nm == '#') |
|
496 goto next_line; |
|
497 |
|
498 /* parse |
|
499 * include pathname */ |
|
500 nmp = ck_word_white(type_nm, "include", LITZ("include")); |
|
501 if (nmp) { |
|
502 DCC_PATH nm; |
|
503 |
|
504 /* can't continue list of identical/missing target |
|
505 * counts into included file */ |
|
506 new_tgts = DCC_TGTS_INVALID; |
|
507 |
|
508 if (cur_buf != &main_buf) { |
|
509 dcc_pemsg(EX_DATAERR, emsg, |
|
510 "nested \"include\" not allowed%s", |
|
511 wf_fnm_lno(&fnm_buf, wf)); |
|
512 result = 0; |
|
513 goto next_line; |
|
514 } |
|
515 |
|
516 /* trim quotes if present from the file name */ |
|
517 i = strlen(nmp); |
|
518 if (i > 1 |
|
519 && ((nmp[0] == '"' && nmp[i-1] == '"') |
|
520 || (nmp[0] == '<' && |
|
521 i > 1 && nmp[i-1] == '>'))) { |
|
522 ++nmp; |
|
523 i -= 2; |
|
524 } |
|
525 |
|
526 if (i == 0) { |
|
527 dcc_pemsg(EX_DATAERR, emsg, |
|
528 "missing file name%s", |
|
529 wf_fnm_lno(&fnm_buf, wf)); |
|
530 result = 0; |
|
531 goto next_line; |
|
532 } |
|
533 if (i >= ISZ(DCC_PATH)) { |
|
534 dcc_pemsg(EX_DATAERR, emsg, |
|
535 "file name too long in" |
|
536 " \"include %.32s...\"%s", |
|
537 nmp, wf_fnm_lno(&fnm_buf, wf)); |
|
538 result = 0; |
|
539 goto next_line; |
|
540 } |
|
541 memcpy(nm, nmp, i); |
|
542 nm[i] = '\0'; |
|
543 if (white_fno >= DIM(wf->wtbl->hdr.white_incs)) { |
|
544 dcc_pemsg(EX_DATAERR, emsg, |
|
545 "too many \"include\" files%s", |
|
546 wf_fnm_lno(&fnm_buf, wf)); |
|
547 result = 0; |
|
548 goto next_line; |
|
549 } |
|
550 |
|
551 if (!fnm2rel(wf->wtbl->hdr.white_incs[white_fno].nm, |
|
552 nm, 0)) { |
|
553 dcc_pemsg(EX_DATAERR, emsg, |
|
554 "name \"%s\" too long%s", |
|
555 nm, wf_fnm_lno(&fnm_buf, wf)); |
|
556 result = 0; |
|
557 goto next_line; |
|
558 } |
|
559 |
|
560 inc_buf.fd = open(nm, O_RDONLY, 0); |
|
561 if (inc_buf.fd < 0) { |
|
562 dcc_pemsg(EX_DATAERR, emsg, |
|
563 "\"include %s\": %s%s", |
|
564 nm, ERROR_STR(), |
|
565 wf_fnm_lno(&fnm_buf, wf)); |
|
566 result = 0; |
|
567 goto next_line; |
|
568 } |
|
569 inc_buf.eob = inc_buf.c; |
|
570 inc_buf.start = inc_buf.c; |
|
571 cur_buf = &inc_buf; |
|
572 |
|
573 if (0 > fstat(inc_buf.fd, &sb)) { |
|
574 wf->wtbl->hdr.white_incs[white_fno].mtime = 0; |
|
575 } else { |
|
576 wf->wtbl->hdr.white_incs[white_fno |
|
577 ].mtime = sb.st_mtime; |
|
578 } |
|
579 |
|
580 wf->fno = ++white_fno; |
|
581 main_lno = wf->lno+1; |
|
582 wf->lno = 0; |
|
583 goto next_line; |
|
584 } |
|
585 |
|
586 /* honor "option" lines in whiteclnt files */ |
|
587 opt = ck_word_white(type_nm, "option", LITZ("option")); |
|
588 if (opt) { |
|
589 /* stop continuation lines when we hit an option */ |
|
590 new_tgts = DCC_TGTS_INVALID; |
|
591 |
|
592 if (!wf->wtbl) { |
|
593 dcc_pemsg(EX_DATAERR, emsg, "\"%s\"" |
|
594 " not legal in server whitelist%s", |
|
595 type_nm, wf_fnm_lno(&fnm_buf, wf)); |
|
596 result = 0; |
|
597 goto next_line; |
|
598 } |
|
599 |
|
600 if (!parse_option(emsg, wf, opt, &fnm_buf, |
|
601 &thold_fnm_buf)) |
|
602 result = 0; |
|
603 goto next_line; |
|
604 } |
|
605 |
|
606 |
|
607 /* Look for the number of targets in a simple line */ |
|
608 if (type_nm != bol) { |
|
609 /* If the line started with white space, the number |
|
610 * of targets is the same as the previous line. */ |
|
611 *bol = '\0'; |
|
612 } else { |
|
613 type_nm += strcspn(type_nm, DCC_WHITESPACE); |
|
614 if (*type_nm == '\0') { |
|
615 dcc_pemsg(EX_DATAERR, emsg, |
|
616 "missing type in \"%s\"%s", |
|
617 bol, wf_fnm_lno(&fnm_buf, wf)); |
|
618 result = 0; |
|
619 goto next_line; |
|
620 } |
|
621 *type_nm++ = '\0'; |
|
622 /* bol now starts with null-terminated |
|
623 * number of targets, "include", or "log" */ |
|
624 type_nm += strspn(type_nm, DCC_WHITESPACE); |
|
625 } |
|
626 |
|
627 ck = type_nm+strcspn(type_nm, DCC_WHITESPACE); |
|
628 |
|
629 if (*ck != '\0') { |
|
630 /* null terminate the type */ |
|
631 *ck++ = '\0'; |
|
632 ck += strspn(ck, DCC_WHITESPACE); |
|
633 } |
|
634 |
|
635 if (strcasecmp(type_nm, "hex")) { |
|
636 hex = 0; |
|
637 } else { |
|
638 hex = 1; |
|
639 type_nm = ck; |
|
640 ck = type_nm+strcspn(type_nm, DCC_WHITESPACE); |
|
641 if (*ck != '\0') { |
|
642 *ck++ = '\0'; |
|
643 ck += strspn(ck, DCC_WHITESPACE); |
|
644 } |
|
645 } |
|
646 |
|
647 /* parse the target count if it is present instead of blank */ |
|
648 if (*bol != '\0') |
|
649 new_tgts = dcc_str2cnt(bol); |
|
650 if (new_tgts == 0 || new_tgts == DCC_TGTS_INVALID) { |
|
651 dcc_pemsg(EX_DATAERR, emsg, |
|
652 "missing or invalid # of targets \"%s\"%s", |
|
653 bol, wf_fnm_lno(&fnm_buf, wf)); |
|
654 new_tgts = DCC_TGTS_INVALID; |
|
655 result = 0; |
|
656 goto next_line; |
|
657 } |
|
658 |
|
659 if (*ck == '\0') { |
|
660 dcc_pemsg(EX_DATAERR, emsg, "missing value%s", |
|
661 wf_fnm_lno(&fnm_buf, wf)); |
|
662 new_tgts = DCC_TGTS_INVALID; |
|
663 result = 0; |
|
664 goto next_line; |
|
665 } |
|
666 |
|
667 type = dcc_str2type_wf(type_nm, -1); |
|
668 |
|
669 if (new_tgts == DCC_TGTS_OK_MX |
|
670 || new_tgts == DCC_TGTS_OK_MXDCC |
|
671 || new_tgts == DCC_TGTS_SUBMIT_CLIENT) { |
|
672 if (type != DCC_CK_IP) { |
|
673 dcc_pemsg(EX_DATAERR, emsg, |
|
674 new_tgts == DCC_TGTS_SUBMIT_CLIENT |
|
675 ? "client must be an IP address%s" |
|
676 : "MX server must be an IP address%s", |
|
677 wf_fnm_lno(&fnm_buf, wf)); |
|
678 new_tgts = DCC_TGTS_INVALID; |
|
679 result = 0; |
|
680 goto next_line; |
|
681 } |
|
682 if (wf->wf_flags & DCC_WF_PER_USER) { |
|
683 dcc_pemsg(EX_DATAERR, emsg, |
|
684 "%s illegal in per-user whitelist%s", |
|
685 dcc_tgts2str(tgts_buf, |
|
686 sizeof(tgts_buf), |
|
687 new_tgts, 0), |
|
688 wf_fnm_lno(&fnm_buf, wf)); |
|
689 new_tgts = DCC_TGTS_INVALID; |
|
690 result = 0; |
|
691 goto next_line; |
|
692 } |
|
693 } |
|
694 |
|
695 /* Look for the type of the checksum, compute the checksum, |
|
696 * and write the checksum to the hash table file. |
|
697 * Write all of its aliases if it is a host name. */ |
|
698 if (hex) { |
|
699 i = dcc_parse_hex_ck(emsg, wf, |
|
700 type_nm, type, ck, new_tgts, |
|
701 add_fnc); |
|
702 } else { |
|
703 i = dcc_parse_ck(emsg, wf, |
|
704 type_nm, type, ck, new_tgts, |
|
705 add_fnc, cidr_fnc); |
|
706 } |
|
707 /* give up on a fatal problem adding a checksum to the file */ |
|
708 if (i < 0) |
|
709 break; |
|
710 if (i == 0) |
|
711 result = 0; |
|
712 else if (new_tgts == DCC_TGTS_OK || new_tgts == DCC_TGTS_OK2) |
|
713 wf_fnm_lno(&white_fnm_buf, wf); |
|
714 } |
|
715 |
|
716 /* fatal problem such as writing to the file */ |
|
717 if (cur_buf != &main_buf) |
|
718 close(cur_buf->fd); |
|
719 return -1; |
|
720 } |