1 /*
2 libutil -- read config file
3
4 Written by Arnt Gulbrandsen <agulbra@troll.no> and copyright 1995
5 Troll Tech AS, Postboks 6133 Etterstad, 0602 Oslo, Norway, fax +47
6 22646949.
7 Modified by Cornelius Krasel <krasel@wpxx02.toxi.uni-wuerzburg.de>
8 and Randolf Skerka <Randolf.Skerka@gmx.de>.
9 Copyright of the modifications 1997.
10 Modified by Kent Robotti <robotti@erols.com>. Copyright of the
11 modifications 1998.
12 Modified by Markus Enzenberger <enz@cip.physik.uni-muenchen.de>.
13 Copyright of the modifications 1998.
14 Modified by Cornelius Krasel <krasel@wpxx02.toxi.uni-wuerzburg.de>.
15 Copyright of the modifications 1998, 1999.
16 Modified and copyright of the modifications 2002 by Ralf Wildenhues
17 <ralf.wildenhues@gmx.de>.
18 Modified and copyright of the modifications 2001 - 2003 by Matthias Andree
19 <matthias.andree@gmx.de>.
20
21 See file COPYING for restrictions on the use of this software.
22 */
23
24 #include "leafnode.h"
25 #include "validatefqdn.h"
26 #include "ln_log.h"
27 #include "strlcpy.h"
28
29 #include <ctype.h>
30 #include <errno.h>
31 #include <sys/types.h>
32 #include <limits.h>
33 #include <netdb.h>
34 #include <netinet/in.h>
35 #ifndef __LCLINT__
36 #include <arpa/inet.h>
37 #endif
38 #include <stdlib.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <syslog.h>
42 #include <unistd.h>
43 #include <sys/stat.h>
44 #include <sys/resource.h>
45
46 #define COREFILESIZE 1024*1024*64
47 #define TOKENSIZE 4096
48
49 #include "groupselect.h"
50
51 #ifndef min
52 #define min(a,b) ((a < b) ? (a) : (b))
53 #endif
54
55 /*
56 * misc. global variables, documented in leafnode.h
57 */
58 time_t expire = 0;
59 int expiredays = 0;
60 struct expire_entry *expire_base;
61 unsigned long artlimit = 0;
62 unsigned long initiallimit = 0;
63 long crosspostlimit = 0;
64 int create_all_links = 0;
65 int delaybody = 0;
66 int db_situ = 0;
67 int debugmode = 0; /* if 1, log lots of stuff via syslog */
68 int maxage = 10;
69 int article_despite_filter = 0;
70 long maxlines = 0;
71 long minlines = 0;
72 unsigned long maxbytes = 0;
73 static int linebuffer = 0; /* if 1, make stdout and stderr explicitly
74 line buffered, GNU libc makes them fully buffered
75 if redirected to files */
76 int timeout_long = 7;
77 int timeout_short = 2;
78 int timeout_active = 90;
79 int timeout_client = 15*60; /* when newsreader is idle for this many seconds, disconnect */
80 int timeout_fetchnews = 5*60; /* wait at most this many seconds for server replies in fetchnews */
81 int clamp_maxage = 1; /* if 1, maxage will be lowered to
82 * groupexpire or expire if the
83 * applicable parameter is lower than
84 * maxage, to prevent duplicate fetches
85 * after a premature exit of
86 * fetchnews. */
87 int allowstrangers = 0;
88 char *filterfile;
89 struct server *servers = NULL;
90 int allow_8bit_headers = 0;
91 char *newsadmin;
92 unsigned long timeout_lock = 5UL;
93
94 /** parse the line in \a l, breaking it into param and value at the "="
95 * delimiter. The right-hand side can be quoted with double quotes,
96 * inside these a backslash escapes a quote that is part of the string.
97 * \return success
98 */
99 static int parse_line(
100 /*@unique@*/ char *l /** input, will be modified */,
101 /*@out@*/ char *param /** output, left-hand side */,
102 /*@out@*/ char *value /** output, right-hand side */);
103
104 /* parse a line, destructively */
105 static int
parse_line(char * l,char * param,char * value)106 parse_line(char *l, char *param, char *value)
107 {
108 char *p, *start;
109 size_t le, len;
110 enum modes { plain, quoted } mode = plain;
111
112 p = l;
113 /* skip leading spaces, read parameter */
114 SKIPLWS(p);
115 le = strcspn(p, "=#");
116 /* strip trailing space */
117 while(le && strchr(" \t", p[le-1])) le--;
118 len = min(le, TOKENSIZE - 1);
119 if (!len) return 0;
120 memcpy(param, p, len);
121 param[len] = '\0';
122 p += le;
123
124 SKIPLWS(p);
125 if (*p++ != '=')
126 return 0;
127 SKIPLWS(p);
128
129 /* strip trailing blanks from input */
130 le = strlen(p);
131 while (le--) {
132 if (p[le] == ' ' || p[le] == '\t')
133 p[le] = '\0';
134 else
135 break;
136 }
137
138 start = value;
139 /* read value */
140 for (le = 0 ; le < TOKENSIZE - 1 ; le ++) {
141 char c = *p++;
142 if (mode == plain) {
143 if (c == '#' || c == '\0') {
144 /* strip trailing blanks */
145 while(value > start && strchr(" \t", value[-1])) value--;
146 break;
147 }
148 if (c == '"') { mode = quoted; continue; }
149 *value++ = c;
150 } else if (mode == quoted) {
151 if (c == '\\') {
152 if (*p) {
153 *value++ = *p++; continue;
154 } else
155 return 0;
156 }
157 if (c == '\0') return 0;
158 if (c == '"') break;
159 *value++ = c;
160 } else {
161 abort();
162 }
163 }
164 *value = '\0';
165 return 1;
166 }
167
168 /*
169 05/25/97 - T. Sweeney - Modified to read user name and password for AUTHINFO.
170 Security questionable as password is stored in
171 plaintext in insecure file.
172 1999-07-15 - Matthias Andree
173 Set p and q defaults to 0
174 */
175
176 /* parses value into timeout_lock, returns 0 for success, -1 for error */
read_timeout_lock(const char * value,const char * source)177 static int read_timeout_lock(
178 const char *value, /* input */
179 const char *source /* where did value come from */) {
180 char *t;
181 unsigned long u;
182
183 errno = 0;
184 u = strtoul(value, &t, 10);
185 if ((u != 0 || errno == 0)
186 && t > value
187 && (!*t || isspace((unsigned char)*t)))
188 {
189 timeout_lock = u;
190 if (debugmode) {
191 if (timeout_lock) {
192 syslog(LOG_DEBUG,
193 "%s: waiting %lu second%s for lockfile",
194 source, timeout_lock, PLURAL(timeout_lock));
195 } else {
196 syslog(LOG_DEBUG,
197 "%s: waiting indefinitely for lockfile", source);
198 }
199 }
200 return 0;
201 } else {
202 ln_log(LNLOG_SERR, LNLOG_CTOP, "error: cannot parse lockfile value \"%s\" from %s", value, source);
203 return -1;
204 }
205 }
206
207 int
readconfig(int logtostderr)208 readconfig(int logtostderr)
209 {
210 struct server *p = 0, *q = 0;
211 struct rlimit corelimit;
212 struct expire_entry *ent = NULL, *prev = NULL;
213 FILE *f;
214 char *l;
215 char *param, *value;
216 char s[SIZE_s + 1];
217 unsigned long curline = 0;
218
219 artlimit = 0;
220 param = critmalloc(TOKENSIZE, "allocating space for parsing");
221 value = critmalloc(TOKENSIZE, "allocating space for parsing");
222
223 xsnprintf(s, SIZE_s, "%s/config", sysconfdir);
224 if ((f = fopen(s, "r")) == NULL) {
225 syslog(LOG_ERR, "cannot open %s", s);
226 free(param);
227 free(value);
228 return 0;
229 }
230 while ((l = getaline(f))) {
231 ++curline;
232 if (parse_line(l, param, value)) {
233 if (strcmp("username", param) == 0) {
234 if (p) {
235 if (p->username != NULL)
236 free(p->username);
237 p->username = critstrdup(value, "readconfig");
238 if (debugmode)
239 syslog(LOG_DEBUG, "config: found username for %s",
240 p->name);
241 } else
242 syslog(LOG_ERR, "config: no server for username %s", value);
243 } else if (strcmp("password", param) == 0) {
244 if (p) {
245 if (p->password != NULL)
246 free(p->password);
247 p->password = critstrdup(value, "readconfig");
248 if (debugmode)
249 syslog(LOG_DEBUG, "config: found password for %s",
250 p->name);
251 } else
252 syslog(LOG_ERR, "config: no server for password");
253 } else if (strcmp("timeout", param) == 0) {
254 if (p) {
255 p->timeout = atoi(value);
256 if (debugmode)
257 syslog(LOG_DEBUG, "config: timeout is %d second%s",
258 p->timeout, PLURAL(p->timeout));
259 } else
260 syslog(LOG_ERR, "config: no server for timeout");
261 } else if (strcmp("allowSTRANGERS", param) == 0) {
262 if (value && strlen(value)) {
263 if (atoi(value) == 42)
264 allowstrangers = 1;
265 if (debugmode)
266 syslog(LOG_DEBUG,
267 "config: allowstrangers is %s",
268 allowstrangers ? "set" : "unset");
269 }
270 } else if (strcmp("create_all_links", param) == 0) {
271 if (value && strlen(value)) {
272 create_all_links = atoi(value);
273 if (create_all_links && debugmode)
274 syslog(LOG_DEBUG,
275 "config: link articles in all groups");
276 }
277 } else if (strcmp("expire", param) == 0) {
278 int i = atoi(value);
279 if (i >= (INT_MAX / SECONDS_PER_DAY))
280 i = (INT_MAX / SECONDS_PER_DAY) - 1;
281 if (i <= 0) {
282 ln_log(LNLOG_SERR, LNLOG_CTOP, "config: expire must be positive, not %d, abort", i);
283 exit(1);
284 }
285 expiredays = i;
286 expire = time(NULL) - (time_t) (SECONDS_PER_DAY * i);
287 if (debugmode)
288 syslog(LOG_DEBUG, "config: expire is %d day%s", i, PLURAL(i));
289 } else if (strcmp("newsadmin", param) == 0) {
290 if (debugmode)
291 syslog(LOG_DEBUG, "config: newsadmin is %s", value);
292 newsadmin = critstrdup(value, "readconfig");
293 } else if (strcmp("filterfile", param) == 0) {
294 if (debugmode)
295 syslog(LOG_DEBUG, "config: filterfile is %s", value);
296 filterfile = critstrdup(value, "readconfig");
297 } else if ((strcmp("hostname", param) == 0) ||
298 (strcmp("fqdn", param) == 0)) {
299 if (debugmode)
300 syslog(LOG_DEBUG, "config: hostname is %s", value);
301 (void)xstrlcpy(fqdn, value, sizeof(fqdn));
302 } else if ((strcmp("maxcrosspost", param) == 0) ||
303 (strcmp("maxgroups", param) == 0)) {
304 /* maxgroups is for compatibility with leafnode+ */
305 crosspostlimit = strtol(value, NULL, 10);
306 if (debugmode)
307 syslog(LOG_DEBUG, "config: crosspostlimit is %ld group%s",
308 crosspostlimit, PLURAL(crosspostlimit));
309 } else if (strcmp("article_despite_filter", param) == 0) {
310 article_despite_filter = atoi(value) ? 1 : 0;
311 if (debugmode)
312 syslog(LOG_DEBUG, "config: article_despite_filter is %s",
313 article_despite_filter ? "TRUE" : "FALSE");
314 } else if (strcmp("clamp_maxage", param) == 0) {
315 clamp_maxage = atoi(value);
316 if (debugmode)
317 syslog(LOG_DEBUG, "config: clamp_maxage is %s",
318 clamp_maxage ? "TRUE" : "FALSE");
319 } else if (strcmp("maxlines", param) == 0) {
320 maxlines = strtol(value, NULL, 10);
321 if (debugmode)
322 syslog(LOG_DEBUG, "config: postings have max. %ld line%s",
323 maxlines, PLURAL(maxlines));
324 } else if (strcmp("minlines", param) == 0) {
325 minlines = strtol(value, NULL, 10);
326 if (debugmode)
327 syslog(LOG_DEBUG, "config: postings have min. %ld line%s",
328 minlines, PLURAL(minlines));
329 } else if (strcmp("maxbytes", param) == 0) {
330 maxbytes = strtoul(value, NULL, 10);
331 if (debugmode)
332 syslog(LOG_DEBUG,
333 "config: postings have max. %lu byte%s",
334 maxbytes, PLURAL(maxbytes));
335 } else if (strcmp("linebuffer", param) == 0) {
336 linebuffer = atoi(value);
337 if (debugmode)
338 syslog(LOG_DEBUG, "config: linebuffer is %d", linebuffer);
339 } else if (strcmp("allow_8bit_headers", param) == 0) {
340 allow_8bit_headers = atoi(value);
341 if (debugmode)
342 syslog(LOG_DEBUG, "config: allow_8bit_headers is %d",
343 allow_8bit_headers);
344 } else if (strcmp("debugmode", param) == 0) {
345 int d;
346 d = atoi(value);
347 debugmode = d > debugmode ? d : debugmode;
348 if (debugmode)
349 syslog(LOG_DEBUG, "config: debugmode is %d", debugmode);
350 } else if (strcmp("delaybody_in_situ", param) == 0) {
351 db_situ = atoi(value);
352 if (debugmode)
353 syslog(LOG_DEBUG, "config: delaybody_in_situ is %d (default 0)",
354 db_situ);
355 } else if (strcmp("delaybody", param) == 0) {
356 delaybody = atoi(value);
357 if (debugmode)
358 syslog(LOG_DEBUG, "config: delaybody is %d (default 0)",
359 delaybody);
360 } else if (strcmp("timeout_short", param) == 0) {
361 timeout_short = atoi(value);
362 if (debugmode)
363 syslog(LOG_DEBUG, "config: timeout_short is %d day%s",
364 timeout_short, PLURAL(timeout_short));
365 } else if (strcmp("timeout_long", param) == 0) {
366 timeout_long = atoi(value);
367 if (debugmode)
368 syslog(LOG_DEBUG, "config: timeout_long is %d day%s",
369 timeout_long, PLURAL(timeout_long));
370 } else if (strcmp("timeout_active", param) == 0) {
371 timeout_active = atoi(value);
372 if (debugmode)
373 syslog(LOG_DEBUG, "config: timeout_active is %d day%s",
374 timeout_active, PLURAL(timeout_active));
375 } else if (strcmp("timeout_client", param) == 0) {
376 timeout_client = atoi(value);
377 if (debugmode)
378 syslog(LOG_DEBUG, "config: timeout_client is %d second%s",
379 timeout_client, PLURAL(timeout_client));
380 } else if (strcmp("timeout_fetchnews", param) == 0) {
381 timeout_fetchnews = atoi(value);
382 if (debugmode)
383 syslog(LOG_DEBUG, "config: timeout_fetchnews is %d second%s",
384 timeout_fetchnews, PLURAL(timeout_fetchnews));
385 } else if (strcmp("timeout_lock", param) == 0) {
386 read_timeout_lock(value, "config");
387 } else if (strncmp("groupexpire", param, 11) == 0) {
388 char *m;
389 m = param;
390 while (*m && !(isspace((unsigned char)*m)))
391 m++;
392 while (isspace((unsigned char)*m))
393 m++;
394 if (m && *m) {
395 time_t e, i = (time_t) atol(value);
396 if (i >= (INT_MAX / SECONDS_PER_DAY))
397 i = (INT_MAX / SECONDS_PER_DAY) - 1;
398 if (debugmode) {
399 if ((long)i < 0)
400 syslog(LOG_DEBUG,
401 "config: groupexpire for %s is %ld (never)",
402 m, (long)i);
403 else if (i == 0) {
404 fprintf(stderr,
405 "config: groupexpire for %s is 0, which is treated as \"use the default expire\"\n", m);
406 syslog(LOG_INFO,
407 "config: groupexpire for %s is 0, which is treated as \"use the default expire\"",
408 m);
409 } else
410 syslog(LOG_DEBUG,
411 "config: groupexpire for %s is %ld day%s",
412 m, (long)i, PLURAL(i));
413 }
414 e = time(NULL) - (time_t) (SECONDS_PER_DAY * i);
415 ent = (struct expire_entry *)
416 critmalloc(sizeof(struct expire_entry), "readconfig");
417 ent->group = critstrdup(m, "readconfig");
418 ent->days = i;
419 ent->xtime = e;
420 ent->next = prev;
421 prev = ent;
422 }
423 } else if ((strcmp("maxage", param) == 0) ||
424 (strcmp("maxold", param) == 0)) {
425 /* maxold is for compatibility with leafnode+ */
426 maxage = atoi(value);
427 #if LONG_MAX / 86400 <= INT_MAX
428 if (maxage > LONG_MAX / 86400)
429 {
430 maxage = 24854; /* 32-bit: LONG_MAX / 86400 - 1 */
431 ln_log(LNLOG_SWARNING, LNLOG_CTOP,
432 "warning: config: maxage cannot exceed %d, "
433 "please fix %s", maxage, s);
434 }
435 #endif
436 if (debugmode)
437 syslog(LOG_DEBUG, "config: maxage is %d", maxage);
438 } else if (strcmp("maxfetch", param) == 0) {
439 artlimit = strtoul(value, NULL, 10);
440 if (debugmode)
441 syslog(LOG_DEBUG, "config: maxfetch is %lu", artlimit);
442 } else if (strcmp("port", param) == 0) {
443 unsigned long pp = strtoul(value, NULL, 10);
444 if (p) {
445 if (pp == 0 || pp > 65535) {
446 syslog(LOG_ERR,
447 "config: invalid port number for nntpport %s",
448 value);
449 } else {
450 p->port = (unsigned int)pp;
451 if (debugmode)
452 syslog(LOG_DEBUG, "config: nntpport is %u",
453 p->port);
454 }
455 } else {
456 syslog(LOG_ERR, "config: no server for nntpport %s", value);
457 }
458 } else if (strcmp("noactive", param) == 0) {
459 long tmp;
460 errno = 0;
461 tmp = strtol(value,NULL,10);
462 if (errno) {
463 syslog(LOG_ERR, "config: invalid value \"%s\" for noactive", value);
464 } else {
465 if (p) {
466 p->updateactive = !tmp;
467 if (debugmode)
468 syslog(LOG_DEBUG, "config: %s active file updates for %s",
469 p->updateactive ? "enabled" : "no", p->name);
470 } else {
471 syslog(LOG_ERR, "config: no server for noactive = %s",
472 value);
473 }
474 }
475 } else if (strcmp("noxover", param) == 0) {
476 if (p) {
477 p->noxover = TRUE;
478 if (debugmode)
479 syslog(LOG_DEBUG, "config: no XOVER for %s",
480 p->name);
481 } else
482 syslog(LOG_ERR, "config: no server for noxover = %s", value);
483 } else if (strcmp("nodesc", param) == 0) {
484 if (p) {
485 p->descriptions = !atoi(value);
486 if (debugmode)
487 syslog(LOG_DEBUG, "config: %s LIST NEWSGROUPS for %s",
488 p->descriptions ? "enabled" : "no", p->name);
489 } else
490 syslog(LOG_ERR, "config: no server for nodesc = %s", value);
491 } else if (strcmp("nopost", param) == 0) {
492 if (p) {
493 p->nopost = atoi(value);
494 if (debugmode)
495 syslog(LOG_DEBUG, "config: nopost for %s is %d",
496 p->name, p->nopost);
497 } else
498 syslog(LOG_ERR, "config: no server for nopost = %s", value);
499 } else if (strcmp("post_anygroup", param) == 0) {
500 if (p) {
501 p->post_anygroup = atoi(value);
502 if (debugmode)
503 syslog(LOG_DEBUG, "config: post_anygroup for %s is %d",
504 p->name, p->nopost);
505 } else
506 syslog(LOG_ERR, "config: no server for post_anygroup = %s", value);
507 } else if (strcmp("noread", param) == 0) {
508 if (p) {
509 p->noread = atoi(value);
510 if (debugmode)
511 syslog(LOG_DEBUG, "config: noread for %s is %d",
512 p->name, p->noread);
513 } else
514 syslog(LOG_ERR, "config: no server for noread = %s", value);
515 } else if (strcmp("only_groups_match_all", param) == 0) {
516 if (p) {
517 p->only_groups_match_all = atoi(value);
518 if (debugmode)
519 syslog(LOG_DEBUG, "config: only_groups_match_all for %s is %d",
520 p->name, p->only_groups_match_all);
521 } else
522 syslog(LOG_ERR, "config: no server for only_groups_match_all = %s", value);
523 } else if (strcmp("initialfetch", param) == 0) {
524 initiallimit = strtoul(value, NULL, 10);
525 if (debugmode)
526 syslog(LOG_DEBUG, "config: initialfetch is %lu",
527 initiallimit);
528 } else if ((strcmp("server", param) == 0) ||
529 (strcmp("supplement", param) == 0)) {
530 if (debugmode)
531 syslog(LOG_DEBUG, "config: server is %s", value);
532 p = (struct server *)critmalloc(sizeof(struct server),
533 "allocating space for server");
534 p->name = critstrdup(value, "readconfig");
535 p->descriptions = TRUE;
536 p->next = NULL;
537 p->timeout = 30; /* default 30 seconds */
538 p->port = 0;
539 p->username = NULL;
540 p->password = NULL;
541 p->nopost = 0;
542 p->noread = 0;
543 p->noxover = 0;
544 p->post_anygroup = 0;
545 p->updateactive = TRUE;
546 p->group_pcre = NULL;
547 p->only_groups_match_all = 0;
548 if (servers == NULL)
549 servers = p;
550 else
551 q->next = p;
552 q = p;
553 } else if (0 == strcmp("only_groups_pcre", param)) {
554 pcre *re = gs_compile(value);
555 if (!re) exit(2);
556 if (p) {
557 p->group_pcre = re;
558 if (debugmode)
559 syslog(LOG_DEBUG, "config: only_groups_pcre for %s is %s",
560 p->name, value);
561 } else {
562 free(re);
563 syslog(LOG_ERR, "config: no server for nopost = %s", value);
564 }
565 } else {
566 ln_log(LNLOG_SERR, LNLOG_CTOP,
567 "config: unknown line %lu: \"%s = %s\"", curline,
568 param, value);
569 }
570 } else {
571 size_t i;
572 if ((i = strspn(l, " \t")) < strlen(l) && l[i] != '#') {
573 ln_log(LNLOG_SERR, LNLOG_CTOP,
574 "config: malformatted line %lu: \"%s\"", curline,
575 l);
576 }
577 }
578 }
579 if (maxage != 0 && maxage > expiredays && clamp_maxage == 0) {
580 ln_log(LNLOG_SERR, LNLOG_CTOP,
581 "config: maxage (%d) > expire (%d). This can cause duplicate download. Please fix your configuration, maxage must not be greater than expire.",
582 maxage, expiredays);
583 exit(1);
584 }
585 debug = debugmode;
586
587 if (!newsadmin) {
588 const char t[] = NEWS_USER;
589 newsadmin = critmalloc(strlen(fqdn) + strlen(t) + 2, "readconfig");
590 strcpy(newsadmin, t); /* RATS: ignore */
591 strcat(newsadmin, "@");
592 strcat(newsadmin, fqdn); /* RATS: ignore */
593 }
594
595 expire_base = ent;
596 fclose(f);
597 free(param);
598 free(value);
599
600 if (servers == NULL) {
601 syslog(LOG_ERR, "no server declaration in config file");
602 return 0;
603 }
604 if (!expire)
605 syslog(LOG_ERR, "no expire declaration in config file");
606
607 /* check for duplicate server configurations */
608 {
609 unsigned short port = 0;
610 struct servent *sp = getservbyname("nntp", "tcp");
611 if (sp) port = ntohs(sp->s_port);
612
613 for (p = servers; p ; p=p->next) {
614 for (q = p->next ; q ; q=q->next) {
615 unsigned short pp = p->port, qp = q->port;
616 if (!pp) pp = port;
617 if (!qp) qp = port;
618 if (!pp || !qp) {
619 syslog(LOG_ERR, "Cannot resolve service \"nntp\" protocol \"tcp\".");
620 fprintf(stderr, "Cannot resolve service \"nntp\" protocol \"tcp\".\n");
621 return 0;
622 }
623 if (pp != qp) continue;
624 if (strcasecmp(p->name, q->name)) continue;
625 syslog(LOG_ERR, "Duplicate definition for server %s port %u", p->name, (unsigned int)pp);
626 fprintf(stderr, "Duplicate definition for server %s port %u\n", p->name, (unsigned int)pp);
627 return 0;
628 }
629 }
630 }
631
632 if (debugmode > 1) {
633 getrlimit(RLIMIT_CORE, &corelimit);
634 corelimit.rlim_cur = COREFILESIZE;
635 if (setrlimit(RLIMIT_CORE, &corelimit) < 0 && debugmode)
636 syslog(LOG_DEBUG, "Changing core file size failed: %m");
637 corelimit.rlim_cur = 0;
638 getrlimit(RLIMIT_CORE, &corelimit);
639 if (debugmode)
640 syslog(LOG_DEBUG, "Core file size: %d", (int)corelimit.rlim_cur);
641 }
642
643 l = getenv("LN_LOCK_TIMEOUT");
644 if (l && *l)
645 read_timeout_lock(l, "LN_LOCK_TIMEOUT");
646
647 if (linebuffer) {
648 fflush(stdout);
649 setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
650 fflush(stderr);
651 setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
652 }
653
654 validatefqdn(logtostderr);
655
656 if (debugmode && verbose) {
657 puts("");
658 puts("WARNING: Make sure that syslog.conf captures news.debug logging");
659 puts("-------- and obtain your debug output from syslog.");
660 puts("WARNING: The screen output below is not sufficient. Check syslog!");
661 puts("");
662 sleep(3);
663 }
664 return 1;
665 }
666
667 /*
668 1997-05-27 - T. Sweeney - Find a group in the expireinfo linked list and return
669 its expire time. Otherwise, return zero.
670 */
671 static struct expire_entry *
lookup_expireent(char * group)672 lookup_expireent(char *group)
673 {
674 struct expire_entry *a;
675
676 a = expire_base;
677 while (a != NULL) {
678 if (ngmatch(a->group, group) == 0)
679 return a;
680 a = a->next;
681 }
682 return NULL;
683 }
684
685 static void
freeserver(struct server * a)686 freeserver(struct server *a) {
687 if (a->group_pcre) pcre_free(a->group_pcre);
688 if (a->name) free(a->name);
689 if (a->username) free(a->username);
690 if (a->password) free(a->password);
691 free(a);
692 }
693
694 void /* exported for exclusive use in nntpd.c */
freeservers(void)695 freeservers(void) {
696 struct server *i = servers, *n;
697
698 while(i != NULL) {
699 n = i->next;
700 freeserver(i);
701 i = n;
702 }
703 servers = NULL;
704 }
705
706
707 void
freeexpire(void)708 freeexpire(void)
709 {
710 struct expire_entry *a, *b;
711
712 a = expire_base;
713 while(a)
714 {
715 b = a->next;
716 free(a->group);
717 free(a);
718 a = b;
719 }
720 }
721
freeconfig(void)722 void freeconfig(void) {
723 freeservers();
724 if (newsadmin)
725 free(newsadmin);
726 freefilter();
727 if (filterfile)
728 free(filterfile);
729 freegetaline();
730 freeexpire();
731 (void)lookup(LOOKUP_FREE);
732 freelastreply();
733 }
734
lookup_expire(char * group)735 time_t lookup_expire(char *group)
736 {
737 struct expire_entry *e;
738 e = lookup_expireent(group);
739 if (e) return e->xtime;
740 return 0;
741 }
742
lookup_expiredays(char * group)743 int lookup_expiredays(char *group)
744 {
745 struct expire_entry *e;
746 e = lookup_expireent(group);
747 if (e) return e->days;
748 return 0;
749 }
750