Mercurial > notdcc
comparison dcclib/parse_whitefile.c @ 0:c7f6b056b673
First import of vendor version
author | Peter Gervai <grin@grin.hu> |
---|---|
date | Tue, 10 Mar 2009 13:49:58 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:c7f6b056b673 |
---|---|
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 } |