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 }