1 /*  $Id: cc.c 10523 2021-01-17 21:52:00Z iulius $
2 **
3 **  Routines for the control channel.
4 **
5 **  Create a Unix-domain datagram socket that processes on the local server
6 **  send messages to.  The control channel is used only by ctlinnd to tell
7 **  the server to perform special functions.  We use datagrams so that we
8 **  don't need to do an accept() and tie up another descriptor.  recvfrom
9 **  seems to be broken on several systems, so the client passes in the
10 **  socket name.
11 **
12 **  This module completely rips away all pretense of software layering.
13 */
14 
15 #include "config.h"
16 #include "clibrary.h"
17 
18 #ifdef HAVE_UNIX_DOMAIN_SOCKETS
19 # include "portable/socket-unix.h"
20 #endif
21 
22 #include "inn/fdflag.h"
23 #include "inn/innconf.h"
24 #include "inn/qio.h"
25 #include "innd.h"
26 #include "inn/inndcomm.h"
27 #include "innperl.h"
28 
29 /*
30 **  An entry in the dispatch table.  The name, and implementing function,
31 **  of every command we support.
32 */
33 typedef struct _CCDISPATCH {
34     char Name;
35     int	argc;
36     const char * (*Function)(char *av[]);
37 } CCDISPATCH;
38 
39 
40 static const char *	CCallow(char *av[]);
41 static const char *	CCbegin(char *av[]);
42 static const char *	CCchgroup(char *av[]);
43 static const char *	CCdrop(char *av[]);
44 static const char *	CCfeedinfo(char *av[]);
45 static const char *	CCflush(char *av[]);
46 static const char *	CCflushlogs(char *unused[]);
47 static const char *	CCgo(char *av[]);
48 static const char *	CChangup(char *av[]);
49 static const char *	CCreserve(char *av[]);
50 static const char *	CClogmode(char *unused[]);
51 static const char *	CCmode(char *unused[]);
52 static const char *	CCname(char *av[]);
53 static const char *	CCnewgroup(char *av[]);
54 static const char *	CCparam(char *av[]);
55 static const char *	CCpause(char *av[]);
56 static const char *	CCreaders(char *av[]);
57 static const char *	CCreject(char *av[]);
58 static const char *	CCreload(char *av[]);
59 static const char *	CCrenumber(char *av[]);
60 static const char *	CCrmgroup(char *av[]);
61 static const char *	CCsend(char *av[]);
62 static const char *	CCshutdown(char *av[]);
63 static const char *	CCsignal(char *av[]);
64 static const char *	CCstathist(char *av[]);
65 static const char *	CCstatus(char *av[]);
66 static const char *	CCthrottle(char *av[]);
67 static const char *	CCtimer(char *av[]);
68 static const char *	CCtrace(char *av[]);
69 static const char *	CCxabort(char *av[]);
70 static const char *	CCxexec(char *av[]);
71 static const char *	CCperl(char *av[]);
72 static const char *	CCpython(char *av[]);
73 static const char *	CClowmark(char *av[]);
74 
75 
76 static char		*CCpath = NULL;
77 static char		**CCargv;
78 static char		CCnosite[] = "1 No such site";
79 static char		CCwrongtype[] = "1 Wrong site type";
80 static char		CCnogroup[] = "1 No such group";
81 static char		CCnochannel[] = "1 No such channel";
82 static char		CCnoreason[] = "1 Empty reason";
83 static char		CCbigreason[] = "1 Reason too long";
84 static char		CCnotrunning[] = "1 Must be running";
85 static struct buffer	CCreply;
86 static CHANNEL		*CCchan;
87 #ifdef HAVE_UNIX_DOMAIN_SOCKETS
88 static int		CCwriter;
89 #endif
90 static CCDISPATCH	CCcommands[] = {
91     {	SC_ADDHIST,	5, CCaddhist	},
92     {	SC_ALLOW,	1, CCallow	},
93     {	SC_BEGIN,	1, CCbegin	},
94     {	SC_CANCEL,	1, CCcancel	},
95     {	SC_CHANGEGROUP,	2, CCchgroup	},
96     {	SC_CHECKFILE,	0, CCcheckfile	},
97     {	SC_DROP,	1, CCdrop	},
98     {	SC_FEEDINFO,	1, CCfeedinfo	},
99     {	SC_PERL,	1, CCperl       },
100     {	SC_PYTHON,	1, CCpython     },
101     {	SC_FLUSH,	1, CCflush	},
102     {	SC_FLUSHLOGS,	0, CCflushlogs	},
103     {	SC_GO,		1, CCgo		},
104     {	SC_HANGUP,	1, CChangup	},
105     {	SC_LOGMODE,	0, CClogmode	},
106     {	SC_MODE,	0, CCmode	},
107     {	SC_NAME,	1, CCname	},
108     {	SC_NEWGROUP,	3, CCnewgroup	},
109     {	SC_PARAM,	2, CCparam	},
110     {	SC_PAUSE,	1, CCpause	},
111     {	SC_READERS,	2, CCreaders	},
112     {	SC_REJECT,	1, CCreject	},
113     {	SC_RENUMBER,	1, CCrenumber	},
114     {	SC_RELOAD,	2, CCreload	},
115     {	SC_RESERVE,	1, CCreserve	},
116     {	SC_RMGROUP,	1, CCrmgroup	},
117     {	SC_SEND,	2, CCsend	},
118     {	SC_SHUTDOWN,	1, CCshutdown	},
119     {	SC_SIGNAL,	2, CCsignal	},
120     {	SC_STATHIST,	1, CCstathist	},
121     {	SC_STATUS,	1, CCstatus	},
122     {	SC_THROTTLE,	1, CCthrottle	},
123     {   SC_TIMER,       1, CCtimer      },
124     {	SC_TRACE,	2, CCtrace	},
125     {	SC_XABORT,	1, CCxabort	},
126     {	SC_LOWMARK,	1, CClowmark	},
127     {	SC_XEXEC,	1, CCxexec	}
128 };
129 
130 static void CCresetup(int unused);
131 
132 
133 void
CCcopyargv(char * av[])134 CCcopyargv(char *av[])
135 {
136     char	**v;
137     int		i;
138 
139     /* Get the vector size. */
140     for (i = 0; av[i]; i++)
141 	continue;
142 
143     /* Get the vector, copy each element. */
144     for (v = CCargv = xmalloc((i + 1) * sizeof(char *)); *av; av++) {
145 	/* not to renumber */
146 	if (strncmp(*av, "-r", 2) == 0)
147 	    continue;
148 	*v++ = xstrdup(*av);
149     }
150     *v = NULL;
151 }
152 
153 
154 /*
155 **  Return a string representing our operating mode.
156 */
157 static const char *
CCcurrmode(void)158 CCcurrmode(void)
159 {
160     static char		buff[32];
161 
162     /* Server's mode. */
163     switch (Mode) {
164     default:
165 	snprintf(buff, sizeof(buff), "Unknown %d", Mode);
166 	return buff;
167     case OMrunning:
168 	return "running";
169     case OMpaused:
170 	return "paused";
171     case OMthrottled:
172 	return "throttled";
173     }
174 }
175 
176 
177 /*
178 **  Notify systemd of the current operating modes.
179 */
180 static void
CCsdnotify(void)181 CCsdnotify(void)
182 {
183 #ifdef HAVE_SD_NOTIFY
184     int status;
185 
186     buffer_sprintf(&CCreply, "STATUS=Server ");
187 
188     /* Server's mode. */
189     switch (Mode) {
190     default:
191         buffer_append_sprintf(&CCreply, "Unknown %d", Mode);
192         break;
193     case OMrunning:
194         buffer_append_sprintf(&CCreply, "running");
195         break;
196     case OMpaused:
197         buffer_append_sprintf(&CCreply, "paused %s", ModeReason);
198         break;
199     case OMthrottled:
200         buffer_append_sprintf(&CCreply, "throttled %s", ModeReason);
201         break;
202     }
203     if (RejectReason)
204         buffer_append_sprintf(&CCreply, ". Rejecting %s", RejectReason);
205 
206     /* Newsreaders. */
207     buffer_append_sprintf(&CCreply, ". Readers ");
208     if (innconf->readerswhenstopped)
209         buffer_append_sprintf(&CCreply, "independent ");
210     else
211         buffer_append_sprintf(&CCreply, "follow ");
212     if (NNRPReason == NULL)
213         buffer_append_sprintf(&CCreply, "enabled.");
214     else
215         buffer_append_sprintf(&CCreply, "disabled %s.", NNRPReason);
216 
217     buffer_append(&CCreply, "", 1);
218     status = sd_notify(false, CCreply.data);
219     if (status < 0)
220         warn("cannot notify systemd of new status: %s", strerror(-status));
221 #endif
222 }
223 
224 
225 /*
226 **  Add <> around Message-ID if needed.
227 */
228 static const char *
CCgetid(char * p,const char ** store)229 CCgetid(char *p, const char **store)
230 {
231     static char	NULLMESGID[] = "1 Empty Message-ID";
232     static struct buffer Save = { 0, 0, 0, NULL };
233     int i;
234 
235     if (*p == '\0')
236 	return NULLMESGID;
237     if (*p == '<') {
238 	if (p[1] == '\0' || p[1] == '>')
239 	    return NULLMESGID;
240 	*store = p;
241 	return NULL;
242     }
243 
244     /* Make sure the Message-ID buffer has room. */
245     i = 1 + strlen(p) + 1 + 1;
246     buffer_resize(&Save, i);
247     *store = Save.data;
248     snprintf(Save.data, Save.size, "<%s>", p);
249     return NULL;
250 }
251 
252 
253 /*
254 **  Abort and dump core.
255 */
256 static const char *
CCxabort(char * av[])257 CCxabort(char *av[])
258 {
259     syslog(L_FATAL, "%s abort %s", LogName, av[0]);
260     abort();
261     syslog(L_FATAL, "%s cant abort %m", LogName);
262     CleanupAndExit(1, av[0]);
263     /* NOTREACHED */
264 }
265 
266 
267 /*
268 **  Do the work needed to add a history entry.
269 */
270 const char *
CCaddhist(char * av[])271 CCaddhist(char *av[])
272 {
273     static char		DIGITS[] = "0123456789";
274     ARTDATA		Data;
275     const char *	p, *msgid;
276     bool		ok;
277     TOKEN		token;
278 
279     /* You must pass a <message-id> ID, the history API will hash it as it
280      * wants */
281     if ((p = CCgetid(av[0], &msgid)) != NULL)
282 	return p;
283 
284     /* If paused, don't try to use the history database since expire may be
285        running */
286     if (Mode == OMpaused)
287 	return "1 Server paused";
288 
289     /* If throttled by admin, briefly open the history database. */
290     if (Mode != OMrunning) {
291 	if (ThrottledbyIOError)
292 	    return "1 Server throttled";
293 	InndHisOpen();
294     }
295 
296     if (HIScheck(History, msgid)) {
297 	if (Mode != OMrunning) InndHisClose();
298 	return "1 Duplicate";
299     }
300     if (Mode != OMrunning) InndHisClose();
301     if (strspn(av[1], DIGITS) != strlen(av[1]))
302 	return "1 Bad arrival date";
303     Data.Arrived = atol(av[1]);
304     if (strspn(av[2], DIGITS) != strlen(av[2]))
305 	return "1 Bad expiration date";
306     Data.Expires = atol(av[2]);
307     if (strspn(av[3], DIGITS) != strlen(av[3]))
308 	return "1 Bad posted date";
309     Data.Posted = atol(av[3]);
310 
311     /* Allow empty tokens, but not badly formatted tokens. */
312     if (*av[4] != '\0' && !IsToken(av[4]))
313         return "1 Bad token";
314     token = TextToToken(av[4]);
315     if (Mode == OMrunning)
316 	ok = InndHisWrite(msgid, Data.Arrived, Data.Posted,
317 			  Data.Expires, &token);
318     else {
319 	/* Possible race condition, but documented in ctlinnd man page. */
320 	InndHisOpen();
321 	ok = InndHisWrite(msgid, Data.Arrived, Data.Posted,
322 			  Data.Expires, &token);
323 	InndHisClose();
324     }
325     return ok ? NULL : "1 Write failed";
326 }
327 
328 
329 /*
330 **  Do the work to allow foreign connections.
331 */
332 static const char *
CCallow(char * av[])333 CCallow(char *av[])
334 {
335     char	*p;
336 
337     if (RejectReason == NULL)
338 	return "1 Already allowed";
339     p = av[0];
340     if (*p && strcmp(p, RejectReason) != 0)
341 	return "1 Wrong reason";
342     free(RejectReason);
343     RejectReason = NULL;
344     CCsdnotify();
345     return NULL;
346 }
347 
348 
349 /*
350 **  Do the work needed to start feeding a (new) site.
351 */
352 static const char *
CCbegin(char * av[])353 CCbegin(char *av[])
354 {
355     SITE	*sp;
356     int		i;
357     int		length;
358     char	*p;
359     const char	*p1;
360     char	**strings;
361     NEWSGROUP	*ngp;
362     const char	*error;
363     char	*subbed;
364     char	*poison;
365 
366     /* If site already exists, drop it. */
367     if (SITEfind(av[0]) != NULL && (p1 = CCdrop(av)) != NULL)
368 	return p1;
369 
370     /* Find the named site. */
371     length = strlen(av[0]);
372     for (strings = SITEreadfile(true), i = 0; (p = strings[i]) != NULL; i++)
373 	if ((p[length] == NF_FIELD_SEP || p[length] == NF_SUBFIELD_SEP)
374 	 && strncasecmp(p, av[0], length) == 0) {
375 	    p = xstrdup(p);
376 	    break;
377 	}
378     if (p == NULL)
379 	return CCnosite;
380 
381     if (p[0] == 'M' && p[1] == 'E' && p[2] == NF_FIELD_SEP)
382 	sp = &ME;
383     else {
384 	/* Get space for the new site entry, and space for it in all
385 	 * the groups. */
386 	for (i = nSites, sp = Sites; --i >= 0; sp++)
387 	    if (sp->Name == NULL)
388 		break;
389 	if (i < 0) {
390 	    nSites++;
391             Sites = xrealloc(Sites, nSites * sizeof(SITE));
392 	    sp = &Sites[nSites - 1];
393 	    sp->Next = sp->Prev = NOSITE;
394 	    for (i = nGroups, ngp = Groups; --i >= 0; ngp++) {
395                 ngp->Sites = xrealloc(ngp->Sites, nSites * sizeof(int));
396                 ngp->Poison = xrealloc(ngp->Poison, nSites * sizeof(int));
397 	    }
398 	}
399     }
400 
401     /* Parse. */
402     subbed = xmalloc(nGroups);
403     poison = xmalloc(nGroups);
404     error = SITEparseone(p, sp, subbed, poison);
405     free(subbed);
406     free(poison);
407     if (error != NULL) {
408 	free((void *)p);
409 	syslog(L_ERROR, "%s bad_newsfeeds %s", av[0], error);
410 	return "1 Parse error";
411     }
412 
413     if (sp != &ME && (!SITEsetup(sp) || !SITEfunnelpatch()))
414 	return "1 Startup error";
415     SITEforward(sp, "begin");
416     return NULL;
417 }
418 
419 
420 /*
421 **  Common code to change a group's flags.
422 */
423 static const char *
CCdochange(NEWSGROUP * ngp,char * Rest)424 CCdochange(NEWSGROUP *ngp, char *Rest)
425 {
426     int			length;
427     char		*p;
428 
429     if (ngp->Rest[0] == Rest[0]) {
430 	length = strlen(Rest);
431 	if (ngp->Rest[length] == '\n' && strncmp(ngp->Rest, Rest, length) == 0)
432 	    return "0 Group status unchanged";
433     }
434     if (Mode != OMrunning)
435 	return CCnotrunning;
436 
437     p = xstrdup(ngp->Name);
438     if (!ICDchangegroup(ngp, Rest)) {
439 	syslog(L_NOTICE, "%s cant change_group %s to %s", LogName, p, Rest);
440 	free(p);
441 	return "1 Change failed (probably can't write active?)";
442     }
443     syslog(L_NOTICE, "%s change_group %s to %s", LogName, p, Rest);
444     free(p);
445     return NULL;
446 }
447 
448 
449 /*
450 **  Change the mode of a newsgroup.
451 */
452 static const char *
CCchgroup(char * av[])453 CCchgroup(char *av[])
454 {
455     NEWSGROUP	*ngp;
456     char	*Rest;
457 
458     if ((ngp = NGfind(av[0])) == NULL)
459 	return CCnogroup;
460     Rest = av[1];
461     if (Rest[0] != NF_FLAG_ALIAS) {
462 	Rest[1] = '\0';
463 	if (isupper((unsigned char) Rest[0]))
464 	    Rest[0] = tolower((unsigned char) Rest[0]);
465     }
466     return CCdochange(ngp, Rest);
467 }
468 
469 
470 /*
471 **  Cancel a message.
472 */
473 const char *
CCcancel(char * av[])474 CCcancel(char *av[])
475 {
476     ARTDATA	Data;
477     const char *	p, *msgid;
478 
479     Data.Posted = Data.Arrived = Now.tv_sec;
480     Data.Expires = 0;
481     Data.Feedsite = "?";
482     if ((p = CCgetid(av[0], &msgid)) != NULL)
483 	return p;
484 
485     Data.HdrContent[HDR__MESSAGE_ID].Value = (char *)msgid;
486     Data.HdrContent[HDR__MESSAGE_ID].Length = strlen(msgid);
487     if (Mode == OMrunning)
488 	ARTcancel(&Data, msgid, true);
489     else {
490 	/* If paused, don't try to use the history database since expire may be
491 	   running */
492 	if (Mode == OMpaused)
493 	    return "1 Server paused";
494 	if (ThrottledbyIOError)
495 	    return "1 Server throttled";
496 	/* Possible race condition, but documented in ctlinnd man page. */
497 	InndHisOpen();
498 	ARTcancel(&Data, msgid, true);
499 	InndHisClose();
500     }
501     if (innconf->logcancelcomm)
502 	syslog(L_NOTICE, "%s cancelled %s", LogName, msgid);
503     return NULL;
504 }
505 
506 
507 /*
508 **  Syntax-check the newsfeeds file.
509 */
510 const char *
CCcheckfile(char * unused[]UNUSED)511 CCcheckfile(char *unused[] UNUSED)
512 {
513   char		**strings;
514   char		*p;
515   int		i;
516   int		errors;
517   const char *	error;
518   SITE		fake;
519   bool		needheaders, needoverview, needpath, needstoredgroup;
520   bool		needreplicdata;
521 
522   /* Parse all site entries. */
523   strings = SITEreadfile(false);
524   fake.Buffer.size = 0;
525   fake.Buffer.data = NULL;
526   /* save global variables not to be changed */
527   needheaders = NeedHeaders;
528   needoverview = NeedOverview;
529   needpath = NeedPath;
530   needstoredgroup = NeedStoredGroup;
531   needreplicdata = NeedReplicdata;
532   for (errors = 0, i = 0; (p = strings[i]) != NULL; i++) {
533     if ((error = SITEparseone(p, &fake, (char *)NULL, (char *)NULL)) != NULL) {
534       syslog(L_ERROR, "%s bad_newsfeeds %s", MaxLength(p, p), error);
535       errors++;
536     }
537     SITEfree(&fake);
538   }
539   free(strings);
540   /* restore global variables not to be changed */
541   NeedHeaders = needheaders;
542   NeedOverview = needoverview;
543   NeedPath = needpath;
544   NeedStoredGroup = needstoredgroup;
545   NeedReplicdata = needreplicdata;
546 
547   if (errors == 0)
548     return NULL;
549 
550   buffer_sprintf(&CCreply, "1 Found %d error(s) -- see syslog", errors);
551   return CCreply.data;
552 }
553 
554 
555 /*
556 **  Drop a site.
557 */
558 static const char *
CCdrop(char * av[])559 CCdrop(char *av[])
560 {
561     SITE	*sp;
562     NEWSGROUP	*ngp;
563     int		*ip;
564     int		idx;
565     int		i;
566     int		j;
567 
568     if ((sp = SITEfind(av[0])) == NULL)
569 	return CCnosite;
570 
571     SITEdrop(sp);
572 
573     /* Loop over all groups, and if the site is in a group, clobber it. */
574     for (idx = sp - Sites, i = nGroups, ngp = Groups; --i >= 0; ngp++) {
575 	for (j = ngp->nSites, ip = ngp->Sites; --j >= 0; ip++)
576 	    if (*ip == idx)
577 		*ip = NOSITE;
578 	for (j = ngp->nPoison, ip = ngp->Poison; --j >= 0; ip++)
579 	    if (*ip == idx)
580 		*ip = NOSITE;
581     }
582 
583 	return NULL;
584 }
585 
586 /*
587 **  Return info on the feeds for one, or all, sites
588 */
589 static const char *
CCfeedinfo(char * av[])590 CCfeedinfo(char *av[])
591 {
592     SITE	*sp;
593     char	*p;
594     int		i;
595 
596     buffer_set(&CCreply, "0 ", 2);
597     p = av[0];
598     if (*p != '\0') {
599 	if ((sp = SITEfind(p)) == NULL)
600 	    return "1 No such site";
601 
602 	SITEinfo(&CCreply, sp, true);
603 	while ((sp = SITEfindnext(p, sp)) != NULL)
604 	    SITEinfo(&CCreply, sp, true);
605     }
606     else
607 	for (i = nSites, sp = Sites; --i >= 0; sp++)
608 	    if (sp->Name)
609 		SITEinfo(&CCreply, sp, false);
610 
611     buffer_append(&CCreply, "", 1);
612     return CCreply.data;
613 }
614 
615 
616 static const char *
CCperl(char * av[]UNUSED)617 CCperl(char *av[] UNUSED)
618 {
619 #ifdef DO_PERL
620     switch (av[0][0]) {
621     default:
622 	return "1 Bad flag";
623     case 'y':
624 	if (PerlFilterActive)
625 	    return "1 Perl filter already enabled";
626         else if (!PerlFilter(true))
627             return "1 Perl filter not defined";
628 	break;
629     case 'n':
630 	if (!PerlFilterActive)
631 	    return "1 Perl filter already disabled";
632         PerlFilter(false);
633 	break;
634     }
635     return NULL;
636 #else
637     return "1 Perl filtering support not compiled in";
638 #endif
639 }
640 
641 
642 static const char *
CCpython(char * av[]UNUSED)643 CCpython(char *av[] UNUSED)
644 {
645 #ifdef DO_PYTHON
646     return PYcontrol(av);
647 #else
648     return "1 Python filtering support not compiled in";
649 #endif
650 }
651 
652 
653 /*
654 **  Flush all sites or one site.
655 */
656 static const char *
CCflush(char * av[])657 CCflush(char *av[])
658 {
659     SITE	*sp;
660     int		i;
661     char	*p;
662 
663     p = av[0];
664     if (*p == '\0') {
665 	ICDwrite();
666 	for (sp = Sites, i = nSites; --i >= 0; sp++)
667 	    SITEflush(sp, true);
668 	syslog(L_NOTICE, "%s flush_all", LogName);
669     }
670     else  {
671 	if ((sp = SITEfind(p)) == NULL)
672 	    return CCnosite;
673 	syslog(L_NOTICE, "%s flush", sp->Name);
674 	SITEflush(sp, true);
675     }
676     return NULL;
677 }
678 
679 
680 /*
681 **  Flush the log files as well as exploder and process channels.
682 */
683 static const char *
CCflushlogs(char * unused[]UNUSED)684 CCflushlogs(char *unused[] UNUSED)
685 {
686     SITE        *sp;
687     CHANNEL     *cp;
688     int         i;
689 
690     if (Debug)
691 	return "1 In debug mode";
692 
693     ICDwrite();
694     syslog(L_NOTICE, "%s flushlogs %s", LogName, CCcurrmode());
695     ReopenLog(Log);
696     ReopenLog(Errlog);
697     /* Flush exploder and process channels so that they take into account
698      * the new log files (for instance during log rotation). */
699     for (sp = Sites, i = nSites; --i >= 0; sp++) {
700         if (((cp = sp->Channel) != NULL)
701              && ((cp->Type == CTexploder) || (cp->Type == CTprocess))) {
702             SITEflush(sp, true);
703             syslog(L_NOTICE, "%s flush", sp->Name);
704         }
705     }
706     return NULL;
707 }
708 
709 
710 /*
711 **  Leave paused or throttled mode.
712 */
713 static const char *
CCgo(char * av[])714 CCgo(char *av[])
715 {
716     static char	YES[] = "y";
717     char	*p;
718 
719     p = av[0];
720     if (Reservation && strcmp(p, Reservation) == 0) {
721 	free(Reservation);
722 	Reservation = NULL;
723     }
724     if (RejectReason && strcmp(p, RejectReason) == 0) {
725 	free(RejectReason);
726 	RejectReason = NULL;
727     }
728 
729     if (Mode == OMrunning)
730 	return "1 Already running";
731     if (*p && strcmp(p, ModeReason) != 0)
732 	return "1 Wrong reason";
733 
734 #if defined(DO_PERL)
735     PLmode(Mode, OMrunning, p);
736 #endif /* defined(DO_PERL) */
737 #if defined(DO_PYTHON)
738     PYmode(Mode, OMrunning, p);
739 #endif /* defined(DO_PYTHON) */
740 
741     free(ModeReason);
742     ModeReason = NULL;
743     Mode = OMrunning;
744     ThrottledbyIOError = false;
745 
746     if (NNRPReason != NULL && !innconf->readerswhenstopped) {
747 	av[0] = YES;
748 	av[1] = p;
749 	CCreaders(av);
750     }
751     if (ErrorCount < 0)
752 	ErrorCount = IO_ERROR_COUNT;
753     InndHisOpen();
754     syslog(L_NOTICE, "%s running", LogName);
755     CCsdnotify();
756     if (ICDneedsetup)
757 	ICDsetup(true);
758     SCHANwakeup(&Mode);
759     return NULL;
760 }
761 
762 
763 /*
764 **  Hangup a channel.
765 */
766 static const char *
CChangup(char * av[])767 CChangup(char *av[])
768 {
769     CHANNEL	*cp;
770     int		fd;
771     char	*p;
772     int		i;
773 
774     /* Parse the argument, a channel number. */
775     for (p = av[0], fd = 0; *p; p++) {
776 	if (!isdigit((unsigned char) *p))
777 	    return "1 Bad channel number";
778 	fd = fd * 10 + *p - '0';
779     }
780 
781     /* Loop over all channels for the desired one. */
782     for (i = 0; (cp = CHANiter(&i, CTany)) != NULL; )
783 	if (cp->fd == fd) {
784 	    p = CHANname(cp);
785 	    switch (cp->Type) {
786 	    default:
787 		snprintf(CCreply.data, CCreply.size, "1 Can't close %s", p);
788 		return CCreply.data;
789 	    case CTexploder:
790 	    case CTprocess:
791 	    case CTfile:
792 	    case CTnntp:
793 	    case CTreject:
794 		syslog(L_NOTICE, "%s hangup", p);
795 		CHANclose(cp, p);
796 		return NULL;
797 	    }
798 	}
799     return "1 Not active";
800 }
801 
802 
803 /*
804 **  Read a file containing lines of the form "newsgroup lowmark" and reset
805 **  the low article number for the specified groups.
806 */
807 static const char *
CClowmark(char * av[])808 CClowmark(char *av[])
809 {
810     long lo;
811     char *line, *cp;
812     const char  *ret = NULL;
813     QIOSTATE *qp;
814     NEWSGROUP *ngp;
815 
816     if (Mode != OMrunning)
817 	return CCnotrunning;
818     if (ICDneedsetup)
819 	return "1 Must first reload newsfeeds";
820     if ((qp = QIOopen(av[0])) == NULL) {
821 	syslog(L_ERROR, "%s cant open %s %m", LogName, av[0]);
822 	return "1 Cannot read input file";
823     }
824     while ((line = QIOread(qp)) != NULL) {
825 	if (QIOerror(qp))
826 		break;
827 	if (QIOtoolong(qp)) {
828 	    ret = "1 Malformed input line (too long)";
829 	    break;
830 	}
831 	while (ISWHITE(*line))
832 	    line++;
833 	for (cp = line; *cp && !ISWHITE(*cp); cp++)
834 	    ;
835 	if (*cp == '\0') {
836 	    ret = "1 Malformed input line (only one field)";
837 	    break;
838 	}
839 	*cp++ = '\0';
840 	while (ISWHITE(*cp))
841 	    cp++;
842 	if (strspn(cp, "0123456789") != strlen(cp)) {
843 	    ret = "1 Malformed input line (non-digit in low mark)";
844 	    break;
845 	}
846 	if ((lo = atol(cp)) == 0 && (cp[0] != '0' || cp[1] != '\0')) {
847 	    ret = "1 Malformed input line (bad low mark)";
848 	    break;
849 	}
850         if ((ngp = NGfind(line)) == NULL) {
851 	    /* ret = CCnogroup; break; */
852 	    continue;
853 	}
854         if (!NGlowmark(ngp, lo)) {
855 	    ret = "1 Cannot set low mark - see syslog";
856 	    break;
857 	}
858     }
859     if (ret == NULL && QIOerror(qp)) {
860 	syslog(L_ERROR, "%s cant read %s %m", LogName, av[0]);
861 	ret = "1 Error reading input file";
862     }
863     QIOclose(qp);
864     ICDwrite();
865     return ret;
866 }
867 
868 
869 /*
870 **  Return our operating mode.
871 */
872 static const char *
CCmode(char * unused[]UNUSED)873 CCmode(char *unused[] UNUSED)
874 {
875     int count, index;
876 
877 #ifdef DO_PERL
878     char *stats;
879 #endif
880 
881     buffer_sprintf(&CCreply, "0 Server ");
882 
883     /* Server's mode. */
884     switch (Mode) {
885     default:
886         buffer_append_sprintf(&CCreply, "Unknown %d\n", Mode);
887 	break;
888     case OMrunning:
889         buffer_append_sprintf(&CCreply, "running\n");
890 	break;
891     case OMpaused:
892         buffer_append_sprintf(&CCreply, "paused %s\n", ModeReason);
893 	break;
894     case OMthrottled:
895         buffer_append_sprintf(&CCreply, "throttled %s\n", ModeReason);
896 	break;
897     }
898     if (RejectReason)
899         buffer_append_sprintf(&CCreply, "Rejecting %s\n", RejectReason);
900     else
901         buffer_append_sprintf(&CCreply, "Allowing remote connections\n");
902 
903     /* Server parameters. */
904     for (count = 0, index = 0; CHANiter(&index, CTnntp) != NULL; )
905 	count++;
906     buffer_append_sprintf(&CCreply, "Parameters c %lu i %lu (%d) l %lu o %d"
907                    " t %ld H %d T %d X %ld %s %s\n",
908                   innconf->artcutoff, innconf->maxconnections, count,
909                   innconf->maxartsize, MaxOutgoing, (long) TimeOut.tv_sec,
910                   RemoteLimit, RemoteTotal, (long) RemoteTimer,
911                   innconf->xrefslave ? "slave" : "normal",
912                   AnyIncoming ? "any" : "specified");
913 
914     /* Reservation. */
915     if (Reservation)
916         buffer_append_sprintf(&CCreply, "Reserved %s\n", Reservation);
917     else
918         buffer_append_sprintf(&CCreply, "Not reserved\n");
919 
920     /* Newsreaders. */
921     buffer_append_sprintf(&CCreply, "Readers ");
922     if (innconf->readerswhenstopped)
923         buffer_append_sprintf(&CCreply, "independent ");
924     else
925         buffer_append_sprintf(&CCreply, "follow ");
926     if (NNRPReason == NULL)
927         buffer_append_sprintf(&CCreply, "enabled");
928     else
929         buffer_append_sprintf(&CCreply, "disabled %s", NNRPReason);
930 
931 #ifdef DO_PERL
932     buffer_append_sprintf(&CCreply, "\nPerl filtering ");
933     if (PerlFilterActive)
934         buffer_append_sprintf(&CCreply, "enabled");
935     else
936         buffer_append_sprintf(&CCreply, "disabled");
937     stats = PLstats();
938     if (stats != NULL) {
939         buffer_append_sprintf(&CCreply, "\nPerl filter stats: %s", stats);
940         free(stats);
941     }
942 #endif
943 
944 #ifdef DO_PYTHON
945     buffer_append_sprintf(&CCreply, "\nPython filtering ");
946     if (PythonFilterActive)
947         buffer_append_sprintf(&CCreply, "enabled");
948     else
949         buffer_append_sprintf(&CCreply, "disabled");
950 #endif
951 
952     buffer_append(&CCreply, "", 1);
953     return CCreply.data;
954 }
955 
956 
957 /*
958 **  Log our operating mode (via syslog).
959 */
960 static const char *
CClogmode(char * unused[]UNUSED)961 CClogmode(char *unused[] UNUSED)
962 {
963     syslog(L_NOTICE, "%s servermode %s", LogName, CCcurrmode());
964     return NULL;
965 }
966 
967 
968 /*
969 **  Name the channels.  ("Name the bats -- simple names.")
970 */
971 static const char *
CCname(char * av[])972 CCname(char *av[])
973 {
974     CHANNEL *cp;
975     int i, count;
976     const char *mode;
977 
978     if (av[0][0] != '\0') {
979         cp = CHANfromdescriptor(atoi(av[0]));
980         if (cp == NULL)
981             return xstrdup(CCnochannel);
982         buffer_sprintf(&CCreply, "0 %s", CHANname(cp));
983 	return CCreply.data;
984     }
985     buffer_set(&CCreply, "0 ", 2);
986     for (count = 0, i = 0; (cp = CHANiter(&i, CTany)) != NULL; ) {
987 	if (cp->Type == CTfree)
988 	    continue;
989 	if (++count > 1)
990 	    buffer_append(&CCreply, "\n", 1);
991         buffer_append_sprintf(&CCreply, "%s", CHANname(cp));
992 	switch (cp->Type) {
993 	case CTremconn:
994             buffer_append_sprintf(&CCreply, ":remconn::");
995 	    break;
996 	case CTreject:
997             buffer_append_sprintf(&CCreply, ":reject::");
998 	    break;
999 	case CTnntp:
1000             mode = (cp->MaxCnx > 0 && cp->ActiveCnx == 0) ? "paused" : "";
1001             buffer_append_sprintf(&CCreply, ":%s:%ld:%s",
1002                            cp->State == CScancel ? "cancel" : "nntp",
1003                            (long) (Now.tv_sec - cp->LastActive), mode);
1004 	    break;
1005 	case CTlocalconn:
1006             buffer_append_sprintf(&CCreply, ":localconn::");
1007 	    break;
1008 	case CTcontrol:
1009             buffer_append_sprintf(&CCreply, ":control::");
1010 	    break;
1011 	case CTfile:
1012             buffer_append_sprintf(&CCreply, "::");
1013 	    break;
1014 	case CTexploder:
1015             buffer_append_sprintf(&CCreply, ":exploder::");
1016 	    break;
1017 	case CTprocess:
1018             buffer_append_sprintf(&CCreply, ":");
1019 	    break;
1020 	default:
1021             buffer_append_sprintf(&CCreply, ":unknown::");
1022 	    break;
1023 	}
1024     }
1025     buffer_append(&CCreply, "", 1);
1026     return CCreply.data;
1027 }
1028 
1029 
1030 /*
1031 **  Create a newsgroup.
1032 */
1033 static const char *
CCnewgroup(char * av[])1034 CCnewgroup(char *av[])
1035 {
1036     static char		*TIMES = NULL;
1037     static char		WHEN[] = "updating active.times";
1038     int			fd;
1039     char		*p;
1040     NEWSGROUP		*ngp;
1041     char		*Name;
1042     char		*Rest;
1043     const char *		who;
1044     char		*buff = NULL;
1045     int			oerrno;
1046 
1047     if (TIMES == NULL)
1048 	TIMES = concatpath(innconf->pathdb, INN_PATH_ACTIVETIMES);
1049 
1050     Name = av[0];
1051     if (Name[0] == '.' || strspn(Name, "0123456789") == strlen(Name))
1052 	return "1 Illegal newsgroup name";
1053     for (p = Name; *p; p++)
1054 	if (*p == '.') {
1055 	    if (p[1] == '.' || p[1] == '\0')
1056 		return "1 Double or trailing period in newsgroup name";
1057 	}
1058 	else if (ISWHITE(*p) || *p == ':' || *p == '!' || *p == '/')
1059 	    return "1 Illegal character in newsgroup name";
1060 
1061     Rest = av[1];
1062     if (Rest[0] != NF_FLAG_ALIAS) {
1063 	Rest[1] = '\0';
1064 	if (isupper((unsigned char) Rest[0]))
1065 	    Rest[0] = tolower((unsigned char) Rest[0]);
1066     }
1067 
1068     who = av[2];
1069     if (*who == '\0')
1070         who = NEWSMASTER;
1071     if (!is_valid_utf8(who))
1072         return "1 Invalid UTF-8 creator's name";
1073 
1074     if (strlen(Name) + strlen(Rest) > SMBUF - 24)
1075 	return "1 Name too long";
1076 
1077     if ((ngp = NGfind(Name)) != NULL)
1078 	return CCdochange(ngp, Rest);
1079 
1080     if (Mode == OMthrottled && ThrottledbyIOError)
1081 	return "1 server throttled";
1082 
1083     /* Update the log of groups created.  Don't use stdio because SunOS
1084      * 4.1 has broken libc which can't handle fd's greater than 127. */
1085     if ((fd = open(TIMES, O_WRONLY | O_APPEND | O_CREAT, 0664)) < 0) {
1086 	oerrno = errno;
1087 	syslog(L_ERROR, "%s cant open %s %m", LogName, TIMES);
1088 	IOError(WHEN, oerrno);
1089     }
1090     else {
1091         xasprintf(&buff, "%s %ld %s\n", Name, (long) Now.tv_sec, who);
1092 	if (xwrite(fd, buff, strlen(buff)) < 0) {
1093 	    oerrno = errno;
1094 	    syslog(L_ERROR, "%s cant write %s %m", LogName, TIMES);
1095 	    IOError(WHEN, oerrno);
1096 	}
1097 
1098 	free(buff);
1099 
1100 	if (close(fd) < 0) {
1101 	    oerrno = errno;
1102 	    syslog(L_ERROR, "%s cant close %s %m", LogName, TIMES);
1103 	    IOError(WHEN, oerrno);
1104 	}
1105     }
1106 
1107     /* Update the in-core data. */
1108     if (!ICDnewgroup(Name, Rest))
1109 	return "1 Failed";
1110     syslog(L_NOTICE, "%s newgroup %s as %s", LogName, Name, Rest);
1111 
1112     return NULL;
1113 }
1114 
1115 
1116 /*
1117 **  Parse and set a boolean flag.
1118 */
1119 static bool
CCparsebool(char name,bool * bp,char value)1120 CCparsebool(char name, bool *bp, char value)
1121 {
1122     switch (value) {
1123     default:
1124 	return false;
1125     case 'y':
1126 	*bp = false;
1127 	break;
1128     case 'n':
1129 	*bp = true;
1130 	break;
1131     }
1132     syslog(L_NOTICE, "%s changed -%c %c", LogName, name, value);
1133     return true;
1134 }
1135 
1136 
1137 /*
1138 **  Change a running parameter.
1139 */
1140 static const char *
CCparam(char * av[])1141 CCparam(char *av[])
1142 {
1143     static char	BADVAL[] = "1 Bad value";
1144     char	*p;
1145     int		temp;
1146 
1147     p = av[1];
1148     switch (av[0][0]) {
1149     default:
1150 	return "1 Unknown parameter";
1151     case 'a':
1152 	if (!CCparsebool('a', (bool *)&AnyIncoming, *p))
1153 	    return BADVAL;
1154 	break;
1155     case 'c':
1156 	innconf->artcutoff = strtoul(p, NULL, 10);
1157 	syslog(L_NOTICE, "%s changed -c %lu", LogName, innconf->artcutoff);
1158 	break;
1159     case 'i':
1160 	innconf->maxconnections = strtoul(p, NULL, 10);
1161 	syslog(L_NOTICE, "%s changed -i %lu", LogName, innconf->maxconnections);
1162 	break;
1163     case 'l':
1164 	innconf->maxartsize = strtoul(p, NULL, 10);
1165 	syslog(L_NOTICE, "%s changed -l %lu", LogName, innconf->maxartsize);
1166 	break;
1167     case 'n':
1168 	if (!CCparsebool('n', (bool *)&innconf->readerswhenstopped, *p))
1169 	    return BADVAL;
1170         CCsdnotify();
1171 	break;
1172     case 'o':
1173 	MaxOutgoing = atoi(p);
1174 	syslog(L_NOTICE, "%s changed -o %d", LogName, MaxOutgoing);
1175 	break;
1176     case 't':
1177 	TimeOut.tv_sec = atol(p);
1178 	syslog(L_NOTICE, "%s changed -t %ld", LogName, (long)TimeOut.tv_sec);
1179 	break;
1180     case 'H':
1181 	RemoteLimit = atoi(p);
1182 	syslog(L_NOTICE, "%s changed -H %d", LogName, RemoteLimit);
1183 	break;
1184     case 'T':
1185         temp = atoi(p);
1186 	if (temp > REMOTETABLESIZE) {
1187 	    syslog(L_NOTICE, "%s -T must be lower than %d",
1188 		   LogName, REMOTETABLESIZE+1);
1189 	    temp = REMOTETABLESIZE;
1190 	}
1191 	syslog(L_NOTICE, "%s changed -T from %d to %d",
1192 	       LogName, RemoteTotal, temp);
1193 	RemoteTotal = temp;
1194 	break;
1195     case 'X':
1196 	RemoteTimer = (time_t) atoi(p);
1197 	syslog(L_NOTICE, "%s changed -X %d", LogName, (int) RemoteTimer);
1198 	break;
1199     }
1200     return NULL;
1201 }
1202 
1203 
1204 /*
1205 **  Common code to implement a pause or throttle.
1206 */
1207 const char *
CCblock(OPERATINGMODE NewMode,char * reason)1208 CCblock(OPERATINGMODE NewMode, char *reason)
1209 {
1210     static char		NO[] = "n";
1211     char *		av[2];
1212 
1213     if (*reason == '\0')
1214 	return CCnoreason;
1215 
1216     if (strlen(reason) > MAX_REASON_LEN) /* MAX_REASON_LEN is as big as is safe. */
1217 	return CCbigreason;
1218 
1219     if (!is_valid_utf8(reason))
1220         return "1 Invalid UTF-8 reason";
1221 
1222     if (Reservation) {
1223 	if (strcmp(reason, Reservation) != 0) {
1224 	    snprintf(CCreply.data, CCreply.size, "1 Reserved \"%s\"",
1225                      Reservation);
1226 	    return CCreply.data;
1227 	}
1228 	free(Reservation);
1229 	Reservation = NULL;
1230     }
1231 
1232 #ifdef DO_PERL
1233     PLmode(Mode, NewMode, reason);
1234 #endif
1235 #ifdef DO_PYTHON
1236     PYmode(Mode, NewMode, reason);
1237 #endif
1238 
1239     ICDwrite();
1240     InndHisClose();
1241     Mode = NewMode;
1242     if (ModeReason)
1243 	free(ModeReason);
1244     ModeReason = xstrdup(reason);
1245     /* Disallow readers when the server is paused or throttled. */
1246     if (NNRPReason == NULL && !innconf->readerswhenstopped) {
1247 	av[0] = NO;
1248 	av[1] = ModeReason;
1249 	CCreaders(av);
1250     }
1251     syslog(L_NOTICE, "%s %s %s",
1252 	LogName, NewMode == OMpaused ? "paused" : "throttled", reason);
1253     CCsdnotify();
1254     return NULL;
1255 }
1256 
1257 
1258 /*
1259 **  Enter paused mode.
1260 */
1261 static const char *
CCpause(char * av[])1262 CCpause(char *av[])
1263 {
1264     switch (Mode) {
1265     case OMrunning:
1266 	return CCblock(OMpaused, av[0]);
1267     case OMpaused:
1268 	return "1 Already paused";
1269     case OMthrottled:
1270 	return "1 Already throttled";
1271     case OMshutdown:
1272         return "1 Shutting down";
1273     }
1274     return "1 Unknown mode";
1275 }
1276 
1277 
1278 /*
1279 **  Allow or disallow newsreaders.
1280 */
1281 static const char *
CCreaders(char * av[])1282 CCreaders(char *av[])
1283 {
1284     const char	*p;
1285 
1286     switch (av[0][0]) {
1287     default:
1288 	return "1 Bad flag";
1289     case 'y':
1290 	if (NNRPReason == NULL)
1291 	    return "1 Already allowing readers";
1292 	p = av[1];
1293 	if (*p && strcmp(p, NNRPReason) != 0)
1294 	    return "1 Wrong reason";
1295 	free(NNRPReason);
1296 	NNRPReason = NULL;
1297 	break;
1298     case 'n':
1299 	if (NNRPReason)
1300 	    return "1 Already not allowing readers";
1301 	p = av[1];
1302 	if (*p == '\0')
1303 	    return CCnoreason;
1304 	if (strlen(p) > MAX_REASON_LEN) /* MAX_REASON_LEN is as big as is safe. */
1305 	    return CCbigreason;
1306         if (!is_valid_utf8(p))
1307             return "1 Invalid UTF-8 reason";
1308 	NNRPReason = xstrdup(p);
1309 	break;
1310     }
1311     CCsdnotify();
1312     return NULL;
1313 }
1314 
1315 
1316 /*
1317 **  Re-exec ourselves.
1318 */
1319 static const char *
CCxexec(char * av[])1320 CCxexec(char *av[])
1321 {
1322     char	*innd;
1323     char	*p;
1324     int		i;
1325     const char  *s;
1326     int         count;
1327     int         status;
1328 
1329     if (CCargv == NULL)
1330 	return "1 no argv!";
1331 
1332     innd = concatpath(innconf->pathbin, "innd");
1333     /* Get the pathname. */
1334     p = av[0];
1335     if (*p == '\0' || strcmp(p, "innd") == 0)
1336 	CCargv[0] = innd;
1337     else
1338 	return "1 Bad value";
1339 
1340 #ifdef DO_PERL
1341     PLmode(Mode, OMshutdown, av[0]);
1342 #endif
1343 #ifdef DO_PYTHON
1344     PYmode(Mode, OMshutdown, av[0]);
1345 #endif
1346     JustCleanup();
1347     syslog(L_NOTICE, "%s execv %s", LogName, CCargv[0]);
1348     status = sd_notify(false, "RELOADING=1");
1349     if (status < 0)
1350         warn("cannot notify systemd of reloading: %s", strerror(-status));
1351 
1352     /* Restore the systemd variables which were backed up in RCsetup()
1353        if socket activation was set. */
1354     s = getenv("INN_BACKUP_LISTEN_FDS");
1355     if (s != NULL) {
1356         if (setenv("LISTEN_FDS", s, true) != 0)
1357             die("setenv failed for LISTEN_FDS");
1358         if (unsetenv("INN_BACKUP_LISTEN_FDS") != 0)
1359             die("unsetenv failed for INN_BACKUP_LISTEN_FDS");
1360     }
1361     s = getenv("INN_BACKUP_LISTEN_PID");
1362     if (s != NULL) {
1363         if (setenv("LISTEN_PID", s, true) != 0)
1364             die("setenv failed for LISTEN_PID");
1365         if (unsetenv("INN_BACKUP_LISTEN_PID") != 0)
1366             die("unsetenv failed for INN_BACKUP_LISTEN_PID");
1367     }
1368 
1369     /* Clear the close-on-exec flag on the socket activation file descriptors.
1370        This is needed because we need to pass them to the new innd process
1371        and sd_listen_fds(), which was called in RCsetup(), set it on all
1372        passed file descriptors. */
1373     s = getenv("INN_SD_LISTEN_FDS_COUNT");
1374     if (s == NULL)
1375         count = 0;
1376     else
1377         count = atoi(s);
1378     for (i = SD_LISTEN_FDS_START; i < SD_LISTEN_FDS_START + count; i++)
1379         fdflag_close_exec(i, false);
1380 
1381     /* Close all fds to protect possible fd leaking across successive innds. */
1382     for (i = SD_LISTEN_FDS_START + count; i < 30; i++)
1383         close(i);
1384 
1385     execv(CCargv[0], CCargv);
1386     syslog(L_FATAL, "%s cant execv %s %m", LogName, CCargv[0]);
1387     _exit(1);
1388     /* NOTREACHED */
1389     return "1 Exit failed";
1390 }
1391 
1392 /*
1393 **  Reject remote readers.
1394 */
1395 static const char *
CCreject(char * av[])1396 CCreject(char *av[])
1397 {
1398     if (RejectReason)
1399 	return "1 Already rejecting";
1400     if (strlen(av[0]) > MAX_REASON_LEN)	/* MAX_REASON_LEN is as big as is safe. */
1401 	return CCbigreason;
1402     if (!is_valid_utf8(av[0]))
1403         return "1 Invalid UTF-8 reason";
1404     RejectReason = xstrdup(av[0]);
1405     CCsdnotify();
1406     return NULL;
1407 }
1408 
1409 
1410 /*
1411 **  Re-read all in-core data.
1412 */
1413 static const char *
CCreload(char * av[])1414 CCreload(char *av[])
1415 {
1416     const char *p;
1417     const char *error;
1418 
1419 #ifdef DO_PERL
1420     static char BADPERLRELOAD[] = "1 Failed to define filter_art" ;
1421     char *path;
1422 #endif
1423 
1424 #ifdef DO_PYTHON
1425     static char BADPYRELOAD[] = "1 Failed to reload filter_innd.py" ;
1426 #endif
1427 
1428     p = av[0];
1429     if (*p == '\0' || strcmp(p, "all") == 0) {
1430         /* Check the syntax of the newsfeeds file before reloading. */
1431         if ((error = CCcheckfile(NULL)) != NULL)
1432             return error;
1433 	SITEflushall(false);
1434         if (Mode == OMrunning)
1435 	    InndHisClose();
1436 	RCreadlist();
1437 	if (Mode == OMrunning)
1438 	    InndHisOpen();
1439 	ICDwrite();
1440 	ICDsetup(true);
1441 #ifdef DO_PERL
1442         path = concatpath(innconf->pathfilter, INN_PATH_PERL_FILTER_INND);
1443         PERLreadfilter(path, "filter_art") ;
1444         free(path);
1445 #endif
1446 #ifdef DO_PYTHON
1447 	syslog(L_NOTICE, "reloading pyfilter");
1448         if (PYreadfilter())
1449             syslog(L_NOTICE, "reloaded pyfilter OK");
1450 #endif
1451 	p = "all";
1452     }
1453     else if (strcmp(p, "active") == 0 || strcmp(p, "newsfeeds") == 0) {
1454         /* Check the syntax of the newsfeeds file before reloading. */
1455         if ((error = CCcheckfile(NULL)) != NULL)
1456             return error;
1457         SITEflushall(false);
1458 	ICDwrite();
1459 	ICDsetup(true);
1460     }
1461     else if (strcmp(p, "history") == 0) {
1462         if (Mode != OMrunning)
1463             return CCnotrunning;
1464 	InndHisClose();
1465 	InndHisOpen();
1466     }
1467     else if (strcmp(p, "incoming.conf") == 0) {
1468         RCreadlist();
1469     }
1470 #if 0 /* we should check almost all innconf parameter, but the code
1471          is still incomplete for innd, so just commented out */
1472     else if (strcmp(p, "inn.conf") == 0) {
1473         struct innconf *saved;
1474 
1475         saved = innconf;
1476         innconf = NULL;
1477         if (innconf_read(NULL))
1478             innconf_free(saved);
1479         else {
1480             innconf = saved;
1481             return "1 Reload of inn.conf failed";
1482         }
1483 	if (innconf->pathhost == NULL) {
1484 	    syslog(L_FATAL, "%s No pathhost set", LogName);
1485 	    exit(1);
1486 	}
1487 	free(Path.Data);
1488 	Path.Used = strlen(innconf->pathhost) + 1;
1489 	Path.Data = xmalloc(Path.Used + 1);
1490 	sprintf(Path.Data, "%s!", innconf->pathhost);
1491 	if (Pathalias.Used > 0)
1492 	    free(Pathalias.Data);
1493 	if (innconf->pathalias == NULL) {
1494 	    Pathalias.Used = 0;
1495 	    Pathalias.Data = NULL;
1496 	} else {
1497 	    Pathalias.Used = strlen(innconf->pathalias) + 1;
1498 	    Pathalias.Data = xmalloc(Pathalias.Used + 1);
1499 	    sprintf(Pathalias.Data, "%s!", innconf->pathalias);
1500 	}
1501         if (Pathcluster.Used > 0)
1502             free(Pathcluster.Data);
1503         if (innconf->pathcluster == NULL) {
1504             Pathcluster.Used = 0;
1505             Pathcluster.Data = NULL;
1506         } else {
1507             Pathcluster.Used = strlen(innconf->pathcluster) + 1;
1508             Pathcluster.Data = xmalloc(Pathcluster.Used + 1);
1509             sprintf(Pathcluster.Data, "%s!", innconf->pathcluster);
1510         }
1511     }
1512 #endif
1513 #ifdef DO_PERL
1514     else if (strcmp(p, "filter.perl") == 0) {
1515         path = concatpath(innconf->pathfilter, INN_PATH_PERL_FILTER_INND);
1516         if (!PERLreadfilter(path, "filter_art")) {
1517             free(path);
1518             return BADPERLRELOAD;
1519         }
1520         free(path);
1521     }
1522 #endif
1523 #ifdef DO_PYTHON
1524     else if (strcmp(p, "filter.python") == 0) {
1525 	if (!PYreadfilter())
1526 	    return BADPYRELOAD;
1527     }
1528 #endif
1529     else
1530 	return "1 Unknown reload type";
1531 
1532     syslog(L_NOTICE, "%s reload %s %s", LogName, p, av[1]);
1533     return NULL;
1534 }
1535 
1536 
1537 /*
1538 **  Renumber the active file.
1539 */
1540 static const char *
CCrenumber(char * av[])1541 CCrenumber(char *av[])
1542 {
1543     static char	CANTRENUMBER[] = "1 Failed (see syslog)";
1544     char	*p;
1545     NEWSGROUP	*ngp;
1546 
1547     if (Mode != OMrunning)
1548 	return CCnotrunning;
1549     if (ICDneedsetup)
1550 	return "1 Must first reload newsfeeds";
1551     p = av[0];
1552     if (*p) {
1553 	if ((ngp = NGfind(p)) == NULL)
1554 	    return CCnogroup;
1555 	if (!NGrenumber(ngp))
1556 	    return CANTRENUMBER;
1557     }
1558     else if (!ICDrenumberactive())
1559 	return CANTRENUMBER;
1560     return NULL;
1561 }
1562 
1563 
1564 /*
1565 **  Reserve a lock.
1566 */
1567 static const char *
CCreserve(char * av[])1568 CCreserve(char *av[])
1569 {
1570     char	*p;
1571 
1572     if (Mode != OMrunning)
1573 	return CCnotrunning;
1574     p = av[0];
1575     if (*p) {
1576 	/* Trying to make a reservation. */
1577 	if (Reservation)
1578 	    return "1 Already reserved";
1579 	if (strlen(p) > MAX_REASON_LEN) /* MAX_REASON_LEN is as big as is safe. */
1580 	    return CCbigreason;
1581         if (!is_valid_utf8(p))
1582             return "1 Invalid UTF-8 reason";
1583 	Reservation = xstrdup(p);
1584     }
1585     else {
1586 	/* Trying to remove a reservation. */
1587 	if (Reservation == NULL)
1588 	    return "1 Not reserved";
1589 	free(Reservation);
1590 	Reservation = NULL;
1591     }
1592     return NULL;
1593 }
1594 
1595 
1596 /*
1597 **  Remove a newsgroup.
1598 */
1599 static const char *
CCrmgroup(char * av[])1600 CCrmgroup(char *av[])
1601 {
1602     NEWSGROUP	*ngp;
1603 
1604     if ((ngp = NGfind(av[0])) == NULL)
1605 	return CCnogroup;
1606 
1607     if (Mode == OMthrottled && ThrottledbyIOError)
1608 	return "1 server throttled";
1609 
1610     /* Update the in-core data. */
1611     if (!ICDrmgroup(ngp))
1612 	return "1 Failed";
1613     syslog(L_NOTICE, "%s rmgroup %s", LogName, av[0]);
1614     return NULL;
1615 }
1616 
1617 
1618 /*
1619 **  Send a command line to an exploder.
1620 */
1621 static const char *
CCsend(char * av[])1622 CCsend(char *av[])
1623 {
1624     SITE		*sp;
1625 
1626     if ((sp = SITEfind(av[0])) == NULL)
1627 	return CCnosite;
1628     if (sp->Type != FTexploder)
1629 	return CCwrongtype;
1630     SITEwrite(sp, av[1]);
1631     return NULL;
1632 }
1633 
1634 
1635 /*
1636 **  Shut down the system.
1637 */
1638 static const char *
CCshutdown(char * av[])1639 CCshutdown(char *av[])
1640 {
1641 #ifdef DO_PERL
1642     PLmode(Mode, OMshutdown, av[0]);
1643 #endif
1644 #ifdef DO_PYTHON
1645     PYmode(Mode, OMshutdown, av[0]);
1646 #endif
1647     syslog(L_NOTICE, "%s shutdown %s", LogName, av[0]);
1648     CleanupAndExit(0, av[0]);
1649     /* NOTREACHED */
1650     return "1 Exit failed";
1651 }
1652 
1653 
1654 /*
1655 **  Send a signal to a site's feed.
1656 */
1657 static const char *
CCsignal(char * av[])1658 CCsignal(char *av[])
1659 {
1660     SITE	*sp;
1661     char	*p;
1662     int		s;
1663     int		oerrno;
1664 
1665     /* Parse the signal. */
1666     p = av[0];
1667     if (*p == '-')
1668 	p++;
1669     if (strcasecmp(p, "HUP") == 0)
1670 	s = SIGHUP;
1671     else if (strcasecmp(p, "INT") == 0)
1672 	s = SIGINT;
1673     else if (strcasecmp(p, "TERM") == 0)
1674 	s = SIGTERM;
1675     else if ((s = atoi(p)) <= 0)
1676 	return "1 Invalid signal";
1677 
1678     /* Parse the site. */
1679     p = av[1];
1680     if ((sp = SITEfind(p)) == NULL)
1681 	return CCnosite;
1682     if (sp->Type != FTchannel && sp->Type != FTexploder)
1683 	return CCwrongtype;
1684     if (sp->Process < 0)
1685 	return "1 Site has no process";
1686 
1687     /* Do it. */
1688     if (kill(sp->pid, s) < 0) {
1689 	oerrno = errno;
1690 	syslog(L_ERROR, "%s cant kill %ld %d site %s, %m", LogName,
1691 		(long) sp->pid, s, p);
1692         buffer_sprintf(&CCreply, "1 Can't signal process %ld: %s",
1693                        (long) sp->pid, strerror(oerrno));
1694 	return CCreply.data;
1695     }
1696 
1697     return NULL;
1698 }
1699 
1700 
1701 /*
1702 **  Enter throttled mode.
1703 */
1704 static const char *
CCthrottle(char * av[])1705 CCthrottle(char *av[])
1706 {
1707     char	*p;
1708 
1709     p = av[0];
1710     switch (Mode) {
1711     case OMpaused:
1712 	if (*p && strcmp(p, ModeReason) != 0)
1713 	    return "1 Already paused";
1714 	/* FALLTHROUGH */
1715     case OMrunning:
1716 	return CCblock(OMthrottled, p);
1717     case OMthrottled:
1718 	return "1 Already throttled";
1719     case OMshutdown:
1720         return "1 Shutting down";
1721     }
1722     return "1 unknown mode";
1723 }
1724 
1725 /*
1726 **  Turn on or off performance monitoring
1727 */
1728 static const char *
CCtimer(char * av[])1729 CCtimer(char *av[])
1730 {
1731     unsigned long    value;
1732     char                *p;
1733 
1734     if (strcmp(av[0], "off") == 0)
1735 	value = 0;
1736     else {
1737 	for (p = av[0]; *p; p++) {
1738 	    if (!isdigit((unsigned char) *p))
1739 		return "1 parameter should be a number or 'off'";
1740 	}
1741 	value = strtoul(av[0], NULL, 10);
1742     }
1743     innconf->timer = value;
1744     if (innconf->timer != 0)
1745         TMRinit(TMR_MAX);
1746     else
1747 	TMRinit(0);
1748     return NULL;
1749 }
1750 
1751 /*
1752 **  Log into filename some history stats
1753 */
1754 static const char *
CCstathist(char * av[])1755 CCstathist(char *av[])
1756 {
1757     if (strcmp(av[0], "off") == 0)
1758         HISlogclose();
1759     else
1760         HISlogto(av[0]);
1761     return NULL;
1762 }
1763 
1764 /*
1765 **  Turn innd status creation on or off
1766 */
1767 static const char *
CCstatus(char * av[])1768 CCstatus(char *av[])
1769 {
1770     unsigned long       value;
1771     char                *p;
1772 
1773     if (strcmp(av[0], "off") == 0)
1774 	value = 0;
1775     else {
1776 	for (p = av[0]; *p; p++) {
1777 	    if (!isdigit((unsigned char) *p))
1778 		return "1 parameter should be a number or 'off'";
1779 	}
1780 	value = strtoul(av[0], NULL, 10);
1781     }
1782     innconf->status = value;
1783     return NULL;
1784 }
1785 
1786 /*
1787 **  Add or remove tracing.
1788 */
1789 static const char *
CCtrace(char * av[])1790 CCtrace(char *av[])
1791 {
1792     char	*p;
1793     bool	Flag;
1794     const char *	word;
1795     CHANNEL	*cp;
1796 
1797     /* Parse the flag. */
1798     p = av[1];
1799     switch (p[0]) {
1800     default:			return "1 Bad trace flag";
1801     case 'y': case 'Y':		Flag = true;	word = "on";	break;
1802     case 'n': case 'N':		Flag = false;	word = "off";	break;
1803     }
1804 
1805     /* Parse what's being traced. */
1806     p = av[0];
1807     switch (*p) {
1808     default:
1809 	return "1 Bad trace item";
1810     case 'i': case 'I':
1811 	Tracing = Flag;
1812 	syslog(L_NOTICE, "%s trace innd %s", LogName, word);
1813 	break;
1814     case 'n': case 'N':
1815 	NNRPTracing = Flag;
1816 	syslog(L_NOTICE, "%s trace nnrpd %s", LogName, word);
1817 	break;
1818     case '0': case '1': case '2': case '3': case '4':
1819     case '5': case '6': case '7': case '8': case '9':
1820 	if ((cp = CHANfromdescriptor(atoi(p))) == NULL)
1821 	    return CCnochannel;
1822 	CHANtracing(cp, Flag);
1823 	break;
1824     }
1825     return NULL;
1826 }
1827 
1828 
1829 
1830 /*
1831 **  Split up the text into fields and stuff them in argv.  Return the
1832 **  number of elements or -1 on error.
1833 */
1834 static int
CCargsplit(char * p,char * end,char ** argv,int size)1835 CCargsplit(char *p, char *end, char **argv, int size)
1836 {
1837     char		**save;
1838 
1839     for (save = argv, *argv++ = p, size--; p < end; p++)
1840 	if (*p == SC_SEP) {
1841 	    if (--size <= 0)
1842 		return -1;
1843 	    *p = '\0';
1844 	    *argv++ = p + 1;
1845 	}
1846     *argv = NULL;
1847     return argv - save;
1848 }
1849 
1850 
1851 /*
1852 **  Read function.  Read and process the message.
1853 */
1854 static void
CCreader(CHANNEL * cp)1855 CCreader(CHANNEL *cp)
1856 {
1857     CCDISPATCH		*dp;
1858     const char *	p;
1859     ICC_MSGLENTYPE	bufflen;
1860     ICC_PROTOCOLTYPE	protocol ;
1861 #if	defined(HAVE_UNIX_DOMAIN_SOCKETS)
1862     static char         TOOLONG[] = "0 Reply too long for server to send";
1863     struct sockaddr_un  client;
1864 #else
1865     int                 written;
1866 #endif	/* defined(HAVE_UNIX_DOMAIN_SOCKETS) */
1867     int			i;
1868     char                buff[BIG_BUFFER + 2];
1869     char		*argv[SC_MAXFIELDS + 2];
1870     int			argc;
1871     int			len;
1872     char		*tbuff ;
1873     const char *start;
1874     char *copy;
1875     size_t offset;
1876 
1877     if (cp != CCchan) {
1878 	syslog(L_ERROR, "%s internal CCreader wrong channel 0x%p not 0x%p",
1879 	    LogName, (void *)cp, (void *)CCchan);
1880 	return;
1881     }
1882 
1883 #if defined (HAVE_UNIX_DOMAIN_SOCKETS)
1884 
1885     i = RECVorREAD(CCchan->fd, buff, BIG_BUFFER) ;
1886     if (i < 0) {
1887 	syslog(L_ERROR, "%s cant recv CCreader %m", LogName);
1888 	return;
1889     } else if (i == 0) {
1890 	syslog(L_ERROR, "%s cant recv CCreader empty", LogName);
1891 	return;
1892     } else if (i < (int)HEADER_SIZE) {
1893 	syslog(L_ERROR, "%s cant recv CCreader header-length %m", LogName);
1894 	return;
1895     }
1896 
1897     memcpy (&protocol,buff,sizeof (protocol)) ;
1898     memcpy (&bufflen,buff + sizeof (protocol),sizeof (bufflen)) ;
1899     bufflen = ntohs (bufflen);
1900 
1901     if (i != bufflen) {
1902 	syslog(L_ERROR, "%s cant recv CCreader short-read %m", LogName);
1903 	return;
1904     }
1905 
1906     bufflen -= HEADER_SIZE;
1907     memmove(buff, buff + HEADER_SIZE, bufflen);
1908     buff[bufflen] = '\0';
1909 
1910     if (protocol != ICC_PROTOCOL_1) {
1911         syslog(L_ERROR, "%s CCreader protocol mismatch", LogName) ;
1912         return ;
1913     }
1914 
1915 #else  /* defined (HAVE_UNIX_DOMAIN_SOCKETS) */
1916 
1917     i = RECVorREAD(CCchan->fd, buff, HEADER_SIZE) ;
1918     if (i < 0) {
1919 	syslog(L_ERROR, "%s cant read CCreader header %m", LogName);
1920 	return;
1921     } else if (i == 0) {
1922 	syslog(L_ERROR, "%s cant read CCreader header empty", LogName);
1923 	return;
1924     } else if (i != HEADER_SIZE) {
1925 	syslog(L_ERROR, "%s cant read CCreader header-length %m", LogName);
1926 	return;
1927     }
1928 
1929     memcpy (&protocol,buff,sizeof (protocol)) ;
1930     memcpy (&bufflen,buff + sizeof (protocol),sizeof (bufflen)) ;
1931     bufflen = ntohs (bufflen);
1932     if (bufflen < HEADER_SIZE || bufflen > BIG_BUFFER) {
1933 	syslog(L_ERROR, "%s cant read CCreader bad length", LogName);
1934 	return;
1935     }
1936     bufflen -= HEADER_SIZE ;
1937 
1938     i = RECVorREAD(CCchan->fd, buff, bufflen) ;
1939 
1940     if (i < 0) {
1941 	syslog(L_ERROR, "%s cant read CCreader buffer %m", LogName);
1942 	return;
1943     } else if (i == 0) {
1944 	syslog(L_ERROR, "%s cant read CCreader buffer empty", LogName);
1945 	return;
1946     } else if (i != bufflen) {
1947 	syslog(L_ERROR, "%s cant read CCreader buffer-length %m", LogName);
1948 	return;
1949     }
1950 
1951     buff[i] = '\0';
1952 
1953     if (protocol != ICC_PROTOCOL_1) {
1954         syslog(L_ERROR, "%s CCreader protocol mismatch", LogName) ;
1955         return ;
1956     }
1957 
1958 #endif /* defined (HAVE_UNIX_DOMAIN_SOCKETS) */
1959 
1960     /* Copy to a printable buffer, and log.  We skip the first
1961        SC_SEP-delimited field.  Note that the protocol allows for nuls in the
1962        message, which we'll replace with ? for logging. */
1963     copy = xmalloc(bufflen + 1);
1964     memcpy(copy, buff, bufflen);
1965     copy[bufflen] = '\0';
1966     for (offset = 0, start = NULL; offset < (size_t) bufflen; offset++)
1967         if (copy[offset] == SC_SEP) {
1968             copy[offset] = ':';
1969             if (start == NULL)
1970                 start = copy + offset + 1;
1971         } else if (copy[offset] == '\0') {
1972             copy[offset] = '?';
1973         }
1974     notice("ctlinnd command %s", start != NULL ? start : copy);
1975     free(copy);
1976 
1977     /* Split up the fields, get the command letter. */
1978     if ((argc = CCargsplit(buff, &buff[bufflen], argv, ARRAY_SIZE(argv))) < 2
1979      || argc == ARRAY_SIZE(argv)) {
1980 	syslog(L_ERROR, "%s bad_fields CCreader", LogName);
1981 	return;
1982     }
1983     p = argv[1];
1984     i = *p;
1985 
1986     /* Dispatch to the command function. */
1987     for (argc -= 2, dp = CCcommands; dp < ARRAY_END(CCcommands); dp++)
1988 	if (i == dp->Name) {
1989 	    if (argc != dp->argc)
1990 		p = "1 Wrong number of parameters";
1991 	    else
1992 		p = (*dp->Function)(&argv[2]);
1993 	    break;
1994 	}
1995     if (dp == ARRAY_END(CCcommands)) {
1996 	syslog(L_NOTICE, "%s bad_message %c", LogName, i);
1997 	p = "1 Bad command";
1998     }
1999     else if (p == NULL)
2000 	p = "0 Ok";
2001 
2002     /* Build the reply address and send the reply. */
2003     len = strlen(p) + HEADER_SIZE ;
2004     tbuff = xmalloc(len + 1);
2005 
2006     protocol = ICC_PROTOCOL_1 ;
2007     memcpy (tbuff,&protocol,sizeof (protocol)) ;
2008     tbuff += sizeof (protocol) ;
2009 
2010     bufflen = htons (len) ;
2011     memcpy (tbuff,&bufflen,sizeof (bufflen)) ;
2012     tbuff += sizeof (bufflen) ;
2013 
2014     strlcpy(tbuff, p, len + 1 - sizeof(protocol) - sizeof(bufflen));
2015     tbuff -= HEADER_SIZE ;
2016 
2017 #if	defined(HAVE_UNIX_DOMAIN_SOCKETS)
2018     memset(&client, 0, sizeof client);
2019     client.sun_family = AF_UNIX;
2020     strlcpy(client.sun_path, argv[0], sizeof(client.sun_path));
2021     if (sendto(CCwriter, tbuff, len, 0,
2022 	    (struct sockaddr *) &client, SUN_LEN(&client)) < 0) {
2023 	i = errno;
2024 	syslog(i == ENOENT ? L_NOTICE : L_ERROR,
2025 	    "%s cant sendto CCreader bytes %d %m", LogName, len);
2026 	if (i == EMSGSIZE)
2027 	    sendto(CCwriter, TOOLONG, strlen(TOOLONG), 0,
2028 		(struct sockaddr *) &client, SUN_LEN(&client));
2029     }
2030 #else
2031     if ((i = open(argv[0], O_WRONLY | O_NDELAY)) < 0)
2032 	syslog(L_ERROR, "%s cant open %s %m", LogName, argv[0]);
2033     else {
2034 	if ((written = write(i, tbuff, len)) != len) {
2035 	    if (written < 0)
2036 		syslog(L_ERROR, "%s cant write %s %m", LogName, argv[0]);
2037             else
2038 		syslog(L_ERROR, "%s cant write %s", LogName, argv[0]);
2039         }
2040 	if (close(i) < 0)
2041 	    syslog(L_ERROR, "%s cant close %s %m", LogName, argv[0]);
2042     }
2043 #endif	/* defined(HAVE_UNIX_DOMAIN_SOCKETS) */
2044     free (tbuff) ;
2045 }
2046 
2047 
2048 /*
2049 **  Called when a write-in-progress is done on the channel.  Shouldn't happen.
2050 */
2051 static void
CCwritedone(CHANNEL * unused UNUSED)2052 CCwritedone(CHANNEL *unused UNUSED)
2053 {
2054     syslog(L_ERROR, "%s internal CCwritedone", LogName);
2055 }
2056 
2057 
2058 /*
2059 **  Create the channel.
2060 */
2061 void
CCsetup(void)2062 CCsetup(void)
2063 {
2064     int			i;
2065 #if	defined(HAVE_UNIX_DOMAIN_SOCKETS)
2066     struct sockaddr_un	server;
2067     int size = 65535;
2068 #endif	/* defined(HAVE_UNIX_DOMAIN_SOCKETS) */
2069 
2070     if (CCpath == NULL)
2071 	CCpath = concatpath(innconf->pathrun, INN_PATH_NEWSCONTROL);
2072     /* Remove old detritus. */
2073     if (unlink(CCpath) < 0 && errno != ENOENT) {
2074 	syslog(L_FATAL, "%s cant unlink %s %m", LogName, CCpath);
2075 	exit(1);
2076     }
2077 
2078 #if	defined(HAVE_UNIX_DOMAIN_SOCKETS)
2079     /* Create a socket and name it. */
2080     if ((i = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
2081 	syslog(L_FATAL, "%s cant socket %s %m", LogName, CCpath);
2082 	exit(1);
2083     }
2084     memset(&server, 0, sizeof server);
2085     server.sun_family = AF_UNIX;
2086     strlcpy(server.sun_path, CCpath, sizeof(server.sun_path));
2087     if (bind(i, (struct sockaddr *) &server, SUN_LEN(&server)) < 0) {
2088 	syslog(L_FATAL, "%s cant bind %s %m", LogName, CCpath);
2089 	exit(1);
2090     }
2091 
2092     /* Create an unbound socket to reply on. */
2093     if ((CCwriter = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
2094 	syslog(L_FATAL, "%s cant socket unbound %m", LogName);
2095 	exit(1);
2096     }
2097 
2098     /* Increase the buffer size for the Unix domain socket */
2099     if (setsockopt(CCwriter, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) < 0)
2100 	syslog(L_ERROR, "%s cant setsockopt %m", LogName);
2101 #else
2102     /* Create a named pipe and open it. */
2103     if (mkfifo(CCpath, 0666) < 0) {
2104 	syslog(L_FATAL, "%s cant mkfifo %s %m", LogName, CCpath);
2105 	exit(1);
2106     }
2107     if ((i = open(CCpath, O_RDWR)) < 0) {
2108 	syslog(L_FATAL, "%s cant open %s %m", LogName, CCpath);
2109 	exit(1);
2110     }
2111 #endif	/* defined(HAVE_UNIX_DOMAIN_SOCKETS) */
2112 
2113     CCchan = CHANcreate(i, CTcontrol, CSwaiting, CCreader, CCwritedone);
2114     syslog(L_NOTICE, "%s ccsetup %s", LogName, CHANname(CCchan));
2115     RCHANadd(CCchan);
2116 
2117     buffer_resize(&CCreply, SMBUF);
2118 
2119     /*
2120      *  Catch SIGUSR1 so that we can recreate the control channel when
2121      *  needed (i.e. something has deleted our named socket.
2122      */
2123 #if     defined(SIGUSR1)
2124     xsignal(SIGUSR1, CCresetup);
2125 #endif  /* defined(SIGUSR1) */
2126 
2127     CCsdnotify();
2128 }
2129 
2130 
2131 /*
2132 **  Cleanly shut down the channel.
2133 */
2134 void
CCclose(void)2135 CCclose(void)
2136 {
2137     CHANclose(CCchan, CHANname(CCchan));
2138     CCchan = NULL;
2139     if (unlink(CCpath) < 0)
2140 	syslog(L_ERROR, "%s cant unlink %s %m", LogName, CCpath);
2141     free(CCpath);
2142     CCpath = NULL;
2143     free(CCreply.data);
2144     CCreply.data = NULL;
2145     CCreply.size = 0;
2146     CCreply.used = 0;
2147     CCreply.left = 0;
2148 #if	defined(HAVE_UNIX_DOMAIN_SOCKETS)
2149     if (close(CCwriter) < 0)
2150 	syslog(L_ERROR, "%s cant close unbound %m", LogName);
2151 #endif	/* defined(HAVE_UNIX_DOMAIN_SOCKETS) */
2152 }
2153 
2154 
2155 #ifdef HAVE_SIGACTION
2156 #define NO_SIGACTION_UNUSED UNUSED
2157 #else
2158 #define NO_SIGACTION_UNUSED
2159 #endif
2160 
2161 /*
2162 **  Restablish the control channel.
2163 */
2164 static void
CCresetup(int s NO_SIGACTION_UNUSED)2165 CCresetup(int s NO_SIGACTION_UNUSED)
2166 {
2167 #ifndef HAVE_SIGACTION
2168     xsignal(s, CCresetup);
2169 #endif
2170     CCclose();
2171     CCsetup();
2172 }
2173