1 /* $Id: rc.c 7751 2008-04-06 14:35:40Z iulius $
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
10 #include "portable/socket.h"
14 #include "inn/innconf.h"
15 #include "inn/vector.h"
18 #define TEST_CONFIG(a, b) \
20 b = ((peer_params.Keysetbit & (1 << a)) != 0) ? true : false; \
23 #define SET_CONFIG(a) \
25 peer_params.Keysetbit |= (1 << a); \
29 ** A remote host has an address and a password.
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 */
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 */
56 typedef struct _REMOTETABLE {
57 struct sockaddr_storage Address;
61 static char *RCslaveflag;
62 static char *RCnnrpd = NULL;
63 static char *RCnntpd = NULL;
64 static CHANNEL **RCchan;
66 static REMOTEHOST_DATA *RCpeerlistfile;
67 static REMOTEHOST *RCpeerlist;
68 static int RCnpeerlist;
69 static char RCbuff[BIG_BUFFER];
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:"
82 #define NORESENDID "noresendid:"
83 #define HOLD_TIME "hold-time:"
84 #define NOLIST "nolist:"
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,
92 typedef enum {T_STRING, T_BOOLEAN, T_INTEGER} _Types;
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"
107 ** Stuff needed for limiting incoming connects.
109 static char RCterm[] = "\r\n";
110 static REMOTETABLE remotetable[REMOTETABLESIZE];
111 static int remotecount;
112 static int remotefirst;
115 * Check that the client has the right identd. Return true if is the
116 * case, false, if not.
119 GoodIdent(int fd, char *identd)
121 #define PORT_IDENTD 113
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;
133 if(identd[0] == '\0') {
137 len = sizeof( ss_local );
138 if ((getsockname(fd,s_local,&len)) < 0) {
139 syslog(L_ERROR, "can't do getsockname for identd");
142 len = sizeof( ss_distant );
143 if ((getpeername(fd,s_distant,&len)) < 0) {
144 syslog(L_ERROR, "can't do getsockname for identd");
148 if( s_local->sa_family == AF_INET6 )
150 struct sockaddr_in6 *s_l6 = (struct sockaddr_in6 *)s_local;
151 struct sockaddr_in6 *s_d6 = (struct sockaddr_in6 *)s_distant;
153 port1=ntohs(s_l6->sin6_port);
154 port2=ntohs(s_d6->sin6_port);
156 s_d6->sin6_port = htons( PORT_IDENTD );
157 ident_fd=socket(PF_INET6, SOCK_STREAM, 0);
160 if( s_local->sa_family == AF_INET )
162 struct sockaddr_in *s_l = (struct sockaddr_in *)s_local;
163 struct sockaddr_in *s_d = (struct sockaddr_in *)s_distant;
165 port1=ntohs(s_l->sin_port);
166 port2=ntohs(s_d->sin_port);
168 s_d->sin_port = htons( PORT_IDENTD );
169 ident_fd=socket(PF_INET, SOCK_STREAM, 0);
172 syslog(L_ERROR, "Bad address family: %d\n", s_local->sa_family );
176 syslog(L_ERROR, "can't open socket for identd (%m)");
179 if (bind(ident_fd,s_local,SA_LEN(s_local)) < 0) {
180 syslog(L_ERROR, "can't bind socket for identd (%m)");
184 if (connect(ident_fd,s_distant,SA_LEN(s_distant)) < 0) {
185 syslog(L_ERROR, "can't connect to identd (%m)");
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"?) */
196 syslog(L_ERROR, "error reading from ident server: %m" );
201 if ((lu>0) && (strstr(buf,"ERROR")==NULL)
202 && ((buf2=strrchr(buf,':'))!=NULL))
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';
211 strlcpy(IDENTuser, "UNKNOWN", sizeof(IDENTuser));
214 return strcmp(identd, IDENTuser) == 0;
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
227 RCCommaSplit(char *text)
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')
245 for (text = r, av = save = xmalloc(i * sizeof(char *)), *av++ = p = text; *p; )
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.
260 * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
263 * Code copied again, and modified for INN, all new mistakes are mine.
267 /* fix_options - get rid of IP-level socket options */
273 RCfix_options(int fd, struct sockaddr_storage *remote)
276 unsigned char optbuf[BUFSIZ / 3], *cp;
277 char lbuf[BUFSIZ], *lp;
278 socklen_t optsize = sizeof(optbuf);
282 switch (remote->ss_family) {
284 if ((ip = getprotobyname("ip")) != 0)
285 ipproto = ip->p_proto;
287 ipproto = IPPROTO_IP;
291 if ((ip = getprotobyname("ipv6")) != 0)
292 ipproto = ip->p_proto;
294 ipproto = IPPROTO_IPV6;
298 syslog(LOG_ERR, "unknown address family: %d", remote->ss_family);
302 if (getsockopt(fd, ipproto, IP_OPTIONS, (char *) optbuf, &optsize) == 0
305 for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3)
306 sprintf(lp, " %2.2x", *cp);
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");
320 RCaddressmatch(const struct sockaddr_storage *cp, const struct sockaddr_storage *rp)
323 struct sockaddr_in *sin_cp, *sin_rp;
324 struct sockaddr_in6 *sin6_cp, *sin6_rp;
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)
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)
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)))
346 if (IN6_ARE_ADDR_EQUAL( &((struct sockaddr_in6 *)cp)->sin6_addr,
347 &((struct sockaddr_in6 *)rp)->sin6_addr))
352 if (((struct sockaddr_in *)cp)->sin_addr.s_addr ==
353 ((struct sockaddr_in *)rp)->sin_addr.s_addr)
360 ** See if the site properly entered the password.
363 RCauthorized(CHANNEL *cp, char *pass)
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)
372 syslog(L_ERROR, "%s (%s) bad_auth", rp->Label,
373 sprint_sockaddr((struct sockaddr *)&cp->Address));
378 /* Not found in our table; this can't happen. */
379 syslog(L_ERROR, "%s not_found", sprint_sockaddr((struct sockaddr *)&cp->Address));
381 /* Anonymous hosts should not authenticate. */
386 ** See if a host is limited or not.
389 RCnolimit(CHANNEL *cp)
394 for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++)
395 if (RCaddressmatch(&cp->Address, &rp->Address))
398 /* Not found in our table; this can't happen. */
403 ** Return the limit (max number of connections) for a host.
411 for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++)
412 if (RCaddressmatch(&cp->Address, &rp->Address))
414 /* Not found in our table; this can't happen. */
420 ** Called when input is ready to read. Shouldn't happen.
423 RCrejectreader(CHANNEL *cp)
425 syslog(L_ERROR, "%s internal RCrejectreader (%s)", LogName,
426 sprint_sockaddr((struct sockaddr *)&cp->Address));
431 ** Write-done function for rejects.
434 RCrejectwritedone(CHANNEL *cp)
438 syslog(L_ERROR, "%s internal RCrejectwritedone state %d",
439 CHANname(cp), cp->State);
442 CHANclose(cp, CHANname(cp));
449 ** Hand off a descriptor to NNRPD.
452 RChandoff(int fd, HANDOFF h)
458 struct vector *flags;
460 flags = vector_split_space(innconf->nnrpdflags, NULL);
461 argv = xmalloc( (flags->count + 6) * sizeof(char*) );
464 RCnnrpd = concatpath(innconf->pathbin, "nnrpd");
466 RCnntpd = concatpath(innconf->pathbin, "nnrpd");
467 #if defined(SOL_SOCKET) && defined(SO_KEEPALIVE)
468 /* Set KEEPALIVE to catch broken socket connections. */
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) */
474 if (nonblocking(fd, false) < 0)
475 syslog(L_ERROR, "%s cant nonblock %d in RChandoff %m", LogName, fd);
478 syslog(L_ERROR, "%s internal RChandoff %d type %d", LogName, fd, h);
480 case HOnnrpd: argv[0] = RCnnrpd; break;
481 case HOnntpd: argv[0] = RCnntpd; break;
486 snprintf(buff, sizeof(buff), "-r%s", NNRPReason);
492 argv[i++] = RCslaveflag;
494 for(j = 0; j < flags->count; j++) {
495 argv[i++] = flags->strings[j];
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);
508 ** Read function. Accept the connection and either create an NNTP channel
509 ** or spawn an nnrpd to handle it.
512 RCreader(CHANNEL *cp)
515 struct sockaddr_storage remote;
522 const char *reject_message;
529 for (i = 0 ; i < chanlimit ; i++) {
530 if (RCchan[i] == cp) {
534 if (i == chanlimit) {
535 syslog(L_ERROR, "%s internal RCreader wrong channel 0x%p",
536 LogName, (void *)cp);
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);
549 ** Clear any IP_OPTIONS, including source routing, on the socket
551 /* FIXME RCfix_options breaks IPv6 sockets, at least on Linux -lutchann */
553 if (RCfix_options(fd, &remote) != 0) {
554 /* shouldn't happen, but we're bit paranoid at this point */
556 syslog(L_ERROR, "%s cant close %d %m", LogName, fd);
561 /* If RemoteTimer is not zero, then check the limits on incoming
562 connections on a total and per host basis.
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.
571 There are three parameters controlling the use of the table not
572 counting the starting index and count:
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
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.
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.
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
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) {
601 if (remotetable[i].Expires < now) {
603 remotefirst = (remotefirst + 1) & (REMOTETABLESIZE - 1);
604 i = (i + 1) & (REMOTETABLESIZE - 1);
607 if (RCaddressmatch(&remotetable[i].Address, &remote))
609 i = (i + 1) & (REMOTETABLESIZE - 1);
611 if (remotecount == RemoteTotal) {
612 reject_val = NNTP_GOODBYE_VAL;
613 reject_message = "400 Server overloaded, try later";
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";
621 i = (remotefirst + remotecount) & (REMOTETABLESIZE - 1);
622 memcpy(&remotetable[i].Address, &remote, SA_LEN((struct sockaddr *)&remote));
623 remotetable[i].Expires = now + RemoteTimer;
629 ** Create a reject channel to reject the connection. This is done
630 ** to avoid a call to fork.
632 if (reject_message) {
633 new = CHANcreate(fd, CTreject, CSwritegoodbye, RCrejectreader,
635 memcpy(&remotetable[i].Address, &remote, SA_LEN((struct sockaddr *)&remote));
636 new->Rejected = reject_val;
638 WCHANset(new, reject_message, (int)strlen(reject_message));
639 WCHANappend(new, RCterm, strlen(RCterm));
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)) {
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) {
655 /* We check now the identd if we have to */
656 if(! GoodIdent(fd, rp->Identd))
658 if (!innconf->noreader) {
659 RChandoff(fd, HOnntpd);
661 syslog(L_ERROR, "%s cant close %d %m", LogName, fd);
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);
683 NCwritereply(new, (char *)NCgreeting);
686 NCwritereply(new, (char *)NCgreeting);
689 } else if (AnyIncoming && !rp->Skip) {
690 if ((new = NCcreate(fd, false, false)) != NULL) {
691 NCwritereply(new, (char *)NCgreeting);
693 } else if (!innconf->noreader) {
694 RChandoff(fd, HOnntpd);
696 syslog(L_ERROR, "%s cant close %d %m", LogName, fd);
699 reject_val = NNTP_ACCESS_VAL;
700 reject_message = NNTP_ACCESS;
701 new = CHANcreate(fd, CTreject, CSwritegoodbye, RCrejectreader,
703 memcpy(&new->Address, &remote, SA_LEN((struct sockaddr *)&remote));
704 new->Rejected = reject_val;
706 WCHANset(new, reject_message, (int)strlen(reject_message));
707 WCHANappend(new, RCterm, strlen(RCterm));
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");
722 ** Write-done function. Shouldn't happen.
725 RCwritedone(CHANNEL *unused)
727 unused = unused; /* ARGSUSED */
728 syslog(L_ERROR, "%s internal RCwritedone", LogName);
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.
736 * Fabien Tassin <fta@sofaraway.org>, 21-Dec-1997.
741 * Read something (a word or a double quoted string) from a file.
744 RCreaddata(int *num, FILE *F, bool *toolong)
753 if (*RCbuff == '\0') {
754 if (feof (F)) return (NULL);
755 fgets(RCbuff, sizeof RCbuff, F);
757 if (strlen (RCbuff) == sizeof RCbuff) {
759 return (NULL); /* Line too long */
764 /* Ignore blank and comment lines. */
765 if ((p = strchr(RCbuff, '\n')) != NULL)
767 if ((p = strchr(RCbuff, '#')) != NULL) {
768 if (p == RCbuff || (p > RCbuff && *(p - 1) != '\\'))
771 for (p = RCbuff; *p == ' ' || *p == '\t' ; p++);
773 if (*p == '\0' && !feof (F)) {
775 fgets(RCbuff, sizeof RCbuff, F);
777 if (strlen (RCbuff) == sizeof RCbuff) {
779 return (NULL); /* Line too long */
784 } while (!feof (F) || !flag);
786 if (*p == '"') { /* double quoted string ? */
789 for (t = p; (*t != '"' || (*t == '"' && *(t - 1) == '\\')) &&
793 fgets(t, sizeof RCbuff - strlen (RCbuff), F);
795 if (strlen (RCbuff) == sizeof RCbuff) {
797 return (NULL); /* Line too long */
799 if ((s = strchr(t, '\n')) != NULL)
808 for (t = p; *t != ' ' && *t != '\t' && *t != '\0'; t++);
812 if (*p == '\0' && feof (F)) return (NULL);
814 for (p = RCbuff; *t != '\0'; t++)
822 * Add all data into RCpeerlistfile.
825 RCadddata(REMOTEHOST_DATA **d, int *count, int Key, int Type, char* Value)
827 (*d)[*count].key = Key;
828 (*d)[*count].type = Type;
829 (*d)[*count].value = Value;
831 *d = xrealloc(*d, (*count + 1) * sizeof(REMOTEHOST_DATA));
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.
840 RCreadfile (REMOTEHOST_DATA **data, REMOTEHOST **list, int *count,
843 static char NOPASS[] = "";
844 static char NOIDENTD[] = "";
845 static char NOEMAIL[] = "";
846 static char NOCOMMENT[] = "";
851 #if !defined( HAVE_INET6)
854 #if !defined(HAVE_UNIX_DOMAIN_SOCKETS) || !defined(HAVE_INET6)
867 REMOTEHOST *group_params = NULL;
868 REMOTEHOST peer_params;
869 REMOTEHOST default_params;
870 bool flag, bit, toolong;
874 for (rp = *list, i = *count; --i >= 0; rp++) {
882 free(rp->Patterns[0]);
891 for (i = 0; (*data)[i].key != K_END; i++)
892 if ((*data)[i].value != NULL)
893 free((*data)[i].value);
900 /* Open the server file. */
901 if ((F = Fopen(filename, "r", TEMPORARYOPEN)) == NULL) {
902 syslog(L_FATAL, "%s cant read %s: %m", LogName, filename);
905 dt = *data = xmalloc(sizeof(REMOTEHOST_DATA));
906 rp = *list = xmalloc(sizeof(REMOTEHOST));
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);
919 rp->Streaming = true;
921 rp->NoResendId = false;
926 #endif /* !defined(HAVE_UNIX_DOMAIN_SOCKETS) */
930 groupcount = 0; /* no group defined yet */
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;
946 /* Read the file to add all the hosts. */
947 while ((word = RCreaddata (&linecount, F, &toolong)) != NULL) {
950 if (!strncmp (word, GROUP, sizeof GROUP)) {
952 /* name of the group */
953 if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
954 syslog(L_ERROR, GROUP_NAME, LogName, filename, linecount);
957 RCadddata(data, &infocount, K_BEGIN_GROUP, T_STRING, word);
959 if (groupcount == 1) {
960 /* First group block. */
961 group_params = groups = xmalloc(sizeof(REMOTEHOST));
963 else if (groupcount >= maxgroup) {
964 /* Alloc 5 groups for extra nested group blocks. */
965 groups = xrealloc(groups, (groupcount + 4) * sizeof(REMOTEHOST));
967 group_params = groups + groupcount - 1;
970 /* Nested group block (no need to extend groups). */
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;
997 if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
998 syslog(L_ERROR, LEFT_BRACE, LogName, filename, linecount);
1002 if (strncmp (word, "{", 1)) {
1004 syslog(L_ERROR, LEFT_BRACE, LogName, filename, linecount);
1009 peer_params.Keysetbit = 0;
1014 if (!strncmp (word, PEER, sizeof PEER)) {
1016 if (peer_params.Label != NULL) {
1017 /* peer can't contain peer */
1018 syslog(L_ERROR, PEER_IN_PEER, LogName,
1019 filename, linecount);
1022 if ((word = RCreaddata (&linecount, F, &toolong)) == NULL)
1024 syslog(L_ERROR, PEER_NAME, LogName, filename, linecount);
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;
1054 peer_params.Keysetbit = 0;
1056 if ((word = RCreaddata (&linecount, F, &toolong)) == NULL)
1058 syslog(L_ERROR, LEFT_BRACE, LogName, filename, linecount);
1062 if (strncmp (word, "{", 1)) {
1063 syslog(L_ERROR, LEFT_BRACE, LogName, filename, linecount);
1073 if (!strncmp (word, "}", 1)) {
1075 if (peer_params.Label != NULL) {
1076 RCadddata(data, &infocount, K_END_PEER, T_STRING, NULL);
1078 /* Hostname defaults to label if not given */
1079 if (peer_params.Name == NULL)
1080 peer_params.Name = xstrdup(peer_params.Label);
1082 for(r = q = RCCommaSplit(xstrdup(peer_params.Name)); *q != NULL; q++) {
1084 struct addrinfo *res, *res0, hints;
1089 /* Grow the array */
1091 *list = xrealloc(*list, *count * sizeof(REMOTEHOST));
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. */
1105 /* Count the addresses and see if we have to grow the list */
1107 for (res = res0; res != NULL; res = res->ai_next)
1109 /* Grow the array */
1112 *list = xrealloc(*list, *count * sizeof(REMOTEHOST));
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;
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;
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. */
1165 /* Count the adresses and see if we have to grow the list */
1166 for (i = 0; hp->h_addr_list[i]; i++)
1169 syslog(L_ERROR, "%s no_address %s %m", LogName, *q);
1175 /* Strange DNS ? try this.. */
1176 for (rr = hp->h_aliases; *rr != 0; rr++) {
1177 if (!inet_aton(*rr, &addr))
1180 /* Grow the array */
1182 *list = xrealloc(*list, *count * sizeof(REMOTEHOST));
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;
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;
1225 /* Grow the array */
1228 *list = xrealloc(*list, *count * sizeof(REMOTEHOST));
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;
1251 #endif /* HAVE_INET6 */
1255 peer_params.Label = NULL;
1257 else if (groupcount > 0 && group_params->Label != NULL) {
1258 RCadddata(data, &infocount, K_END_GROUP, T_STRING, NULL);
1259 group_params->Label = NULL;
1261 if (groupcount == 0) {
1262 /* We are now outside a group block. */
1270 syslog(L_ERROR, RIGHT_BRACE, LogName, linecount, filename);
1276 if (!strncmp (word, STREAMING, sizeof STREAMING)) {
1278 TEST_CONFIG(K_STREAM, bit);
1280 syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
1283 if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
1286 if (!strcmp (word, "true"))
1289 if (!strcmp (word, "false"))
1292 syslog(L_ERROR, MUST_BE_BOOL, LogName, filename, linecount);
1295 RCadddata(data, &infocount, K_STREAM, T_STRING, word);
1296 if (peer_params.Label != NULL)
1297 peer_params.Streaming = flag;
1299 if (groupcount > 0 && group_params->Label != NULL)
1300 group_params->Streaming = flag;
1302 default_params.Streaming = flag;
1303 SET_CONFIG(K_STREAM);
1308 if (!strncmp (word, SKIP, sizeof SKIP)) {
1310 TEST_CONFIG(K_SKIP, bit);
1312 syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
1315 if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
1318 if (!strcmp (word, "true"))
1321 if (!strcmp (word, "false"))
1324 syslog(L_ERROR, MUST_BE_BOOL, LogName, filename, linecount);
1327 RCadddata(data, &infocount, K_SKIP, T_STRING, word);
1328 if (peer_params.Label != NULL)
1329 peer_params.Skip = flag;
1331 if (groupcount > 0 && group_params->Label != NULL)
1332 group_params->Skip = flag;
1334 default_params.Skip = flag;
1340 if (!strncmp (word, NORESENDID, sizeof NORESENDID)) {
1342 TEST_CONFIG(K_NORESENDID, bit);
1344 syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
1347 if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
1350 if (!strcmp (word, "true"))
1353 if (!strcmp (word, "false"))
1356 syslog(L_ERROR, MUST_BE_BOOL, LogName, filename, linecount);
1359 RCadddata(data, &infocount, K_NORESENDID, T_STRING, word);
1360 if (peer_params.Label != NULL)
1361 peer_params.NoResendId = flag;
1363 if (groupcount > 0 && group_params->Label != NULL)
1364 group_params->NoResendId = flag;
1366 default_params.NoResendId = flag;
1367 SET_CONFIG(K_NORESENDID);
1372 if (!strncmp (word, NOLIST, sizeof NOLIST)) {
1374 TEST_CONFIG(K_NOLIST, bit);
1376 syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
1379 if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
1382 if (!strcmp (word, "true"))
1385 if (!strcmp (word, "false"))
1388 syslog(L_ERROR, MUST_BE_BOOL, LogName, filename, linecount);
1391 RCadddata(data, &infocount, K_NOLIST, T_STRING, word);
1392 if (peer_params.Label != NULL)
1393 peer_params.Nolist = flag;
1395 if (groupcount > 0 && group_params->Label != NULL)
1396 group_params->Nolist = flag;
1398 default_params.Nolist = flag;
1399 SET_CONFIG(K_NOLIST);
1403 /* max-connections */
1404 if (!strncmp (word, MAX_CONN, sizeof MAX_CONN)) {
1407 TEST_CONFIG(K_MAX_CONN, bit);
1409 syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
1412 if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
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")) {
1421 syslog(L_ERROR, MUST_BE_INT, LogName, filename, linecount);
1426 if (peer_params.Label != NULL)
1427 peer_params.MaxCnx = max;
1429 if (groupcount > 0 && group_params->Label != NULL)
1430 group_params->MaxCnx = max;
1432 default_params.MaxCnx = max;
1433 SET_CONFIG(K_MAX_CONN);
1438 if (!strncmp (word, HOLD_TIME, sizeof HOLD_TIME)) {
1440 TEST_CONFIG(K_HOLD_TIME, bit);
1442 syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
1445 if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
1448 RCadddata(data, &infocount, K_HOLD_TIME, T_STRING, word);
1449 for (p = word; CTYPE(isdigit, *p) && *p != '\0'; p++);
1451 syslog(L_ERROR, MUST_BE_INT, LogName, filename, linecount);
1454 if (peer_params.Label != NULL)
1455 peer_params.HoldTime = atoi(word);
1457 if (groupcount > 0 && group_params->Label != NULL)
1458 group_params->HoldTime = atoi(word);
1460 default_params.HoldTime = atoi(word);
1461 SET_CONFIG(K_HOLD_TIME);
1466 if (!strncmp (word, HOSTNAME, sizeof HOSTNAME)) {
1468 TEST_CONFIG(K_HOSTNAME, bit);
1470 syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
1473 if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
1476 RCadddata(data, &infocount, K_HOSTNAME, T_STRING, word);
1477 peer_params.Name = word;
1478 SET_CONFIG(K_HOSTNAME);
1483 if (!strncmp (word, PASSWORD, sizeof PASSWORD)) {
1485 TEST_CONFIG(K_PASSWORD, bit);
1487 syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
1490 if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
1493 RCadddata(data, &infocount, K_PASSWORD, T_STRING, word);
1494 if (peer_params.Label != NULL)
1495 peer_params.Password = word;
1497 if (groupcount > 0 && group_params->Label != NULL)
1498 group_params->Password = word;
1500 default_params.Password = word;
1501 SET_CONFIG(K_PASSWORD);
1506 if (!strncmp (word, IDENTD, sizeof IDENTD)) {
1508 TEST_CONFIG(K_IDENTD, bit);
1510 syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
1513 if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
1516 RCadddata(data, &infocount, K_IDENTD, T_STRING, word);
1517 if (peer_params.Label != NULL)
1518 peer_params.Identd = word;
1520 if (groupcount > 0 && group_params->Label != NULL)
1521 group_params->Identd = word;
1523 default_params.Identd = word;
1524 SET_CONFIG(K_IDENTD);
1529 if (!strncmp (word, PATTERNS, sizeof PATTERNS)) {
1530 TEST_CONFIG(K_PATTERNS, bit);
1532 syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
1536 if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
1539 RCadddata(data, &infocount, K_PATTERNS, T_STRING, word);
1540 if (peer_params.Label != NULL)
1541 peer_params.Pattern = word;
1543 if (groupcount > 0 && group_params->Label != NULL)
1544 group_params->Pattern = word;
1546 default_params.Pattern = word;
1547 SET_CONFIG(K_PATTERNS);
1552 if (!strncmp (word, EMAIL, sizeof EMAIL)) {
1554 TEST_CONFIG(K_EMAIL, bit);
1556 syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
1559 if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
1562 RCadddata(data, &infocount, K_EMAIL, T_STRING, word);
1563 if (peer_params.Label != NULL)
1564 peer_params.Email = word;
1566 if (groupcount > 0 && group_params->Label != NULL)
1567 group_params->Email = word;
1569 default_params.Email = word;
1570 SET_CONFIG(K_EMAIL);
1575 if (!strncmp (word, COMMENT, sizeof COMMENT)) {
1577 TEST_CONFIG(K_COMMENT, bit);
1579 syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
1582 if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
1585 RCadddata(data, &infocount, K_COMMENT, T_STRING, word);
1586 if (peer_params.Label != NULL)
1587 peer_params.Comment = word;
1589 if (groupcount > 0 && group_params->Label != NULL)
1590 group_params->Comment = word;
1592 default_params.Comment = word;
1593 SET_CONFIG(K_COMMENT);
1598 syslog(L_ERROR, "%s line too long at %d: %s",
1599 LogName, --linecount, filename);
1601 syslog(L_ERROR, "%s Unknown value line %d: %s",
1602 LogName, linecount, filename);
1606 free(default_params.Email);
1607 free(default_params.Comment);
1608 RCadddata(data, &infocount, K_END, T_STRING, NULL);
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);
1619 syslog(L_ERROR, "%s Syntax error in %s at or before line %d", LogName,
1620 filename, linecount);
1622 if (Fclose(F) == EOF)
1623 syslog(L_ERROR, "%s cant fclose %s %m", LogName, filename);
1625 free(default_params.Password);
1626 free(default_params.Identd);
1631 ** Indent a line with 3 * c blanks.
1632 ** Used by RCwritelist().
1635 RCwritelistindent(FILE *F, int c)
1639 for (i = 0; i < c; i++)
1644 ** Add double quotes around a string, if needed.
1645 ** Used by RCwritelist().
1648 RCwritelistvalue(FILE *F, char *value)
1650 if (*value == '\0' || strchr (value, '\n') ||
1651 strchr (value, ' ') || strchr (value, '\t'))
1652 fprintf(F, "\"%s\"", value);
1654 fprintf(F, "%s", value);
1658 ** Write the incoming configuration (memory->disk)
1661 RCwritelist(char *filename)
1670 if ((F = Fopen(filename, "w", TEMPORARYOPEN)) == NULL) {
1671 syslog(L_FATAL, "%s cant write %s: %m", LogName, filename);
1675 /* Write a standard header.. */
1677 /* Find the filename */
1678 p = concatpath(innconf->pathetc, _PATH_INNDHOSTS);
1679 for (r = q = p; *p; p++)
1683 fprintf (F, "## $Revision: 7751 $\n");
1684 fprintf (F, "## %s - names and addresses that feed us news\n", q);
1686 fprintf (F, "##\n\n");
1691 for (i = 0; RCpeerlistfile[i].key != K_END; i++) {
1692 switch (RCpeerlistfile[i].key) {
1695 RCwritelistindent (F, inc);
1696 fprintf(F, "%s %s {\n", PEER, RCpeerlistfile[i].value);
1701 RCwritelistindent (F, inc);
1702 fprintf(F, "%s %s {\n", GROUP, RCpeerlistfile[i].value);
1708 RCwritelistindent (F, inc);
1712 RCwritelistindent (F, inc);
1713 fprintf(F, "%s\t", STREAMING);
1714 RCwritelistvalue (F, RCpeerlistfile[i].value);
1718 RCwritelistindent (F, inc);
1719 fprintf(F, "%s\t", SKIP);
1720 RCwritelistvalue (F, RCpeerlistfile[i].value);
1724 RCwritelistindent (F, inc);
1725 fprintf(F, "%s\t", NORESENDID);
1726 RCwritelistvalue (F, RCpeerlistfile[i].value);
1730 RCwritelistindent (F, inc);
1731 fprintf(F, "%s\t", NOLIST);
1732 RCwritelistvalue (F, RCpeerlistfile[i].value);
1736 RCwritelistindent (F, inc);
1737 fprintf(F, "%s\t", HOSTNAME);
1738 RCwritelistvalue (F, RCpeerlistfile[i].value);
1742 RCwritelistindent (F, inc);
1743 fprintf(F, "%s\t", MAX_CONN);
1744 RCwritelistvalue (F, RCpeerlistfile[i].value);
1748 RCwritelistindent (F, inc);
1749 fprintf(F, "%s\t", HOLD_TIME);
1750 RCwritelistvalue (F, RCpeerlistfile[i].value);
1754 RCwritelistindent (F, inc);
1755 fprintf(F, "%s\t", PASSWORD);
1756 RCwritelistvalue (F, RCpeerlistfile[i].value);
1760 RCwritelistindent (F, inc);
1761 fprintf(F, "%s\t", IDENTD);
1762 RCwritelistvalue (F, RCpeerlistfile[i].value);
1766 RCwritelistindent (F, inc);
1767 fprintf(F, "%s\t", EMAIL);
1768 RCwritelistvalue (F, RCpeerlistfile[i].value);
1772 RCwritelistindent (F, inc);
1773 fprintf(F, "%s\t", PATTERNS);
1774 RCwritelistvalue (F, RCpeerlistfile[i].value);
1778 RCwritelistindent (F, inc);
1779 fprintf(F, "%s\t", COMMENT);
1780 RCwritelistvalue (F, RCpeerlistfile[i].value);
1784 fprintf(F, "# ***ERROR***\n");
1787 if (Fclose(F) == EOF)
1788 syslog(L_ERROR, "%s cant fclose %s %m", LogName, filename);
1795 static char *INNDHOSTS = NULL;
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"); */
1805 ** Find the name of a remote host we've connected to.
1808 RChostname(const CHANNEL *cp)
1810 static char buff[SMBUF];
1814 for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++)
1815 if (RCaddressmatch(&cp->Address, &rp->Address))
1817 strlcpy(buff, sprint_sockaddr((struct sockaddr *)&cp->Address),
1823 ** Find the label name of a remote host we've connected to.
1826 RClabelname(CHANNEL *cp) {
1830 for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++) {
1831 if (RCaddressmatch(&cp->Address, &rp->Address))
1838 ** Is the remote site allowed to post to this group?
1841 RCcanpost(CHANNEL *cp, char *group)
1850 /* Connections from lc.c are from local nnrpd and should always work */
1851 if (cp->Address.ss_family == 0)
1854 for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++) {
1855 if (!RCaddressmatch(&cp->Address, &rp->Address))
1857 if (rp->Patterns == NULL)
1859 for (match = 0, argv = rp->Patterns; (pat = *argv++) != NULL; ) {
1860 subvalue = (*pat != SUB_NEGATE) && (*pat != SUB_POISON) ?
1864 if ((match != subvalue) && uwildmat(group, pat)) {
1865 if (subvalue == SUB_POISON)
1877 ** Create the channel.
1882 #if defined(SO_REUSEADDR)
1884 #endif /* defined(SO_REUSEADDR) */
1888 /* This code is called only when inndstart is not being used */
1891 syslog(L_FATAL, "%s innd MUST be started with inndstart", LogName);
1894 /* Create a socket and name it. */
1895 struct sockaddr_in server;
1897 if ((i = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
1898 syslog(L_FATAL, "%s cant socket RCreader %m", LogName);
1901 #if defined(SO_REUSEADDR)
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 );
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);
1920 if (bind(i, (struct sockaddr *)&server, sizeof server) < 0) {
1921 syslog(L_FATAL, "%s cant bind RCreader %m", LogName);
1924 #endif /* HAVE_INET6 */
1927 /* Set it up to wait for connections. */
1928 if (listen(i, MAXLISTEN) < 0) {
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)
1938 rcchan = CHANcreate(i, CTremconn, CSwaiting, RCreader, RCwritedone);
1939 syslog(L_NOTICE, "%s rcsetup %s", LogName, CHANname(rcchan));
1942 for (j = 0 ; j < chanlimit ; j++ ) {
1943 if (RCchan[j] == NULL) {
1947 if (j < chanlimit) {
1949 } else if (chanlimit == 0) {
1950 /* assuming two file descriptors(AF_INET and AF_INET6) */
1952 RCchan = xmalloc(chanlimit * sizeof(CHANNEL **));
1953 for (j = 0 ; j < chanlimit ; j++ ) {
1958 /* extend to double size */
1959 RCchan = xrealloc(RCchan, chanlimit * 2 * sizeof(CHANNEL **));
1960 for (j = chanlimit ; j < chanlimit * 2 ; j++ ) {
1963 RCchan[chanlimit] = rcchan;
1967 /* Get the list of hosts we handle. */
1973 ** Cleanly shut down the channel.
1981 for (i = 0 ; i < chanlimit ; i++) {
1982 if (RCchan[i] != NULL) {
1983 CHANclose(RCchan[i], CHANname(RCchan[i]));
1993 for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++) {
2001 free(rp->Patterns[0]);
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;