chiark / gitweb /
Rerun autoconf2.13 on etch and consequently refresh configure-hostname patch
[inn-innduct.git] / innd / rc.c
1 /*  $Id: rc.c 7751 2008-04-06 14:35:40Z iulius $
2 **
3 **  Routines for the remote connect channel.  Create an Internet stream
4 **  socket that processes connect to.  If the incoming site is not one of
5 **  our feeds, then we optionally pass the connection off to the standard
6 **  NNTP daemon.
7 */
8 #include "config.h"
9 #include "clibrary.h"
10 #include "portable/socket.h"
11 #include <errno.h>
12 #include <netdb.h>
13
14 #include "inn/innconf.h"
15 #include "inn/vector.h"
16 #include "innd.h"
17
18 #define TEST_CONFIG(a, b) \
19     { \
20         b = ((peer_params.Keysetbit & (1 << a)) != 0) ? true : false; \
21     }
22
23 #define SET_CONFIG(a) \
24     { \
25         peer_params.Keysetbit |= (1 << a); \
26     }
27
28 /*
29 **  A remote host has an address and a password.
30 */
31 typedef struct _REMOTEHOST {
32     char        *Label;         /* Peer label */
33     char        *Name;          /* Hostname */
34     struct sockaddr_storage Address;     /* List of ip adresses */
35     char        *Password;      /* Optional password */
36     char        *Identd;        /* Optional identd */
37     bool        Streaming;      /* Streaming allowed ? */
38     bool        Skip;           /* Skip this peer ? */
39     bool        NoResendId;     /* Don't send RESEND responses ? */
40     bool        Nolist;         /* no list command allowed */
41     int         MaxCnx;         /* Max connections (per peer) */
42     char        **Patterns;     /* List of groups allowed */
43     char        *Pattern;       /* List of groups allowed (string) */
44     char        *Email;         /* Email(s) of contact */
45     char        *Comment;       /* Commentary [max size = MAXBUFF] */
46     int         HoldTime;       /* Hold time before disconnect over MaxCnx */
47     int         Keysetbit;      /* Bit to check duplicated key */
48 } REMOTEHOST;
49
50 typedef struct _REMOTEHOST_DATA {
51     int         key;            /* Key (as defined in the _Keywords enum) */
52     int         type;           /* Type of the value (see _Type enum) */
53     char        *value;         /* Value */
54 } REMOTEHOST_DATA;
55
56 typedef struct _REMOTETABLE {
57     struct sockaddr_storage Address;
58     time_t         Expires;
59 } REMOTETABLE;
60
61 static char             *RCslaveflag;
62 static char             *RCnnrpd = NULL;
63 static char             *RCnntpd = NULL;
64 static CHANNEL          **RCchan;
65 static int              chanlimit;
66 static REMOTEHOST_DATA  *RCpeerlistfile;
67 static REMOTEHOST       *RCpeerlist;
68 static int              RCnpeerlist;
69 static char             RCbuff[BIG_BUFFER];
70
71 #define PEER            "peer"
72 #define GROUP           "group"
73 #define HOSTNAME        "hostname:"
74 #define STREAMING       "streaming:"
75 #define MAX_CONN        "max-connections:"
76 #define PASSWORD        "password:"
77 #define IDENTD          "identd:"
78 #define PATTERNS        "patterns:"
79 #define EMAIL           "email:"
80 #define COMMENT         "comment:"
81 #define SKIP            "skip:"
82 #define NORESENDID      "noresendid:"
83 #define HOLD_TIME       "hold-time:"
84 #define NOLIST          "nolist:"
85
86 typedef enum {K_END, K_BEGIN_PEER, K_BEGIN_GROUP, K_END_PEER, K_END_GROUP,
87               K_STREAM, K_HOSTNAME, K_MAX_CONN, K_PASSWORD, K_IDENTD,
88               K_EMAIL, K_PATTERNS, K_COMMENT, K_SKIP, K_NORESENDID,
89               K_HOLD_TIME, K_NOLIST
90              } _Keywords;
91
92 typedef enum {T_STRING, T_BOOLEAN, T_INTEGER} _Types;
93
94 #define GROUP_NAME      "%s can't get group name in %s line %d"
95 #define PEER_IN_PEER    "%s peer can't contain peer in %s line %d"
96 #define PEER_NAME       "%s can't get peer name in %s line %d"
97 #define LEFT_BRACE      "%s '{' expected in %s line %d"
98 #define RIGHT_BRACE     "%s '}' unexpected line %d in %s"
99 #define INCOMPLETE_PEER "%s incomplete peer (%s) in %s line %d"
100 #define INCOMPLETE_GROUP "%s incomplete group (%s) in %s line %d"
101 #define MUST_BE_BOOL    "%s Must be 'true' or 'false' in %s line %d"
102 #define MUST_BE_INT     "%s Must be an integer value in %s line %d"
103 #define HOST_NEEDED     "%s 'hostname' needed in %s line %d"
104 #define DUPLICATE_KEY   "%s duplicate key in %s line %d"
105
106 /*
107 ** Stuff needed for limiting incoming connects.
108 */
109 static char             RCterm[] = "\r\n";
110 static REMOTETABLE      remotetable[REMOTETABLESIZE];
111 static int              remotecount;
112 static int              remotefirst;
113
114 /*
115  * Check that the client has the right identd. Return true if is the
116  * case, false, if not.
117  */
118 static bool
119 GoodIdent(int fd, char *identd)
120 {
121 #define PORT_IDENTD 113
122     char IDENTuser[80];
123     struct sockaddr_storage ss_local;
124     struct sockaddr_storage ss_distant;
125     struct sockaddr *s_local = (struct sockaddr *)&ss_local;
126     struct sockaddr *s_distant = (struct sockaddr *)&ss_distant;
127     int ident_fd;
128     socklen_t len;
129     int port1,port2;
130     ssize_t lu;
131     char buf[80], *buf2;
132
133     if(identd[0] == '\0') {
134          return true;
135     }
136     
137     len = sizeof( ss_local );
138     if ((getsockname(fd,s_local,&len)) < 0) {
139         syslog(L_ERROR, "can't do getsockname for identd");
140         return false;
141     }
142     len = sizeof( ss_distant );
143     if ((getpeername(fd,s_distant,&len)) < 0) {
144         syslog(L_ERROR, "can't do getsockname for identd");
145         return false;
146     }
147 #ifdef HAVE_INET6
148     if( s_local->sa_family == AF_INET6 )
149     {
150         struct sockaddr_in6 *s_l6 = (struct sockaddr_in6 *)s_local;
151         struct sockaddr_in6 *s_d6 = (struct sockaddr_in6 *)s_distant;
152
153         port1=ntohs(s_l6->sin6_port);
154         port2=ntohs(s_d6->sin6_port);
155         s_l6->sin6_port = 0;
156         s_d6->sin6_port = htons( PORT_IDENTD );
157         ident_fd=socket(PF_INET6, SOCK_STREAM, 0);
158     } else
159 #endif
160     if( s_local->sa_family == AF_INET )
161     {
162         struct sockaddr_in *s_l = (struct sockaddr_in *)s_local;
163         struct sockaddr_in *s_d = (struct sockaddr_in *)s_distant;
164
165         port1=ntohs(s_l->sin_port);
166         port2=ntohs(s_d->sin_port);
167         s_l->sin_port = 0;
168         s_d->sin_port = htons( PORT_IDENTD );
169         ident_fd=socket(PF_INET, SOCK_STREAM, 0);
170     } else
171     {
172         syslog(L_ERROR, "Bad address family: %d\n", s_local->sa_family );
173         return false;
174     }
175     if (ident_fd < 0) {
176         syslog(L_ERROR, "can't open socket for identd (%m)");
177         return false;
178     }
179     if (bind(ident_fd,s_local,SA_LEN(s_local)) < 0) {
180         syslog(L_ERROR, "can't bind socket for identd (%m)");
181         close(ident_fd);
182         return false;
183     }
184     if (connect(ident_fd,s_distant,SA_LEN(s_distant)) < 0) {
185         syslog(L_ERROR, "can't connect to identd (%m)");
186         close(ident_fd);
187         return false;
188     }
189
190     snprintf(buf,sizeof(buf),"%d,%d\r\n",port2, port1);
191     write(ident_fd,buf, strlen(buf));
192     memset( buf, 0, 80 );
193     lu=read(ident_fd, buf, 79); /* pas encore parfait ("not yet perfect"?) */
194     if (lu<0)
195     {
196         syslog(L_ERROR, "error reading from ident server: %m" );
197         close( ident_fd );
198         return false;
199     }
200     buf[lu]='\0';
201     if ((lu>0) && (strstr(buf,"ERROR")==NULL)
202                     && ((buf2=strrchr(buf,':'))!=NULL)) 
203     {
204         buf2++;
205         while(*buf2 == ' ') buf2++;
206         strlcpy(IDENTuser, buf2, sizeof(IDENTuser));
207         buf2=strchr(IDENTuser,'\r');
208         if (!buf2) buf2=strchr(IDENTuser,'\n');
209         if (buf2) *buf2='\0';
210     } else
211         strlcpy(IDENTuser, "UNKNOWN", sizeof(IDENTuser));
212     close(ident_fd);
213
214     return strcmp(identd, IDENTuser) == 0;
215 }
216
217 /*
218  * Split text into comma-separated fields.  Return an allocated
219  * NULL-terminated array of the fields within the modified argument that
220  * the caller is expected to save or free.  We don't use strchr() since
221  * the text is expected to be either relatively short or "comma-dense."
222  * (This function is different from CommaSplit because spaces are allowed
223  * and removed here)
224  */
225
226 static char **
227 RCCommaSplit(char *text)
228 {
229     int         i;
230     char        *p;
231     char        *q;
232     char        *r;
233     char        **av;
234     char        **save;
235  
236     /* How much space do we need? */
237     for (i = 2, p = text, q = r = xstrdup(text); *p; p++) {
238         if (*p != ' ' && *p != '\t' && *p != '\n')
239             *q++ = *p;
240         if (*p == ',')
241             i++;
242     }
243     *q = '\0';
244     free (text);
245     for (text = r, av = save = xmalloc(i * sizeof(char *)), *av++ = p = text; *p; )
246         if (*p == ',') {
247             *p++ = '\0';
248             *av++ = p;
249         }
250         else
251             p++;
252     *av = NULL;
253     return save;
254 }
255
256  /*
257   * Routine to disable IP-level socket options. This code was taken from 4.4BSD
258   * rlogind source, but all mistakes in it are my fault.
259   *
260   * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
261   *
262   * 21-Jan-1997 smd
263   *     Code copied again, and modified for INN, all new mistakes are mine.
264   * 
265   */
266
267 /* fix_options - get rid of IP-level socket options */
268 #ifndef IP_OPTIONS
269 #define IP_OPTIONS 1
270 #endif
271
272 static int
273 RCfix_options(int fd, struct sockaddr_storage *remote)
274 {
275 #if IP_OPTIONS
276     unsigned char optbuf[BUFSIZ / 3], *cp;
277     char    lbuf[BUFSIZ], *lp;
278     socklen_t optsize = sizeof(optbuf);
279     int     ipproto;
280     struct protoent *ip;
281
282     switch (remote->ss_family) {
283     case AF_INET:
284         if ((ip = getprotobyname("ip")) != 0)
285             ipproto = ip->p_proto;
286         else
287             ipproto = IPPROTO_IP;
288         break;
289 #ifdef HAVE_INET6
290     case AF_INET6:
291         if ((ip = getprotobyname("ipv6")) != 0)
292             ipproto = ip->p_proto;
293         else
294             ipproto = IPPROTO_IPV6;
295         break;
296 #endif
297     default:
298         syslog(LOG_ERR, "unknown address family: %d", remote->ss_family);
299         return -1;
300     }
301
302     if (getsockopt(fd, ipproto, IP_OPTIONS, (char *) optbuf, &optsize) == 0
303         && optsize != 0) {
304         lp = lbuf;
305         for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3)
306             sprintf(lp, " %2.2x", *cp);
307         syslog(LOG_NOTICE,
308                "connect from %s with IP options (ignored):%s",
309                sprint_sockaddr((struct sockaddr *)remote), lbuf);
310         if (setsockopt(fd, ipproto, IP_OPTIONS, (char *) 0, optsize) != 0) {
311             syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m");
312             return -1;
313         }
314     }
315 #endif
316     return 0;
317 }
318
319 static bool
320 RCaddressmatch(const struct sockaddr_storage *cp, const struct sockaddr_storage *rp)
321 {
322 #ifdef HAVE_INET6
323     struct sockaddr_in  *sin_cp, *sin_rp;
324     struct sockaddr_in6 *sin6_cp, *sin6_rp;
325
326     if (cp->ss_family == AF_INET6 && rp->ss_family == AF_INET) {
327         sin6_cp = (struct sockaddr_in6 *)cp;
328         sin_rp = (struct sockaddr_in *)rp;
329         if (IN6_IS_ADDR_V4MAPPED(&sin6_cp->sin6_addr) &&
330                 memcmp(&sin6_cp->sin6_addr.s6_addr[12],
331                     &sin_rp->sin_addr.s_addr, sizeof(struct in_addr)) == 0)
332             return true;
333     } else if (cp->ss_family == AF_INET && rp->ss_family == AF_INET6) {
334         sin_cp = (struct sockaddr_in *)cp;
335         sin6_rp = (struct sockaddr_in6 *)rp;
336         if (IN6_IS_ADDR_V4MAPPED(&sin6_rp->sin6_addr) &&
337                 memcmp(&sin6_rp->sin6_addr.s6_addr[12],
338                     &sin_cp->sin_addr.s_addr, sizeof(struct in_addr)) == 0)
339             return true;
340     } else if (cp->ss_family == AF_INET6 && rp->ss_family == AF_INET6) {
341 #ifdef HAVE_BROKEN_IN6_ARE_ADDR_EQUAL
342         if (!memcmp(&((struct sockaddr_in6 *)cp)->sin6_addr,
343                     &((struct sockaddr_in6 *)rp)->sin6_addr,
344                     sizeof(struct in6_addr)))
345 #else
346         if (IN6_ARE_ADDR_EQUAL( &((struct sockaddr_in6 *)cp)->sin6_addr,
347                                 &((struct sockaddr_in6 *)rp)->sin6_addr))
348 #endif
349             return true;
350     } else
351 #endif /* INET6 */
352         if (((struct sockaddr_in *)cp)->sin_addr.s_addr ==
353              ((struct sockaddr_in *)rp)->sin_addr.s_addr)
354             return true;
355
356     return false;
357 }
358
359 /*
360 **  See if the site properly entered the password.
361 */
362 bool
363 RCauthorized(CHANNEL *cp, char *pass)
364 {
365     REMOTEHOST  *rp;
366     int         i;
367
368     for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++)
369         if (RCaddressmatch(&cp->Address, &rp->Address)) {
370             if (rp->Password[0] == '\0' || strcmp(pass, rp->Password) == 0)
371                 return true;
372             syslog(L_ERROR, "%s (%s) bad_auth", rp->Label,
373                    sprint_sockaddr((struct sockaddr *)&cp->Address));
374             return false;
375         }
376
377     if (!AnyIncoming)
378         /* Not found in our table; this can't happen. */
379         syslog(L_ERROR, "%s not_found", sprint_sockaddr((struct sockaddr *)&cp->Address));
380
381     /* Anonymous hosts should not authenticate. */
382     return false;
383 }
384
385 /*
386 **  See if a host is limited or not.
387 */
388 bool
389 RCnolimit(CHANNEL *cp)
390 {
391     REMOTEHOST  *rp;
392     int         i;
393
394     for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++)
395         if (RCaddressmatch(&cp->Address, &rp->Address))
396             return !rp->MaxCnx;
397
398     /* Not found in our table; this can't happen. */
399     return false;
400 }
401
402 /*
403 **  Return the limit (max number of connections) for a host.
404 */
405 int
406 RClimit(CHANNEL *cp)
407 {
408     REMOTEHOST  *rp;
409     int         i;
410
411     for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++)
412         if (RCaddressmatch(&cp->Address, &rp->Address))
413             return rp->MaxCnx;
414     /* Not found in our table; this can't happen. */
415     return RemoteLimit;
416 }
417
418
419 /*
420 **  Called when input is ready to read.  Shouldn't happen.
421 */
422 static void
423 RCrejectreader(CHANNEL *cp)
424 {
425     syslog(L_ERROR, "%s internal RCrejectreader (%s)", LogName,
426            sprint_sockaddr((struct sockaddr *)&cp->Address));
427 }
428
429
430 /*
431 **  Write-done function for rejects.
432 */
433 static void
434 RCrejectwritedone(CHANNEL *cp)
435 {
436     switch (cp->State) {
437     default:
438         syslog(L_ERROR, "%s internal RCrejectwritedone state %d",
439             CHANname(cp), cp->State);
440         break;
441     case CSwritegoodbye:
442         CHANclose(cp, CHANname(cp));
443         break;
444     }
445 }
446
447
448 /*
449 **  Hand off a descriptor to NNRPD.
450 */
451 void
452 RChandoff(int fd, HANDOFF h)
453 {
454     const char **argv;
455     char buff[SMBUF];
456     int i;
457     unsigned int j;
458     struct vector *flags;
459     
460     flags = vector_split_space(innconf->nnrpdflags, NULL);
461     argv  = xmalloc( (flags->count + 6) * sizeof(char*) );
462
463     if (RCnnrpd == NULL)
464         RCnnrpd = concatpath(innconf->pathbin, "nnrpd");
465     if (RCnntpd == NULL)
466         RCnntpd = concatpath(innconf->pathbin, "nnrpd");
467 #if     defined(SOL_SOCKET) && defined(SO_KEEPALIVE)
468     /* Set KEEPALIVE to catch broken socket connections. */
469     i = 1;
470     if (setsockopt(fd, SOL_SOCKET,  SO_KEEPALIVE, (char *)&i, sizeof i) < 0)
471         syslog(L_ERROR, "fd %d cant setsockopt(KEEPALIVE) %m", fd);
472 #endif /* defined(SOL_SOCKET) && defined(SO_KEEPALIVE) */
473
474     if (nonblocking(fd, false) < 0)
475         syslog(L_ERROR, "%s cant nonblock %d in RChandoff %m", LogName, fd);
476     switch (h) {
477     default:
478         syslog(L_ERROR, "%s internal RChandoff %d type %d", LogName, fd, h);
479         /* FALLTHROUGH */
480     case HOnnrpd:       argv[0] = RCnnrpd;      break;
481     case HOnntpd:       argv[0] = RCnntpd;      break;
482     }
483     argv[1] = "-s                                                ";
484     i = 2;
485     if (NNRPReason) {
486         snprintf(buff, sizeof(buff), "-r%s", NNRPReason);
487         argv[i++] = buff;
488     }
489     if (NNRPTracing)
490         argv[i++] = "-t";
491     if (RCslaveflag)
492         argv[i++] = RCslaveflag;
493
494     for(j = 0; j < flags->count; j++) {
495         argv[i++] = flags->strings[j];
496     }
497     argv[i] = NULL;
498
499     /* Call NNRP; don't send back a QUIT message if Spawn fails since  
500      * that's a major error we want to find out about quickly. */
501     (void)Spawn(innconf->nicekids, fd, fd, fd, (char * const *)argv);
502     vector_free(flags);
503     free(argv);
504 }
505
506
507 /*
508 **  Read function.  Accept the connection and either create an NNTP channel
509 **  or spawn an nnrpd to handle it.
510 */
511 static void
512 RCreader(CHANNEL *cp)
513 {
514     int                 fd;
515     struct sockaddr_storage     remote;
516     socklen_t           size;
517     int                 i;
518     REMOTEHOST          *rp;
519     CHANNEL             *new;
520     char                *name;
521     long                reject_val = 0;
522     const char          *reject_message;
523     int                 count;
524     int                 found;
525     time_t              now;
526     CHANNEL             tempchan;
527     char                buff[SMBUF];
528
529     for (i = 0 ; i < chanlimit ; i++) {
530         if (RCchan[i] == cp) {
531             break;
532         }
533     }
534     if (i == chanlimit) {
535         syslog(L_ERROR, "%s internal RCreader wrong channel 0x%p",
536                 LogName, (void *)cp);
537         return;
538     }
539
540     /* Get the connection. */
541     size = sizeof remote;
542     if ((fd = accept(cp->fd, (struct sockaddr *)&remote, &size)) < 0) {
543         if (errno != EWOULDBLOCK && errno != EAGAIN)
544             syslog(L_ERROR, "%s cant accept RCreader %m", LogName);
545         return;
546     }
547
548     /*
549     ** Clear any IP_OPTIONS, including source routing, on the socket
550     */
551     /* FIXME RCfix_options breaks IPv6 sockets, at least on Linux -lutchann */
552 #ifndef HAVE_INET6
553     if (RCfix_options(fd, &remote) != 0) {
554         /* shouldn't happen, but we're bit paranoid at this point */
555         if (close(fd) < 0)
556             syslog(L_ERROR, "%s cant close %d %m", LogName, fd);
557         return;
558     }
559 #endif
560
561     /* If RemoteTimer is not zero, then check the limits on incoming
562        connections on a total and per host basis.
563
564        The incoming connection table is fixed at 128 entries to make
565        calculating the index easy (i + 1) & 7, and to be pretty sure that you
566        won't run out of space.  The table is used as a ring with new entries
567        being added to the end (wrapping around) and expired entries being
568        deleted from the front (again wrapping around).  It is doubtful that
569        you will ever use even half of the table.
570
571        There are three parameters controlling the use of the table not
572        counting the starting index and count:
573
574            H = per host incoming connects per X seconds allowed
575            T = total incoming connects per X seconds allowed
576            X = number of seconds to remember a successful connect
577
578        First, one pass is made over the live entries deleting any that are
579        over X seconds old.  If the entry hasn't expired, compare the incoming
580        connection's host address with the entry's host address.  If equal,
581        increment the "found" counter.
582
583        Second, if the number of entries now in the table is equal to the T
584        parameter, reject the connection with a message indicating that the
585        server is overloaded.
586
587        Third, if the number of entries now in the table which match the
588        incoming connection's host address is equal to the H parameter, reject
589        the connection.
590
591        Finally, if neither rejection happened, add the entry to the table, and
592        continue on as a normal connect. */
593     memcpy(&tempchan.Address, &remote, SA_LEN((struct sockaddr *)&remote));
594     reject_message = NULL;
595     if (RemoteTimer != 0) {
596         now = time(NULL);
597         i = remotefirst;
598         count = remotecount;
599         found = 0;
600         while (count--) {
601             if (remotetable[i].Expires < now) {
602                 remotecount--;
603                 remotefirst = (remotefirst + 1) & (REMOTETABLESIZE - 1);
604                 i = (i + 1) & (REMOTETABLESIZE - 1);
605                 continue;
606             }
607             if (RCaddressmatch(&remotetable[i].Address, &remote))
608                 found++;
609             i = (i + 1) & (REMOTETABLESIZE - 1);
610         }
611         if (remotecount == RemoteTotal) {
612             reject_val = NNTP_GOODBYE_VAL;
613             reject_message = "400 Server overloaded, try later";
614         }
615         else if (found >= RemoteLimit && !RCnolimit(&tempchan)) {
616             reject_val = NNTP_GOODBYE_VAL;
617             reject_message = "400 Connection rejected, you're making too"
618                 " many connects per minute";
619         }
620         else {
621             i = (remotefirst + remotecount) & (REMOTETABLESIZE - 1);
622             memcpy(&remotetable[i].Address, &remote, SA_LEN((struct sockaddr *)&remote));
623             remotetable[i].Expires = now + RemoteTimer;
624             remotecount++;
625         }
626     }
627
628     /*
629     ** Create a reject channel to reject the connection.  This is done
630     ** to avoid a call to fork.  
631     */
632     if (reject_message) {
633         new = CHANcreate(fd, CTreject, CSwritegoodbye, RCrejectreader,
634             RCrejectwritedone);
635         memcpy(&remotetable[i].Address, &remote, SA_LEN((struct sockaddr *)&remote));
636         new->Rejected = reject_val;
637         RCHANremove(new);
638         WCHANset(new, reject_message, (int)strlen(reject_message));
639         WCHANappend(new, RCterm, strlen(RCterm));
640         WCHANadd(new);
641         return;
642     }
643
644     /* See if it's one of our servers. */
645     for (name = NULL, rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++)
646         if (RCaddressmatch(&rp->Address, &remote)) {
647             name = rp->Name;
648             break;
649         }
650
651     /* If not a server, and not allowing anyone, hand him off unless
652        not spawning nnrpd in which case we return an error. */
653     if ((i >= 0) && !rp->Skip) {
654
655         /* We check now the identd if we have to */
656         if(! GoodIdent(fd, rp->Identd))
657         {
658             if (!innconf->noreader) {
659                 RChandoff(fd, HOnntpd);
660                 if (close(fd) < 0)
661                     syslog(L_ERROR, "%s cant close %d %m", LogName, fd);
662                 return;
663             }
664         }
665         
666         if ((new = NCcreate(fd, rp->Password[0] != '\0', false)) != NULL) {
667             new->Streaming = rp->Streaming;
668             new->Skip = rp->Skip;
669             new->NoResendId = rp->NoResendId;
670             new->Nolist = rp->Nolist;
671             new->MaxCnx = rp->MaxCnx;
672             new->HoldTime = rp->HoldTime;
673             memcpy(&new->Address, &remote, SA_LEN((struct sockaddr *)&remote));
674             if (new->MaxCnx > 0 && new->HoldTime == 0) {
675                 CHANsetActiveCnx(new);
676                 if((new->ActiveCnx > new->MaxCnx) && (new->fd > 0)) {
677                     snprintf(buff, sizeof(buff),
678                              "You are limited to %d connection%s",
679                              new->MaxCnx, (new->MaxCnx != 1) ? "s" : "");
680                     NCwriteshutdown(new, buff);
681                     syslog(L_NOTICE, "too many connections from %s", rp->Label);
682                 } else {
683                     NCwritereply(new, (char *)NCgreeting);
684                 }
685             } else {
686                 NCwritereply(new, (char *)NCgreeting);
687             }
688         }
689     } else if (AnyIncoming && !rp->Skip) {
690         if ((new = NCcreate(fd, false, false)) != NULL) {
691             NCwritereply(new, (char *)NCgreeting);
692         }
693     } else if (!innconf->noreader) {
694         RChandoff(fd, HOnntpd);
695         if (close(fd) < 0)
696             syslog(L_ERROR, "%s cant close %d %m", LogName, fd);
697         return;
698     } else {
699         reject_val = NNTP_ACCESS_VAL;
700         reject_message = NNTP_ACCESS;
701         new = CHANcreate(fd, CTreject, CSwritegoodbye, RCrejectreader,
702             RCrejectwritedone);
703         memcpy(&new->Address, &remote, SA_LEN((struct sockaddr *)&remote));
704         new->Rejected = reject_val;
705         RCHANremove(new);
706         WCHANset(new, reject_message, (int)strlen(reject_message));
707         WCHANappend(new, RCterm, strlen(RCterm));
708         WCHANadd(new);
709         return;
710     }
711
712     if (new != NULL) {
713         memcpy(&new->Address, &remote, SA_LEN((struct sockaddr *)&remote));
714         syslog(L_NOTICE, "%s connected %d streaming %s",
715            name ? name : sprint_sockaddr((struct sockaddr *)&new->Address),
716            new->fd, (!StreamingOff && new->Streaming) ? "allowed" : "not allowed");
717     }
718 }
719
720
721 /*
722 **  Write-done function.  Shouldn't happen.
723 */
724 static void
725 RCwritedone(CHANNEL *unused)
726 {
727     unused = unused;            /* ARGSUSED */
728     syslog(L_ERROR, "%s internal RCwritedone", LogName);
729 }
730
731 /*
732  *  New config file style. Old hosts.nntp and hosts.nntp.nolimit are merged
733  *  into one file called incoming.conf (to avoid confusion).
734  *  See ../samples/incoming.conf for the new syntax.
735  *
736  *  Fabien Tassin <fta@sofaraway.org>, 21-Dec-1997.
737  */
738
739
740 /*
741  * Read something (a word or a double quoted string) from a file.
742  */
743 static char *
744 RCreaddata(int *num, FILE *F, bool *toolong)
745 {
746   char  *p;
747   char  *s;
748   char  *t;
749   char  *word;
750   bool  flag;
751
752   *toolong = false;
753   if (*RCbuff == '\0') {
754     if (feof (F)) return (NULL);
755     fgets(RCbuff, sizeof RCbuff, F);
756     (*num)++;
757     if (strlen (RCbuff) == sizeof RCbuff) {
758       *toolong = true;
759       return (NULL); /* Line too long */
760     }
761   }
762   p = RCbuff;
763   do {
764      /* Ignore blank and comment lines. */
765      if ((p = strchr(RCbuff, '\n')) != NULL)
766        *p = '\0';
767      if ((p = strchr(RCbuff, '#')) != NULL) {
768        if (p == RCbuff || (p > RCbuff && *(p - 1) != '\\'))
769            *p = '\0';
770      }
771      for (p = RCbuff; *p == ' ' || *p == '\t' ; p++);
772      flag = true;
773      if (*p == '\0' && !feof (F)) {
774        flag = false;
775        fgets(RCbuff, sizeof RCbuff, F);
776        (*num)++;
777        if (strlen (RCbuff) == sizeof RCbuff) {
778          *toolong = true;
779          return (NULL); /* Line too long */
780        }
781        continue;
782      }
783      break;
784   } while (!feof (F) || !flag);
785
786   if (*p == '"') { /* double quoted string ? */
787     p++;
788     do {
789       for (t = p; (*t != '"' || (*t == '"' && *(t - 1) == '\\')) &&
790              *t != '\0'; t++);
791       if (*t == '\0') {
792         *t++ = '\n';
793         fgets(t, sizeof RCbuff - strlen (RCbuff), F);
794         (*num)++;
795         if (strlen (RCbuff) == sizeof RCbuff) {
796           *toolong = true;
797           return (NULL); /* Line too long */
798         }
799         if ((s = strchr(t, '\n')) != NULL)
800           *s = '\0';
801       }
802       else 
803         break;
804     } while (!feof (F));
805     *t++ = '\0';
806   }
807   else {
808     for (t = p; *t != ' ' && *t != '\t' && *t != '\0'; t++);
809     if (*t != '\0')
810       *t++ = '\0';
811   }
812   if (*p == '\0' && feof (F)) return (NULL);
813   word = xstrdup (p);
814   for (p = RCbuff; *t != '\0'; t++)
815     *p++ = *t;
816   *p = '\0';
817
818   return (word);
819 }
820
821 /*
822  *  Add all data into RCpeerlistfile.
823  */
824 static void
825 RCadddata(REMOTEHOST_DATA **d, int *count, int Key, int Type, char* Value)
826 {
827   (*d)[*count].key = Key;
828   (*d)[*count].type = Type;
829   (*d)[*count].value = Value;
830   (*count)++;
831   *d = xrealloc(*d, (*count + 1) * sizeof(REMOTEHOST_DATA));
832 }
833
834 /*
835 **  Read in the file listing the hosts we take news from, and fill in the
836 **  global list of their Internet addresses.  A host can have multiple
837 **  addresses, so we take care to add all of them to the list.
838 */
839 static void
840 RCreadfile (REMOTEHOST_DATA **data, REMOTEHOST **list, int *count, 
841             char *filename)
842 {
843     static char         NOPASS[] = "";
844     static char         NOIDENTD[] = "";
845     static char         NOEMAIL[] = "";
846     static char         NOCOMMENT[] = "";
847     FILE                *F;
848     char                *p;
849     char                **q;
850     char                **r;
851 #if     !defined( HAVE_INET6)
852     struct hostent      *hp;
853 #endif
854 #if     !defined(HAVE_UNIX_DOMAIN_SOCKETS) || !defined(HAVE_INET6)
855     struct in_addr      addr;
856 #endif
857     int                 i;
858     int                 j;
859     int                 linecount;
860     int                 infocount;
861     int                 groupcount;
862     int                 maxgroup;
863     REMOTEHOST_DATA     *dt;
864     REMOTEHOST          *rp;
865     char                *word;
866     REMOTEHOST          *groups;
867     REMOTEHOST          *group_params = NULL;
868     REMOTEHOST          peer_params;
869     REMOTEHOST          default_params;
870     bool                flag, bit, toolong;
871  
872     *RCbuff = '\0';
873     if (*list) {
874         for (rp = *list, i = *count; --i >= 0; rp++) {
875             free(rp->Name);
876             free(rp->Label);
877             free(rp->Email);
878             free(rp->Comment);
879             free(rp->Password);
880             free(rp->Identd);
881             if (rp->Patterns) {
882                 free(rp->Patterns[0]);
883                 free(rp->Patterns);
884             }
885         }
886         free(*list);
887         *list = NULL;
888         *count = 0;
889     }
890     if (*data) {
891         for (i = 0; (*data)[i].key != K_END; i++)
892             if ((*data)[i].value != NULL)
893                 free((*data)[i].value);
894         free(*data);
895         *data = NULL;
896     }
897
898     *count = 0;
899     maxgroup = 0;
900     /* Open the server file. */
901     if ((F = Fopen(filename, "r", TEMPORARYOPEN)) == NULL) {
902         syslog(L_FATAL, "%s cant read %s: %m", LogName, filename);
903         exit(1);
904     }
905     dt = *data = xmalloc(sizeof(REMOTEHOST_DATA));
906     rp = *list = xmalloc(sizeof(REMOTEHOST));
907
908 #if     !defined(HAVE_UNIX_DOMAIN_SOCKETS)
909     addr.s_addr = INADDR_LOOPBACK;
910     make_sin( (struct sockaddr_in *)&rp->Address, &addr );
911     rp->Name = xstrdup("localhost");
912     rp->Label = xstrdup("localhost");
913     rp->Email = xstrdup(NOEMAIL);
914     rp->Comment = xstrdup(NOCOMMENT);
915     rp->Password = xstrdup(NOPASS);
916     rp->Identd = xstrdup(NOIDENTD);
917     rp->Patterns = NULL;
918     rp->MaxCnx = 0;
919     rp->Streaming = true;
920     rp->Skip = false;
921     rp->NoResendId = false;
922     rp->Nolist = false;
923     rp->HoldTime = 0;
924     rp++;
925     (*count)++;
926 #endif  /* !defined(HAVE_UNIX_DOMAIN_SOCKETS) */
927
928     linecount = 0;
929     infocount = 0;
930     groupcount = 0; /* no group defined yet */
931     groups = 0;
932     peer_params.Label = NULL;
933     default_params.Streaming = true;
934     default_params.Skip = false;
935     default_params.NoResendId = false;
936     default_params.Nolist = false;
937     default_params.MaxCnx = 0;
938     default_params.HoldTime = 0;
939     default_params.Password = xstrdup(NOPASS);
940     default_params.Identd = xstrdup(NOIDENTD);
941     default_params.Email = xstrdup(NOEMAIL);
942     default_params.Comment = xstrdup(NOCOMMENT);
943     default_params.Pattern = NULL;
944     peer_params.Keysetbit = 0;
945
946     /* Read the file to add all the hosts. */
947     while ((word = RCreaddata (&linecount, F, &toolong)) != NULL) {
948
949       /* group */
950       if (!strncmp (word, GROUP,  sizeof GROUP)) {
951         free(word);
952         /* name of the group */
953         if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
954           syslog(L_ERROR, GROUP_NAME, LogName, filename, linecount);
955           break;
956         }
957         RCadddata(data, &infocount, K_BEGIN_GROUP, T_STRING, word);
958         groupcount++;
959         if (groupcount == 1) {
960           /* First group block. */
961           group_params = groups = xmalloc(sizeof(REMOTEHOST));
962         }
963         else if (groupcount >= maxgroup) {
964           /* Alloc 5 groups for extra nested group blocks. */
965           groups = xrealloc(groups, (groupcount + 4) * sizeof(REMOTEHOST));
966           maxgroup += 5;
967           group_params = groups + groupcount - 1;
968         }
969         else {
970           /* Nested group block (no need to extend groups). */
971           group_params++;
972         }
973         group_params->Label = word;
974         group_params->Skip = groupcount > 1 ?
975           groups[groupcount - 2].Skip : default_params.Skip;
976         group_params->Streaming = groupcount > 1 ?
977           groups[groupcount - 2].Streaming : default_params.Streaming;
978         group_params->NoResendId = groupcount > 1 ?
979           groups[groupcount - 2].NoResendId : default_params.NoResendId;
980         group_params->Nolist = groupcount > 1 ?
981           groups[groupcount - 2].Nolist : default_params.Nolist;
982         group_params->Email = groupcount > 1 ?
983           groups[groupcount - 2].Email : default_params.Email;
984         group_params->Comment = groupcount > 1 ?
985           groups[groupcount - 2].Comment : default_params.Comment;
986         group_params->Pattern = groupcount > 1 ?
987           groups[groupcount - 2].Pattern : default_params.Pattern;
988         group_params->Password = groupcount > 1 ?
989           groups[groupcount - 2].Password : default_params.Password;
990         group_params->Identd = groupcount > 1 ?
991           groups[groupcount - 2].Identd : default_params.Identd;
992         group_params->MaxCnx = groupcount > 1 ?
993           groups[groupcount - 2].MaxCnx : default_params.MaxCnx;
994         group_params->HoldTime = groupcount > 1 ?
995           groups[groupcount - 2].HoldTime : default_params.HoldTime;
996
997         if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
998           syslog(L_ERROR, LEFT_BRACE, LogName, filename, linecount);
999           break;
1000         }
1001         /* left brace */
1002         if (strncmp (word, "{", 1)) {
1003           free(word);
1004           syslog(L_ERROR, LEFT_BRACE, LogName, filename, linecount);
1005           break;
1006         }
1007         else
1008           free(word);
1009         peer_params.Keysetbit = 0;
1010         continue;
1011       }
1012
1013       /* peer */
1014       if (!strncmp (word, PEER, sizeof PEER)) {
1015         free(word);
1016         if (peer_params.Label != NULL) {
1017           /* peer can't contain peer */
1018           syslog(L_ERROR, PEER_IN_PEER, LogName, 
1019               filename, linecount);
1020           break;
1021         }
1022         if ((word = RCreaddata (&linecount, F, &toolong)) == NULL)
1023         {
1024           syslog(L_ERROR, PEER_NAME, LogName, filename, linecount);
1025           break;
1026         }
1027         RCadddata(data, &infocount, K_BEGIN_PEER, T_STRING, word);
1028         /* name of the peer */
1029         peer_params.Label = word;
1030         peer_params.Name = NULL;
1031         peer_params.Skip = groupcount > 0 ?
1032           group_params->Skip : default_params.Skip;
1033         peer_params.Streaming = groupcount > 0 ?
1034           group_params->Streaming : default_params.Streaming;
1035         peer_params.NoResendId = groupcount > 0 ?
1036           group_params->NoResendId : default_params.NoResendId;
1037         peer_params.Nolist = groupcount > 0 ?
1038           group_params->Nolist : default_params.Nolist;
1039         peer_params.Email = groupcount > 0 ?
1040           group_params->Email : default_params.Email;
1041         peer_params.Comment = groupcount > 0 ?
1042           group_params->Comment : default_params.Comment;
1043         peer_params.Pattern = groupcount > 0 ?
1044           group_params->Pattern : default_params.Pattern;
1045         peer_params.Password = groupcount > 0 ?
1046           group_params->Password : default_params.Password;
1047         peer_params.Identd = groupcount > 0 ?
1048           group_params->Identd : default_params.Identd;
1049         peer_params.MaxCnx = groupcount > 0 ?
1050           group_params->MaxCnx : default_params.MaxCnx;
1051         peer_params.HoldTime = groupcount > 0 ?
1052           group_params->HoldTime : default_params.HoldTime;
1053
1054         peer_params.Keysetbit = 0;
1055
1056         if ((word = RCreaddata (&linecount, F, &toolong)) == NULL)
1057         {
1058           syslog(L_ERROR, LEFT_BRACE, LogName, filename, linecount);
1059           break;
1060         }
1061         /* left brace */
1062         if (strncmp (word, "{", 1)) {
1063           syslog(L_ERROR, LEFT_BRACE, LogName, filename, linecount);
1064           free(word);
1065           break;
1066         }
1067         else
1068           free(word);
1069         continue;
1070       }
1071
1072       /* right brace */
1073       if (!strncmp (word, "}", 1)) {
1074         free(word);
1075         if (peer_params.Label != NULL) {
1076           RCadddata(data, &infocount, K_END_PEER, T_STRING, NULL);
1077
1078           /* Hostname defaults to label if not given */
1079           if (peer_params.Name == NULL)
1080             peer_params.Name = xstrdup(peer_params.Label);
1081
1082           for(r = q = RCCommaSplit(xstrdup(peer_params.Name)); *q != NULL; q++) {
1083 #ifdef HAVE_INET6
1084               struct addrinfo *res, *res0, hints;
1085               int gai_ret;
1086 #endif
1087             (*count)++;
1088
1089             /* Grow the array */
1090             j = rp - *list;
1091             *list = xrealloc(*list, *count * sizeof(REMOTEHOST));
1092             rp = *list + j;
1093
1094 #ifdef HAVE_INET6
1095             memset( &hints, 0, sizeof( hints ) );
1096             hints.ai_socktype = SOCK_STREAM;
1097             hints.ai_family = PF_UNSPEC;
1098             if ((gai_ret = getaddrinfo(*q, NULL, &hints, &res0)) != 0) {
1099                 syslog(L_ERROR, "%s cant getaddrinfo %s %s", LogName, *q,
1100                                 gai_strerror( gai_ret ) );
1101                 /* decrement *count, since we never got to add this record. */
1102                 (*count)--;
1103                 continue;
1104             }
1105             /* Count the addresses and see if we have to grow the list */
1106             i = 0;
1107             for (res = res0; res != NULL; res = res->ai_next)
1108                 i++;
1109             /* Grow the array */
1110             j = rp - *list;
1111             *count += i - 1;
1112             *list = xrealloc(*list, *count * sizeof(REMOTEHOST));
1113             rp = *list + j;
1114
1115             /* Add all hosts */
1116             for (res = res0; res != NULL; res = res->ai_next) {
1117                 (void)memcpy(&rp->Address, res->ai_addr, res->ai_addrlen);
1118                 rp->Name = xstrdup (*q);
1119                 rp->Label = xstrdup (peer_params.Label);
1120                 rp->Email = xstrdup(peer_params.Email);
1121                 rp->Comment = xstrdup(peer_params.Comment);
1122                 rp->Streaming = peer_params.Streaming;
1123                 rp->Skip = peer_params.Skip;
1124                 rp->NoResendId = peer_params.NoResendId;
1125                 rp->Nolist = peer_params.Nolist;
1126                 rp->Password = xstrdup(peer_params.Password);
1127                 rp->Identd = xstrdup(peer_params.Identd);
1128                 rp->Patterns = peer_params.Pattern != NULL ?
1129                     RCCommaSplit(xstrdup(peer_params.Pattern)) : NULL;
1130                 rp->MaxCnx = peer_params.MaxCnx;
1131                 rp->HoldTime = peer_params.HoldTime;
1132                 rp++;
1133             }
1134             freeaddrinfo(res0);
1135 #else /* HAVE_INET6 */
1136             /* Was host specified as a dotted quad ? */
1137             if (inet_aton(*q, &addr)) {
1138               make_sin( (struct sockaddr_in *)&rp->Address, &addr );
1139               rp->Name = xstrdup (*q);
1140               rp->Label = xstrdup (peer_params.Label);
1141               rp->Password = xstrdup(peer_params.Password);
1142               rp->Identd = xstrdup(peer_params.Identd);
1143               rp->Skip = peer_params.Skip;
1144               rp->Streaming = peer_params.Streaming;
1145               rp->NoResendId = peer_params.NoResendId;
1146               rp->Nolist = peer_params.Nolist;
1147               rp->Email = xstrdup(peer_params.Email);
1148               rp->Comment = xstrdup(peer_params.Comment);
1149               rp->Patterns = peer_params.Pattern != NULL ?
1150                     RCCommaSplit(xstrdup(peer_params.Pattern)) : NULL;
1151               rp->MaxCnx = peer_params.MaxCnx;
1152               rp->HoldTime = peer_params.HoldTime;
1153               rp++;
1154               continue;
1155             }
1156             
1157             /* Host specified as a text name ? */
1158             if ((hp = gethostbyname(*q)) == NULL) {
1159               syslog(L_ERROR, "%s cant gethostbyname %s %m", LogName, *q);
1160               /* decrement *count, since we never got to add this record. */
1161               (*count)--;
1162               continue;
1163             }
1164
1165             /* Count the adresses and see if we have to grow the list */
1166             for (i = 0; hp->h_addr_list[i]; i++)
1167               continue;
1168             if (i == 0) {
1169               syslog(L_ERROR, "%s no_address %s %m", LogName, *q);
1170               continue;
1171             }
1172             if (i == 1) {
1173               char **rr;
1174               int    t = 0;
1175               /* Strange DNS ? try this.. */
1176               for (rr = hp->h_aliases; *rr != 0; rr++) {
1177                 if (!inet_aton(*rr, &addr))
1178                   continue;
1179                 (*count)++;
1180                 /* Grow the array */
1181                 j = rp - *list;
1182                 *list = xrealloc(*list, *count * sizeof(REMOTEHOST));
1183                 rp = *list + j;
1184
1185                 make_sin( (struct sockaddr_in *)&rp->Address, &addr );
1186                 rp->Name = xstrdup (*q);
1187                 rp->Label = xstrdup (peer_params.Label);
1188                 rp->Email = xstrdup(peer_params.Email);
1189                 rp->Comment = xstrdup(peer_params.Comment);
1190                 rp->Streaming = peer_params.Streaming;
1191                 rp->Skip = peer_params.Skip;
1192                 rp->NoResendId = peer_params.NoResendId;
1193                 rp->Nolist = peer_params.Nolist;
1194                 rp->Password = xstrdup(peer_params.Password);
1195                 rp->Identd = xstrdup(peer_params.Identd);
1196                 rp->Patterns = peer_params.Pattern != NULL ?
1197                   RCCommaSplit(xstrdup(peer_params.Pattern)) : NULL;
1198                 rp->MaxCnx = peer_params.MaxCnx;
1199                 rp->HoldTime = peer_params.HoldTime;
1200                 rp++;
1201                 t++;
1202               }
1203               if (t == 0) {
1204                 /* Just one, no need to grow. */
1205                 make_sin( (struct sockaddr_in *)&rp->Address,
1206                                 (struct in_addr *)hp->h_addr_list[0] );
1207                 rp->Name = xstrdup (*q);
1208                 rp->Label = xstrdup (peer_params.Label);
1209                 rp->Email = xstrdup(peer_params.Email);
1210                 rp->Comment = xstrdup(peer_params.Comment);
1211                 rp->Streaming = peer_params.Streaming;
1212                 rp->Skip = peer_params.Skip;
1213                 rp->NoResendId = peer_params.NoResendId;
1214                 rp->Nolist = peer_params.Nolist;
1215                 rp->Password = xstrdup(peer_params.Password);
1216                 rp->Identd = xstrdup(peer_params.Identd);
1217                 rp->Patterns = peer_params.Pattern != NULL ?
1218                   RCCommaSplit(xstrdup(peer_params.Pattern)) : NULL;
1219                 rp->MaxCnx = peer_params.MaxCnx;
1220                 rp->HoldTime = peer_params.HoldTime;
1221                 rp++;
1222                 continue;
1223               }
1224             }
1225             /* Grow the array */
1226             j = rp - *list;
1227             *count += i - 1;
1228             *list = xrealloc(*list, *count * sizeof(REMOTEHOST));
1229             rp = *list + j;
1230
1231             /* Add all the hosts. */
1232             for (i = 0; hp->h_addr_list[i]; i++) {
1233               make_sin( (struct sockaddr_in *)&rp->Address,
1234                               (struct in_addr *)hp->h_addr_list[i] );
1235               rp->Name = xstrdup (*q);
1236               rp->Label = xstrdup (peer_params.Label);
1237               rp->Email = xstrdup(peer_params.Email);
1238               rp->Comment = xstrdup(peer_params.Comment);
1239               rp->Streaming = peer_params.Streaming;
1240               rp->Skip = peer_params.Skip;
1241               rp->NoResendId = peer_params.NoResendId;
1242               rp->Nolist = peer_params.Nolist;
1243               rp->Password = xstrdup(peer_params.Password);
1244               rp->Identd = xstrdup(peer_params.Identd);
1245               rp->Patterns = peer_params.Pattern != NULL ?
1246                 RCCommaSplit(xstrdup(peer_params.Pattern)) : NULL;
1247               rp->MaxCnx = peer_params.MaxCnx;
1248               rp->HoldTime = peer_params.HoldTime;
1249               rp++;
1250             }
1251 #endif /* HAVE_INET6 */
1252           }
1253           free(r[0]);
1254           free(r);
1255           peer_params.Label = NULL;
1256         }
1257         else if (groupcount > 0 && group_params->Label != NULL) {
1258           RCadddata(data, &infocount, K_END_GROUP, T_STRING, NULL);
1259           group_params->Label = NULL;
1260           groupcount--;
1261          if (groupcount == 0) {
1262            /* We are now outside a group block. */
1263            free(groups);
1264            maxgroup = 0;
1265          } else {
1266            group_params--;
1267          }
1268         }
1269         else {
1270           syslog(L_ERROR, RIGHT_BRACE, LogName, linecount, filename);
1271         }
1272         continue;
1273       }
1274
1275       /* streaming */
1276       if (!strncmp (word, STREAMING, sizeof STREAMING)) {
1277         free(word);
1278         TEST_CONFIG(K_STREAM, bit);
1279         if (bit) {
1280           syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
1281           break;
1282         }
1283         if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
1284           break;
1285         }
1286         if (!strcmp (word, "true"))
1287           flag = true;
1288         else
1289           if (!strcmp (word, "false"))
1290             flag = false;
1291           else {
1292             syslog(L_ERROR, MUST_BE_BOOL, LogName, filename, linecount);
1293             break;
1294           }
1295         RCadddata(data, &infocount, K_STREAM, T_STRING, word);
1296         if (peer_params.Label != NULL)
1297           peer_params.Streaming = flag;
1298         else
1299           if (groupcount > 0 && group_params->Label != NULL)
1300             group_params->Streaming = flag;
1301           else
1302             default_params.Streaming = flag;
1303         SET_CONFIG(K_STREAM);
1304         continue;
1305       }
1306
1307       /* skip */
1308       if (!strncmp (word, SKIP, sizeof SKIP)) {
1309         free(word);
1310         TEST_CONFIG(K_SKIP, bit);
1311         if (bit) {
1312           syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
1313           break;
1314         }
1315         if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
1316           break;
1317         }
1318         if (!strcmp (word, "true"))
1319           flag = true;
1320         else
1321           if (!strcmp (word, "false"))
1322             flag = false;
1323           else {
1324             syslog(L_ERROR, MUST_BE_BOOL, LogName, filename, linecount);
1325             break;
1326           }
1327         RCadddata(data, &infocount, K_SKIP, T_STRING, word);
1328         if (peer_params.Label != NULL)
1329           peer_params.Skip = flag;
1330         else
1331           if (groupcount > 0 && group_params->Label != NULL)
1332             group_params->Skip = flag;
1333           else
1334             default_params.Skip = flag;
1335         SET_CONFIG(K_SKIP);
1336         continue;
1337       }
1338
1339       /* noresendid */
1340       if (!strncmp (word, NORESENDID, sizeof NORESENDID)) {
1341         free(word);
1342         TEST_CONFIG(K_NORESENDID, bit);
1343         if (bit) {
1344           syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
1345           break;
1346         }
1347         if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
1348           break;
1349         }
1350         if (!strcmp (word, "true"))
1351           flag = true;
1352         else
1353           if (!strcmp (word, "false"))
1354             flag = false;
1355           else {
1356             syslog(L_ERROR, MUST_BE_BOOL, LogName, filename, linecount);
1357             break;
1358           }
1359         RCadddata(data, &infocount, K_NORESENDID, T_STRING, word);
1360         if (peer_params.Label != NULL)
1361           peer_params.NoResendId = flag;
1362         else
1363           if (groupcount > 0 && group_params->Label != NULL)
1364             group_params->NoResendId = flag;
1365           else
1366             default_params.NoResendId = flag;
1367         SET_CONFIG(K_NORESENDID);
1368         continue;
1369       }
1370
1371       /* nolist */
1372       if (!strncmp (word, NOLIST, sizeof NOLIST)) {
1373         free(word);
1374         TEST_CONFIG(K_NOLIST, bit);
1375         if (bit) {
1376           syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
1377           break;
1378         }
1379         if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
1380           break;
1381         }
1382         if (!strcmp (word, "true"))
1383           flag = true;
1384         else
1385           if (!strcmp (word, "false"))
1386             flag = false;
1387           else {
1388             syslog(L_ERROR, MUST_BE_BOOL, LogName, filename, linecount);
1389             break;
1390           }
1391         RCadddata(data, &infocount, K_NOLIST, T_STRING, word);
1392         if (peer_params.Label != NULL)
1393           peer_params.Nolist = flag;
1394         else
1395           if (groupcount > 0 && group_params->Label != NULL)
1396             group_params->Nolist = flag;
1397           else
1398             default_params.Nolist = flag;
1399         SET_CONFIG(K_NOLIST);
1400         continue;
1401       }
1402
1403       /* max-connections */
1404       if (!strncmp (word, MAX_CONN, sizeof MAX_CONN)) {
1405         int max;
1406         free(word);
1407         TEST_CONFIG(K_MAX_CONN, bit);
1408         if (bit) {
1409           syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
1410           break;
1411         }
1412         if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
1413           break;
1414         }
1415         RCadddata(data, &infocount, K_MAX_CONN, T_STRING, word);
1416         for (p = word; CTYPE(isdigit, *p) && *p != '\0'; p++);
1417         if (!strcmp (word, "none") || !strcmp (word, "unlimited")) {
1418           max = 0;
1419         } else {
1420           if (*p != '\0') {
1421             syslog(L_ERROR, MUST_BE_INT, LogName, filename, linecount);
1422             break;
1423           }
1424           max = atoi(word);
1425         }
1426         if (peer_params.Label != NULL)
1427           peer_params.MaxCnx = max;
1428         else
1429           if (groupcount > 0 && group_params->Label != NULL)
1430             group_params->MaxCnx = max;
1431           else
1432             default_params.MaxCnx = max;
1433         SET_CONFIG(K_MAX_CONN);
1434         continue;
1435       }
1436
1437       /* hold-time */
1438       if (!strncmp (word, HOLD_TIME, sizeof HOLD_TIME)) {
1439         free(word);
1440         TEST_CONFIG(K_HOLD_TIME, bit);
1441         if (bit) {
1442           syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
1443           break;
1444         }
1445         if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
1446           break;
1447         }
1448         RCadddata(data, &infocount, K_HOLD_TIME, T_STRING, word);
1449         for (p = word; CTYPE(isdigit, *p) && *p != '\0'; p++);
1450         if (*p != '\0') {
1451           syslog(L_ERROR, MUST_BE_INT, LogName, filename, linecount);
1452           break;
1453         }
1454         if (peer_params.Label != NULL)
1455           peer_params.HoldTime = atoi(word);
1456         else
1457           if (groupcount > 0 && group_params->Label != NULL)
1458             group_params->HoldTime = atoi(word);
1459           else
1460             default_params.HoldTime = atoi(word);
1461         SET_CONFIG(K_HOLD_TIME);
1462         continue;
1463       }
1464
1465       /* hostname */
1466       if (!strncmp (word, HOSTNAME, sizeof HOSTNAME)) {
1467         free(word);
1468         TEST_CONFIG(K_HOSTNAME, bit);
1469         if (bit) {
1470           syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
1471           break;
1472         }
1473         if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
1474           break;
1475         }
1476         RCadddata(data, &infocount, K_HOSTNAME, T_STRING, word);
1477         peer_params.Name = word;
1478         SET_CONFIG(K_HOSTNAME);
1479         continue;
1480       }
1481
1482       /* password */
1483       if (!strncmp (word, PASSWORD, sizeof PASSWORD)) {
1484         free(word);
1485         TEST_CONFIG(K_PASSWORD, bit);
1486         if (bit) {
1487           syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
1488           break;
1489         }
1490         if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
1491           break;
1492         }
1493         RCadddata(data, &infocount, K_PASSWORD, T_STRING, word);
1494         if (peer_params.Label != NULL)
1495           peer_params.Password = word;
1496         else
1497           if (groupcount > 0 && group_params->Label != NULL)
1498             group_params->Password = word;
1499           else
1500             default_params.Password = word;
1501         SET_CONFIG(K_PASSWORD);
1502         continue;
1503       }
1504
1505       /* identd */
1506       if (!strncmp (word, IDENTD, sizeof IDENTD)) {
1507         free(word);
1508         TEST_CONFIG(K_IDENTD, bit);
1509         if (bit) {
1510           syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
1511           break;
1512         }
1513         if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
1514           break;
1515         }
1516         RCadddata(data, &infocount, K_IDENTD, T_STRING, word);
1517         if (peer_params.Label != NULL)
1518           peer_params.Identd = word;
1519         else
1520           if (groupcount > 0 && group_params->Label != NULL)
1521             group_params->Identd = word;
1522           else
1523             default_params.Identd = word;
1524         SET_CONFIG(K_IDENTD);
1525         continue;
1526       }
1527
1528       /* patterns */
1529       if (!strncmp (word, PATTERNS, sizeof PATTERNS)) {
1530         TEST_CONFIG(K_PATTERNS, bit);
1531         if (bit) {
1532           syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
1533           break;
1534         }
1535         free(word);
1536         if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
1537           break;
1538         }
1539         RCadddata(data, &infocount, K_PATTERNS, T_STRING, word);
1540         if (peer_params.Label != NULL)
1541           peer_params.Pattern = word;
1542         else
1543           if (groupcount > 0 && group_params->Label != NULL)
1544             group_params->Pattern = word;
1545           else
1546             default_params.Pattern = word;
1547         SET_CONFIG(K_PATTERNS);
1548         continue;
1549       }
1550
1551       /* email */
1552       if (!strncmp (word, EMAIL, sizeof EMAIL)) {
1553         free(word);
1554         TEST_CONFIG(K_EMAIL, bit);
1555         if (bit) {
1556           syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
1557           break;
1558         }
1559         if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
1560           break;
1561         }
1562         RCadddata(data, &infocount, K_EMAIL, T_STRING, word);
1563         if (peer_params.Label != NULL)
1564           peer_params.Email = word;
1565         else
1566           if (groupcount > 0 && group_params->Label != NULL)
1567             group_params->Email = word;
1568           else
1569             default_params.Email = word;
1570         SET_CONFIG(K_EMAIL);
1571         continue;
1572       }
1573
1574       /* comment */
1575       if (!strncmp (word, COMMENT, sizeof COMMENT)) {
1576         free(word);
1577         TEST_CONFIG(K_COMMENT, bit);
1578         if (bit) {
1579           syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
1580           break;
1581         }
1582         if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
1583           break;
1584         }
1585         RCadddata(data, &infocount, K_COMMENT, T_STRING, word);
1586         if (peer_params.Label != NULL)
1587           peer_params.Comment = word;
1588         else
1589           if (groupcount > 0 && group_params->Label != NULL)
1590             group_params->Comment = word;
1591           else
1592             default_params.Comment = word;
1593         SET_CONFIG(K_COMMENT);
1594         continue;
1595       }
1596
1597       if (toolong)
1598         syslog(L_ERROR, "%s line too long at %d: %s",
1599              LogName, --linecount, filename);
1600       else
1601         syslog(L_ERROR, "%s Unknown value line %d: %s",
1602              LogName, linecount, filename);
1603       free(word);
1604       break;
1605     }
1606     free(default_params.Email);
1607     free(default_params.Comment);
1608     RCadddata(data, &infocount, K_END, T_STRING, NULL);
1609
1610     if (feof (F)) {
1611       if (peer_params.Label != NULL)
1612         syslog(L_ERROR, INCOMPLETE_PEER, LogName, peer_params.Label,
1613                filename, linecount);
1614       if (groupcount > 0 && group_params->Label != NULL)
1615         syslog(L_ERROR, INCOMPLETE_GROUP, LogName, group_params->Label,
1616                filename, linecount);
1617     }
1618     else
1619       syslog(L_ERROR, "%s Syntax error in %s at or before line %d", LogName, 
1620              filename, linecount);
1621
1622     if (Fclose(F) == EOF)
1623         syslog(L_ERROR, "%s cant fclose %s %m", LogName, filename);
1624
1625     free(default_params.Password);
1626     free(default_params.Identd);
1627 }
1628
1629
1630 /*
1631 **  Indent a line with 3 * c blanks.
1632 **  Used by RCwritelist().
1633 */
1634 static void
1635 RCwritelistindent(FILE *F, int c)
1636 {
1637     int         i;
1638
1639     for (i = 0; i < c; i++)
1640         fprintf(F, "   ");
1641 }
1642
1643 /*
1644 **  Add double quotes around a string, if needed.
1645 **  Used by RCwritelist().
1646 */
1647 static void
1648 RCwritelistvalue(FILE *F, char *value)
1649 {
1650     if (*value == '\0' || strchr (value, '\n') ||
1651         strchr (value, ' ') || strchr (value, '\t'))
1652         fprintf(F, "\"%s\"", value);
1653     else
1654         fprintf(F, "%s", value);
1655 }
1656
1657 /*
1658 **  Write the incoming configuration (memory->disk)
1659 */
1660 static void UNUSED
1661 RCwritelist(char *filename)
1662 {
1663     FILE        *F;
1664     int         i;
1665     int         inc;
1666     char        *p;
1667     char        *q;
1668     char        *r;
1669
1670     if ((F = Fopen(filename, "w", TEMPORARYOPEN)) == NULL) {
1671         syslog(L_FATAL, "%s cant write %s: %m", LogName, filename);
1672         return;
1673     }
1674
1675     /* Write a standard header.. */
1676
1677     /* Find the filename */
1678     p = concatpath(innconf->pathetc, _PATH_INNDHOSTS);
1679     for (r = q = p; *p; p++)
1680         if (*p == '/')
1681            q = p + 1;
1682
1683     fprintf (F, "##  $Revision: 7751 $\n");
1684     fprintf (F, "##  %s - names and addresses that feed us news\n", q);
1685     free(r);
1686     fprintf (F, "##\n\n");
1687
1688     /* ... */
1689
1690     inc = 0;
1691     for (i = 0; RCpeerlistfile[i].key != K_END; i++) {
1692         switch (RCpeerlistfile[i].key) {
1693           case K_BEGIN_PEER:
1694             fputc ('\n', F);
1695             RCwritelistindent (F, inc);
1696             fprintf(F, "%s %s {\n", PEER, RCpeerlistfile[i].value);
1697             inc++;
1698             break;
1699           case K_BEGIN_GROUP:
1700             fputc ('\n', F);
1701             RCwritelistindent (F, inc);
1702             fprintf(F, "%s %s {\n", GROUP, RCpeerlistfile[i].value);
1703             inc++;
1704             break;
1705           case K_END_PEER:
1706           case K_END_GROUP:
1707             inc--;
1708             RCwritelistindent (F, inc);
1709             fprintf(F, "}\n");
1710             break;
1711           case K_STREAM:
1712             RCwritelistindent (F, inc);
1713             fprintf(F, "%s\t", STREAMING);
1714             RCwritelistvalue (F, RCpeerlistfile[i].value);
1715             fputc ('\n', F);
1716             break;
1717           case K_SKIP:
1718             RCwritelistindent (F, inc);
1719             fprintf(F, "%s\t", SKIP);
1720             RCwritelistvalue (F, RCpeerlistfile[i].value);
1721             fputc ('\n', F);
1722             break;
1723           case K_NORESENDID:
1724             RCwritelistindent (F, inc);
1725             fprintf(F, "%s\t", NORESENDID);
1726             RCwritelistvalue (F, RCpeerlistfile[i].value);
1727             fputc ('\n', F);
1728             break;
1729           case K_NOLIST:
1730             RCwritelistindent (F, inc);
1731             fprintf(F, "%s\t", NOLIST);
1732             RCwritelistvalue (F, RCpeerlistfile[i].value);
1733             fputc ('\n', F);
1734             break;
1735           case K_HOSTNAME:
1736             RCwritelistindent (F, inc);
1737             fprintf(F, "%s\t", HOSTNAME);
1738             RCwritelistvalue (F, RCpeerlistfile[i].value);
1739             fputc ('\n', F);
1740             break;
1741           case K_MAX_CONN:
1742             RCwritelistindent (F, inc);
1743             fprintf(F, "%s\t", MAX_CONN);
1744             RCwritelistvalue (F, RCpeerlistfile[i].value);
1745             fputc ('\n', F);
1746             break;
1747           case K_HOLD_TIME:
1748             RCwritelistindent (F, inc);
1749             fprintf(F, "%s\t", HOLD_TIME);
1750             RCwritelistvalue (F, RCpeerlistfile[i].value);
1751             fputc ('\n', F);
1752             break;
1753           case K_PASSWORD:
1754             RCwritelistindent (F, inc);
1755             fprintf(F, "%s\t", PASSWORD);
1756             RCwritelistvalue (F, RCpeerlistfile[i].value);
1757             fputc ('\n', F);
1758             break;
1759           case K_IDENTD:
1760             RCwritelistindent (F, inc);
1761             fprintf(F, "%s\t", IDENTD);
1762             RCwritelistvalue (F, RCpeerlistfile[i].value);
1763             fputc ('\n', F);
1764             break;
1765           case K_EMAIL:
1766             RCwritelistindent (F, inc);
1767             fprintf(F, "%s\t", EMAIL);
1768             RCwritelistvalue (F, RCpeerlistfile[i].value);
1769             fputc ('\n', F);
1770             break;
1771           case K_PATTERNS:
1772             RCwritelistindent (F, inc);
1773             fprintf(F, "%s\t", PATTERNS);
1774             RCwritelistvalue (F, RCpeerlistfile[i].value);
1775             fputc ('\n', F);
1776             break;
1777           case K_COMMENT:
1778             RCwritelistindent (F, inc);
1779             fprintf(F, "%s\t", COMMENT);
1780             RCwritelistvalue (F, RCpeerlistfile[i].value);
1781             fputc ('\n', F);
1782             break;
1783           default:
1784             fprintf(F, "# ***ERROR***\n");
1785         }
1786     }
1787     if (Fclose(F) == EOF)
1788         syslog(L_ERROR, "%s cant fclose %s %m", LogName, filename);
1789
1790 }
1791
1792 void
1793 RCreadlist(void)
1794 {
1795     static char *INNDHOSTS = NULL;
1796
1797     if (INNDHOSTS == NULL)
1798         INNDHOSTS = concatpath(innconf->pathetc, _PATH_INNDHOSTS);
1799     StreamingOff = false;
1800     RCreadfile(&RCpeerlistfile, &RCpeerlist, &RCnpeerlist, INNDHOSTS);
1801     /* RCwritelist("/tmp/incoming.conf.new"); */
1802 }
1803
1804 /*
1805 **  Find the name of a remote host we've connected to.
1806 */
1807 char *
1808 RChostname(const CHANNEL *cp)
1809 {
1810     static char buff[SMBUF];
1811     REMOTEHOST  *rp;
1812     int         i;
1813
1814     for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++)
1815         if (RCaddressmatch(&cp->Address, &rp->Address))
1816             return rp->Name;
1817     strlcpy(buff, sprint_sockaddr((struct sockaddr *)&cp->Address),
1818             sizeof(buff));
1819     return buff;
1820 }
1821
1822 /*
1823 **  Find the label name of a remote host we've connected to.
1824 */
1825 char *
1826 RClabelname(CHANNEL *cp) {
1827     REMOTEHOST  *rp;
1828     int         i;
1829
1830     for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++) {
1831         if (RCaddressmatch(&cp->Address, &rp->Address))
1832             return rp->Label;
1833     }
1834     return NULL;
1835 }
1836
1837 /*
1838 **  Is the remote site allowed to post to this group?
1839 */
1840 int
1841 RCcanpost(CHANNEL *cp, char *group)
1842 {
1843     REMOTEHOST          *rp;
1844     char                match;
1845     char                subvalue;
1846     char                **argv;
1847     char                *pat;
1848     int                 i;
1849
1850     /* Connections from lc.c are from local nnrpd and should always work */
1851     if (cp->Address.ss_family == 0)
1852         return 1;
1853
1854     for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++) {
1855         if (!RCaddressmatch(&cp->Address, &rp->Address))
1856             continue;
1857         if (rp->Patterns == NULL)
1858             break;
1859         for (match = 0, argv = rp->Patterns; (pat = *argv++) != NULL; ) {
1860             subvalue = (*pat != SUB_NEGATE) && (*pat != SUB_POISON) ?
1861               0 : *pat;
1862             if (subvalue)
1863                 pat++;
1864             if ((match != subvalue) && uwildmat(group, pat)) {
1865                 if (subvalue == SUB_POISON)
1866                     return -1;
1867                 match = subvalue;
1868             }
1869         }
1870         return !match;
1871     }
1872     return 1;
1873 }
1874
1875
1876 /*
1877 **  Create the channel.
1878 */
1879 void
1880 RCsetup(int i)
1881 {
1882 #if     defined(SO_REUSEADDR)
1883     int         on;
1884 #endif  /* defined(SO_REUSEADDR) */
1885     int         j;
1886     CHANNEL     *rcchan;
1887
1888     /* This code is called only when inndstart is not being used */
1889     if (i < 0) {
1890 #ifdef HAVE_INET6
1891         syslog(L_FATAL, "%s innd MUST be started with inndstart", LogName);
1892         exit(1);
1893 #else
1894         /* Create a socket and name it. */
1895         struct sockaddr_in      server;
1896
1897         if ((i = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
1898             syslog(L_FATAL, "%s cant socket RCreader %m", LogName);
1899             exit(1);
1900         }
1901 #if     defined(SO_REUSEADDR)
1902         on = 1;
1903         if (setsockopt(i, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on) < 0)
1904             syslog(L_ERROR, "%s cant setsockopt RCreader %m", LogName);
1905 #endif  /* defined(SO_REUSEADDR) */
1906         memset(&server, 0, sizeof server);
1907         server.sin_port = htons(innconf->port);
1908         server.sin_family = AF_INET;
1909 #ifdef HAVE_SOCKADDR_LEN
1910         server.sin_len = sizeof( struct sockaddr_in );
1911 #endif
1912         server.sin_addr.s_addr = htonl(INADDR_ANY);
1913         if (innconf->bindaddress) {
1914             if (!inet_aton(innconf->bindaddress, &server.sin_addr)) {
1915                 syslog(L_FATAL, "unable to determine bind ip (%s) %m",
1916                        innconf->bindaddress);
1917                 exit(1);
1918             }
1919         }
1920         if (bind(i, (struct sockaddr *)&server, sizeof server) < 0) {
1921             syslog(L_FATAL, "%s cant bind RCreader %m", LogName);
1922             exit(1);
1923         }
1924 #endif /* HAVE_INET6 */
1925     }
1926
1927     /* Set it up to wait for connections. */
1928     if (listen(i, MAXLISTEN) < 0) {
1929         j = errno;
1930         syslog(L_FATAL, "%s cant listen RCreader %m", LogName);
1931         /* some IPv6 systems already listening on any address will 
1932            return EADDRINUSE when trying to listen on the IPv4 socket */
1933         if (j == EADDRINUSE)
1934            return;
1935         exit(1);
1936     }
1937
1938     rcchan = CHANcreate(i, CTremconn, CSwaiting, RCreader, RCwritedone);
1939     syslog(L_NOTICE, "%s rcsetup %s", LogName, CHANname(rcchan));
1940     RCHANadd(rcchan);
1941
1942     for (j = 0 ; j < chanlimit ; j++ ) {
1943         if (RCchan[j] == NULL) {
1944             break;
1945         }
1946     }
1947     if (j < chanlimit) {
1948         RCchan[j] = rcchan;
1949     } else if (chanlimit == 0) {
1950         /* assuming two file descriptors(AF_INET and AF_INET6) */
1951         chanlimit = 2;
1952         RCchan = xmalloc(chanlimit * sizeof(CHANNEL **));
1953         for (j = 0 ; j < chanlimit ; j++ ) {
1954             RCchan[j] = NULL;
1955         }
1956         RCchan[0] = rcchan;
1957     } else {
1958         /* extend to double size */
1959         RCchan = xrealloc(RCchan, chanlimit * 2 * sizeof(CHANNEL **));
1960         for (j = chanlimit ; j < chanlimit * 2 ; j++ ) {
1961             RCchan[j] = NULL;
1962         }
1963         RCchan[chanlimit] = rcchan;
1964         chanlimit *= 2;
1965     }
1966
1967     /* Get the list of hosts we handle. */
1968     RCreadlist();
1969 }
1970
1971
1972 /*
1973 **  Cleanly shut down the channel.
1974 */
1975 void
1976 RCclose(void)
1977 {
1978     REMOTEHOST  *rp;
1979     int         i;
1980
1981     for (i = 0 ; i < chanlimit ; i++) {
1982         if (RCchan[i] != NULL) {
1983             CHANclose(RCchan[i], CHANname(RCchan[i]));
1984         } else {
1985             break;
1986         }
1987     }
1988     if (chanlimit != 0)
1989         free(RCchan);
1990     RCchan = NULL;
1991     chanlimit = 0;
1992     if (RCpeerlist) {
1993         for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++) {
1994             free(rp->Name);
1995             free(rp->Label);
1996             free(rp->Email);
1997             free(rp->Password);
1998             free(rp->Identd);
1999             free(rp->Comment);
2000             if (rp->Patterns) {
2001                 free(rp->Patterns[0]);
2002                 free(rp->Patterns);
2003             }
2004         }
2005         free(RCpeerlist);
2006         RCpeerlist = NULL;
2007         RCnpeerlist = 0;
2008     }
2009
2010     if (RCpeerlistfile) {
2011         for (i = 0; RCpeerlistfile[i].key != K_END; i++)
2012         if (RCpeerlistfile[i].value != NULL)
2013            free(RCpeerlistfile[i].value);
2014         free(RCpeerlistfile);
2015         RCpeerlistfile = NULL;
2016     }
2017 }