+++ /dev/null
-/* $Id: rc.c 7751 2008-04-06 14:35:40Z iulius $
-**
-** Routines for the remote connect channel. Create an Internet stream
-** socket that processes connect to. If the incoming site is not one of
-** our feeds, then we optionally pass the connection off to the standard
-** NNTP daemon.
-*/
-#include "config.h"
-#include "clibrary.h"
-#include "portable/socket.h"
-#include <errno.h>
-#include <netdb.h>
-
-#include "inn/innconf.h"
-#include "inn/vector.h"
-#include "innd.h"
-
-#define TEST_CONFIG(a, b) \
- { \
- b = ((peer_params.Keysetbit & (1 << a)) != 0) ? true : false; \
- }
-
-#define SET_CONFIG(a) \
- { \
- peer_params.Keysetbit |= (1 << a); \
- }
-
-/*
-** A remote host has an address and a password.
-*/
-typedef struct _REMOTEHOST {
- char *Label; /* Peer label */
- char *Name; /* Hostname */
- struct sockaddr_storage Address; /* List of ip adresses */
- char *Password; /* Optional password */
- char *Identd; /* Optional identd */
- bool Streaming; /* Streaming allowed ? */
- bool Skip; /* Skip this peer ? */
- bool NoResendId; /* Don't send RESEND responses ? */
- bool Nolist; /* no list command allowed */
- int MaxCnx; /* Max connections (per peer) */
- char **Patterns; /* List of groups allowed */
- char *Pattern; /* List of groups allowed (string) */
- char *Email; /* Email(s) of contact */
- char *Comment; /* Commentary [max size = MAXBUFF] */
- int HoldTime; /* Hold time before disconnect over MaxCnx */
- int Keysetbit; /* Bit to check duplicated key */
-} REMOTEHOST;
-
-typedef struct _REMOTEHOST_DATA {
- int key; /* Key (as defined in the _Keywords enum) */
- int type; /* Type of the value (see _Type enum) */
- char *value; /* Value */
-} REMOTEHOST_DATA;
-
-typedef struct _REMOTETABLE {
- struct sockaddr_storage Address;
- time_t Expires;
-} REMOTETABLE;
-
-static char *RCslaveflag;
-static char *RCnnrpd = NULL;
-static char *RCnntpd = NULL;
-static CHANNEL **RCchan;
-static int chanlimit;
-static REMOTEHOST_DATA *RCpeerlistfile;
-static REMOTEHOST *RCpeerlist;
-static int RCnpeerlist;
-static char RCbuff[BIG_BUFFER];
-
-#define PEER "peer"
-#define GROUP "group"
-#define HOSTNAME "hostname:"
-#define STREAMING "streaming:"
-#define MAX_CONN "max-connections:"
-#define PASSWORD "password:"
-#define IDENTD "identd:"
-#define PATTERNS "patterns:"
-#define EMAIL "email:"
-#define COMMENT "comment:"
-#define SKIP "skip:"
-#define NORESENDID "noresendid:"
-#define HOLD_TIME "hold-time:"
-#define NOLIST "nolist:"
-
-typedef enum {K_END, K_BEGIN_PEER, K_BEGIN_GROUP, K_END_PEER, K_END_GROUP,
- K_STREAM, K_HOSTNAME, K_MAX_CONN, K_PASSWORD, K_IDENTD,
- K_EMAIL, K_PATTERNS, K_COMMENT, K_SKIP, K_NORESENDID,
- K_HOLD_TIME, K_NOLIST
- } _Keywords;
-
-typedef enum {T_STRING, T_BOOLEAN, T_INTEGER} _Types;
-
-#define GROUP_NAME "%s can't get group name in %s line %d"
-#define PEER_IN_PEER "%s peer can't contain peer in %s line %d"
-#define PEER_NAME "%s can't get peer name in %s line %d"
-#define LEFT_BRACE "%s '{' expected in %s line %d"
-#define RIGHT_BRACE "%s '}' unexpected line %d in %s"
-#define INCOMPLETE_PEER "%s incomplete peer (%s) in %s line %d"
-#define INCOMPLETE_GROUP "%s incomplete group (%s) in %s line %d"
-#define MUST_BE_BOOL "%s Must be 'true' or 'false' in %s line %d"
-#define MUST_BE_INT "%s Must be an integer value in %s line %d"
-#define HOST_NEEDED "%s 'hostname' needed in %s line %d"
-#define DUPLICATE_KEY "%s duplicate key in %s line %d"
-
-/*
-** Stuff needed for limiting incoming connects.
-*/
-static char RCterm[] = "\r\n";
-static REMOTETABLE remotetable[REMOTETABLESIZE];
-static int remotecount;
-static int remotefirst;
-
-/*
- * Check that the client has the right identd. Return true if is the
- * case, false, if not.
- */
-static bool
-GoodIdent(int fd, char *identd)
-{
-#define PORT_IDENTD 113
- char IDENTuser[80];
- struct sockaddr_storage ss_local;
- struct sockaddr_storage ss_distant;
- struct sockaddr *s_local = (struct sockaddr *)&ss_local;
- struct sockaddr *s_distant = (struct sockaddr *)&ss_distant;
- int ident_fd;
- socklen_t len;
- int port1,port2;
- ssize_t lu;
- char buf[80], *buf2;
-
- if(identd[0] == '\0') {
- return true;
- }
-
- len = sizeof( ss_local );
- if ((getsockname(fd,s_local,&len)) < 0) {
- syslog(L_ERROR, "can't do getsockname for identd");
- return false;
- }
- len = sizeof( ss_distant );
- if ((getpeername(fd,s_distant,&len)) < 0) {
- syslog(L_ERROR, "can't do getsockname for identd");
- return false;
- }
-#ifdef HAVE_INET6
- if( s_local->sa_family == AF_INET6 )
- {
- struct sockaddr_in6 *s_l6 = (struct sockaddr_in6 *)s_local;
- struct sockaddr_in6 *s_d6 = (struct sockaddr_in6 *)s_distant;
-
- port1=ntohs(s_l6->sin6_port);
- port2=ntohs(s_d6->sin6_port);
- s_l6->sin6_port = 0;
- s_d6->sin6_port = htons( PORT_IDENTD );
- ident_fd=socket(PF_INET6, SOCK_STREAM, 0);
- } else
-#endif
- if( s_local->sa_family == AF_INET )
- {
- struct sockaddr_in *s_l = (struct sockaddr_in *)s_local;
- struct sockaddr_in *s_d = (struct sockaddr_in *)s_distant;
-
- port1=ntohs(s_l->sin_port);
- port2=ntohs(s_d->sin_port);
- s_l->sin_port = 0;
- s_d->sin_port = htons( PORT_IDENTD );
- ident_fd=socket(PF_INET, SOCK_STREAM, 0);
- } else
- {
- syslog(L_ERROR, "Bad address family: %d\n", s_local->sa_family );
- return false;
- }
- if (ident_fd < 0) {
- syslog(L_ERROR, "can't open socket for identd (%m)");
- return false;
- }
- if (bind(ident_fd,s_local,SA_LEN(s_local)) < 0) {
- syslog(L_ERROR, "can't bind socket for identd (%m)");
- close(ident_fd);
- return false;
- }
- if (connect(ident_fd,s_distant,SA_LEN(s_distant)) < 0) {
- syslog(L_ERROR, "can't connect to identd (%m)");
- close(ident_fd);
- return false;
- }
-
- snprintf(buf,sizeof(buf),"%d,%d\r\n",port2, port1);
- write(ident_fd,buf, strlen(buf));
- memset( buf, 0, 80 );
- lu=read(ident_fd, buf, 79); /* pas encore parfait ("not yet perfect"?) */
- if (lu<0)
- {
- syslog(L_ERROR, "error reading from ident server: %m" );
- close( ident_fd );
- return false;
- }
- buf[lu]='\0';
- if ((lu>0) && (strstr(buf,"ERROR")==NULL)
- && ((buf2=strrchr(buf,':'))!=NULL))
- {
- buf2++;
- while(*buf2 == ' ') buf2++;
- strlcpy(IDENTuser, buf2, sizeof(IDENTuser));
- buf2=strchr(IDENTuser,'\r');
- if (!buf2) buf2=strchr(IDENTuser,'\n');
- if (buf2) *buf2='\0';
- } else
- strlcpy(IDENTuser, "UNKNOWN", sizeof(IDENTuser));
- close(ident_fd);
-
- return strcmp(identd, IDENTuser) == 0;
-}
-
-/*
- * Split text into comma-separated fields. Return an allocated
- * NULL-terminated array of the fields within the modified argument that
- * the caller is expected to save or free. We don't use strchr() since
- * the text is expected to be either relatively short or "comma-dense."
- * (This function is different from CommaSplit because spaces are allowed
- * and removed here)
- */
-
-static char **
-RCCommaSplit(char *text)
-{
- int i;
- char *p;
- char *q;
- char *r;
- char **av;
- char **save;
-
- /* How much space do we need? */
- for (i = 2, p = text, q = r = xstrdup(text); *p; p++) {
- if (*p != ' ' && *p != '\t' && *p != '\n')
- *q++ = *p;
- if (*p == ',')
- i++;
- }
- *q = '\0';
- free (text);
- for (text = r, av = save = xmalloc(i * sizeof(char *)), *av++ = p = text; *p; )
- if (*p == ',') {
- *p++ = '\0';
- *av++ = p;
- }
- else
- p++;
- *av = NULL;
- return save;
-}
-
- /*
- * Routine to disable IP-level socket options. This code was taken from 4.4BSD
- * rlogind source, but all mistakes in it are my fault.
- *
- * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
- *
- * 21-Jan-1997 smd
- * Code copied again, and modified for INN, all new mistakes are mine.
- *
- */
-
-/* fix_options - get rid of IP-level socket options */
-#ifndef IP_OPTIONS
-#define IP_OPTIONS 1
-#endif
-
-static int
-RCfix_options(int fd, struct sockaddr_storage *remote)
-{
-#if IP_OPTIONS
- unsigned char optbuf[BUFSIZ / 3], *cp;
- char lbuf[BUFSIZ], *lp;
- socklen_t optsize = sizeof(optbuf);
- int ipproto;
- struct protoent *ip;
-
- switch (remote->ss_family) {
- case AF_INET:
- if ((ip = getprotobyname("ip")) != 0)
- ipproto = ip->p_proto;
- else
- ipproto = IPPROTO_IP;
- break;
-#ifdef HAVE_INET6
- case AF_INET6:
- if ((ip = getprotobyname("ipv6")) != 0)
- ipproto = ip->p_proto;
- else
- ipproto = IPPROTO_IPV6;
- break;
-#endif
- default:
- syslog(LOG_ERR, "unknown address family: %d", remote->ss_family);
- return -1;
- }
-
- if (getsockopt(fd, ipproto, IP_OPTIONS, (char *) optbuf, &optsize) == 0
- && optsize != 0) {
- lp = lbuf;
- for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3)
- sprintf(lp, " %2.2x", *cp);
- syslog(LOG_NOTICE,
- "connect from %s with IP options (ignored):%s",
- sprint_sockaddr((struct sockaddr *)remote), lbuf);
- if (setsockopt(fd, ipproto, IP_OPTIONS, (char *) 0, optsize) != 0) {
- syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m");
- return -1;
- }
- }
-#endif
- return 0;
-}
-
-static bool
-RCaddressmatch(const struct sockaddr_storage *cp, const struct sockaddr_storage *rp)
-{
-#ifdef HAVE_INET6
- struct sockaddr_in *sin_cp, *sin_rp;
- struct sockaddr_in6 *sin6_cp, *sin6_rp;
-
- if (cp->ss_family == AF_INET6 && rp->ss_family == AF_INET) {
- sin6_cp = (struct sockaddr_in6 *)cp;
- sin_rp = (struct sockaddr_in *)rp;
- if (IN6_IS_ADDR_V4MAPPED(&sin6_cp->sin6_addr) &&
- memcmp(&sin6_cp->sin6_addr.s6_addr[12],
- &sin_rp->sin_addr.s_addr, sizeof(struct in_addr)) == 0)
- return true;
- } else if (cp->ss_family == AF_INET && rp->ss_family == AF_INET6) {
- sin_cp = (struct sockaddr_in *)cp;
- sin6_rp = (struct sockaddr_in6 *)rp;
- if (IN6_IS_ADDR_V4MAPPED(&sin6_rp->sin6_addr) &&
- memcmp(&sin6_rp->sin6_addr.s6_addr[12],
- &sin_cp->sin_addr.s_addr, sizeof(struct in_addr)) == 0)
- return true;
- } else if (cp->ss_family == AF_INET6 && rp->ss_family == AF_INET6) {
-#ifdef HAVE_BROKEN_IN6_ARE_ADDR_EQUAL
- if (!memcmp(&((struct sockaddr_in6 *)cp)->sin6_addr,
- &((struct sockaddr_in6 *)rp)->sin6_addr,
- sizeof(struct in6_addr)))
-#else
- if (IN6_ARE_ADDR_EQUAL( &((struct sockaddr_in6 *)cp)->sin6_addr,
- &((struct sockaddr_in6 *)rp)->sin6_addr))
-#endif
- return true;
- } else
-#endif /* INET6 */
- if (((struct sockaddr_in *)cp)->sin_addr.s_addr ==
- ((struct sockaddr_in *)rp)->sin_addr.s_addr)
- return true;
-
- return false;
-}
-
-/*
-** See if the site properly entered the password.
-*/
-bool
-RCauthorized(CHANNEL *cp, char *pass)
-{
- REMOTEHOST *rp;
- int i;
-
- for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++)
- if (RCaddressmatch(&cp->Address, &rp->Address)) {
- if (rp->Password[0] == '\0' || strcmp(pass, rp->Password) == 0)
- return true;
- syslog(L_ERROR, "%s (%s) bad_auth", rp->Label,
- sprint_sockaddr((struct sockaddr *)&cp->Address));
- return false;
- }
-
- if (!AnyIncoming)
- /* Not found in our table; this can't happen. */
- syslog(L_ERROR, "%s not_found", sprint_sockaddr((struct sockaddr *)&cp->Address));
-
- /* Anonymous hosts should not authenticate. */
- return false;
-}
-
-/*
-** See if a host is limited or not.
-*/
-bool
-RCnolimit(CHANNEL *cp)
-{
- REMOTEHOST *rp;
- int i;
-
- for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++)
- if (RCaddressmatch(&cp->Address, &rp->Address))
- return !rp->MaxCnx;
-
- /* Not found in our table; this can't happen. */
- return false;
-}
-
-/*
-** Return the limit (max number of connections) for a host.
-*/
-int
-RClimit(CHANNEL *cp)
-{
- REMOTEHOST *rp;
- int i;
-
- for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++)
- if (RCaddressmatch(&cp->Address, &rp->Address))
- return rp->MaxCnx;
- /* Not found in our table; this can't happen. */
- return RemoteLimit;
-}
-
-
-/*
-** Called when input is ready to read. Shouldn't happen.
-*/
-static void
-RCrejectreader(CHANNEL *cp)
-{
- syslog(L_ERROR, "%s internal RCrejectreader (%s)", LogName,
- sprint_sockaddr((struct sockaddr *)&cp->Address));
-}
-
-
-/*
-** Write-done function for rejects.
-*/
-static void
-RCrejectwritedone(CHANNEL *cp)
-{
- switch (cp->State) {
- default:
- syslog(L_ERROR, "%s internal RCrejectwritedone state %d",
- CHANname(cp), cp->State);
- break;
- case CSwritegoodbye:
- CHANclose(cp, CHANname(cp));
- break;
- }
-}
-
-
-/*
-** Hand off a descriptor to NNRPD.
-*/
-void
-RChandoff(int fd, HANDOFF h)
-{
- const char **argv;
- char buff[SMBUF];
- int i;
- unsigned int j;
- struct vector *flags;
-
- flags = vector_split_space(innconf->nnrpdflags, NULL);
- argv = xmalloc( (flags->count + 6) * sizeof(char*) );
-
- if (RCnnrpd == NULL)
- RCnnrpd = concatpath(innconf->pathbin, "nnrpd");
- if (RCnntpd == NULL)
- RCnntpd = concatpath(innconf->pathbin, "nnrpd");
-#if defined(SOL_SOCKET) && defined(SO_KEEPALIVE)
- /* Set KEEPALIVE to catch broken socket connections. */
- i = 1;
- if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&i, sizeof i) < 0)
- syslog(L_ERROR, "fd %d cant setsockopt(KEEPALIVE) %m", fd);
-#endif /* defined(SOL_SOCKET) && defined(SO_KEEPALIVE) */
-
- if (nonblocking(fd, false) < 0)
- syslog(L_ERROR, "%s cant nonblock %d in RChandoff %m", LogName, fd);
- switch (h) {
- default:
- syslog(L_ERROR, "%s internal RChandoff %d type %d", LogName, fd, h);
- /* FALLTHROUGH */
- case HOnnrpd: argv[0] = RCnnrpd; break;
- case HOnntpd: argv[0] = RCnntpd; break;
- }
- argv[1] = "-s ";
- i = 2;
- if (NNRPReason) {
- snprintf(buff, sizeof(buff), "-r%s", NNRPReason);
- argv[i++] = buff;
- }
- if (NNRPTracing)
- argv[i++] = "-t";
- if (RCslaveflag)
- argv[i++] = RCslaveflag;
-
- for(j = 0; j < flags->count; j++) {
- argv[i++] = flags->strings[j];
- }
- argv[i] = NULL;
-
- /* Call NNRP; don't send back a QUIT message if Spawn fails since
- * that's a major error we want to find out about quickly. */
- (void)Spawn(innconf->nicekids, fd, fd, fd, (char * const *)argv);
- vector_free(flags);
- free(argv);
-}
-
-
-/*
-** Read function. Accept the connection and either create an NNTP channel
-** or spawn an nnrpd to handle it.
-*/
-static void
-RCreader(CHANNEL *cp)
-{
- int fd;
- struct sockaddr_storage remote;
- socklen_t size;
- int i;
- REMOTEHOST *rp;
- CHANNEL *new;
- char *name;
- long reject_val = 0;
- const char *reject_message;
- int count;
- int found;
- time_t now;
- CHANNEL tempchan;
- char buff[SMBUF];
-
- for (i = 0 ; i < chanlimit ; i++) {
- if (RCchan[i] == cp) {
- break;
- }
- }
- if (i == chanlimit) {
- syslog(L_ERROR, "%s internal RCreader wrong channel 0x%p",
- LogName, (void *)cp);
- return;
- }
-
- /* Get the connection. */
- size = sizeof remote;
- if ((fd = accept(cp->fd, (struct sockaddr *)&remote, &size)) < 0) {
- if (errno != EWOULDBLOCK && errno != EAGAIN)
- syslog(L_ERROR, "%s cant accept RCreader %m", LogName);
- return;
- }
-
- /*
- ** Clear any IP_OPTIONS, including source routing, on the socket
- */
- /* FIXME RCfix_options breaks IPv6 sockets, at least on Linux -lutchann */
-#ifndef HAVE_INET6
- if (RCfix_options(fd, &remote) != 0) {
- /* shouldn't happen, but we're bit paranoid at this point */
- if (close(fd) < 0)
- syslog(L_ERROR, "%s cant close %d %m", LogName, fd);
- return;
- }
-#endif
-
- /* If RemoteTimer is not zero, then check the limits on incoming
- connections on a total and per host basis.
-
- The incoming connection table is fixed at 128 entries to make
- calculating the index easy (i + 1) & 7, and to be pretty sure that you
- won't run out of space. The table is used as a ring with new entries
- being added to the end (wrapping around) and expired entries being
- deleted from the front (again wrapping around). It is doubtful that
- you will ever use even half of the table.
-
- There are three parameters controlling the use of the table not
- counting the starting index and count:
-
- H = per host incoming connects per X seconds allowed
- T = total incoming connects per X seconds allowed
- X = number of seconds to remember a successful connect
-
- First, one pass is made over the live entries deleting any that are
- over X seconds old. If the entry hasn't expired, compare the incoming
- connection's host address with the entry's host address. If equal,
- increment the "found" counter.
-
- Second, if the number of entries now in the table is equal to the T
- parameter, reject the connection with a message indicating that the
- server is overloaded.
-
- Third, if the number of entries now in the table which match the
- incoming connection's host address is equal to the H parameter, reject
- the connection.
-
- Finally, if neither rejection happened, add the entry to the table, and
- continue on as a normal connect. */
- memcpy(&tempchan.Address, &remote, SA_LEN((struct sockaddr *)&remote));
- reject_message = NULL;
- if (RemoteTimer != 0) {
- now = time(NULL);
- i = remotefirst;
- count = remotecount;
- found = 0;
- while (count--) {
- if (remotetable[i].Expires < now) {
- remotecount--;
- remotefirst = (remotefirst + 1) & (REMOTETABLESIZE - 1);
- i = (i + 1) & (REMOTETABLESIZE - 1);
- continue;
- }
- if (RCaddressmatch(&remotetable[i].Address, &remote))
- found++;
- i = (i + 1) & (REMOTETABLESIZE - 1);
- }
- if (remotecount == RemoteTotal) {
- reject_val = NNTP_GOODBYE_VAL;
- reject_message = "400 Server overloaded, try later";
- }
- else if (found >= RemoteLimit && !RCnolimit(&tempchan)) {
- reject_val = NNTP_GOODBYE_VAL;
- reject_message = "400 Connection rejected, you're making too"
- " many connects per minute";
- }
- else {
- i = (remotefirst + remotecount) & (REMOTETABLESIZE - 1);
- memcpy(&remotetable[i].Address, &remote, SA_LEN((struct sockaddr *)&remote));
- remotetable[i].Expires = now + RemoteTimer;
- remotecount++;
- }
- }
-
- /*
- ** Create a reject channel to reject the connection. This is done
- ** to avoid a call to fork.
- */
- if (reject_message) {
- new = CHANcreate(fd, CTreject, CSwritegoodbye, RCrejectreader,
- RCrejectwritedone);
- memcpy(&remotetable[i].Address, &remote, SA_LEN((struct sockaddr *)&remote));
- new->Rejected = reject_val;
- RCHANremove(new);
- WCHANset(new, reject_message, (int)strlen(reject_message));
- WCHANappend(new, RCterm, strlen(RCterm));
- WCHANadd(new);
- return;
- }
-
- /* See if it's one of our servers. */
- for (name = NULL, rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++)
- if (RCaddressmatch(&rp->Address, &remote)) {
- name = rp->Name;
- break;
- }
-
- /* If not a server, and not allowing anyone, hand him off unless
- not spawning nnrpd in which case we return an error. */
- if ((i >= 0) && !rp->Skip) {
-
- /* We check now the identd if we have to */
- if(! GoodIdent(fd, rp->Identd))
- {
- if (!innconf->noreader) {
- RChandoff(fd, HOnntpd);
- if (close(fd) < 0)
- syslog(L_ERROR, "%s cant close %d %m", LogName, fd);
- return;
- }
- }
-
- if ((new = NCcreate(fd, rp->Password[0] != '\0', false)) != NULL) {
- new->Streaming = rp->Streaming;
- new->Skip = rp->Skip;
- new->NoResendId = rp->NoResendId;
- new->Nolist = rp->Nolist;
- new->MaxCnx = rp->MaxCnx;
- new->HoldTime = rp->HoldTime;
- memcpy(&new->Address, &remote, SA_LEN((struct sockaddr *)&remote));
- if (new->MaxCnx > 0 && new->HoldTime == 0) {
- CHANsetActiveCnx(new);
- if((new->ActiveCnx > new->MaxCnx) && (new->fd > 0)) {
- snprintf(buff, sizeof(buff),
- "You are limited to %d connection%s",
- new->MaxCnx, (new->MaxCnx != 1) ? "s" : "");
- NCwriteshutdown(new, buff);
- syslog(L_NOTICE, "too many connections from %s", rp->Label);
- } else {
- NCwritereply(new, (char *)NCgreeting);
- }
- } else {
- NCwritereply(new, (char *)NCgreeting);
- }
- }
- } else if (AnyIncoming && !rp->Skip) {
- if ((new = NCcreate(fd, false, false)) != NULL) {
- NCwritereply(new, (char *)NCgreeting);
- }
- } else if (!innconf->noreader) {
- RChandoff(fd, HOnntpd);
- if (close(fd) < 0)
- syslog(L_ERROR, "%s cant close %d %m", LogName, fd);
- return;
- } else {
- reject_val = NNTP_ACCESS_VAL;
- reject_message = NNTP_ACCESS;
- new = CHANcreate(fd, CTreject, CSwritegoodbye, RCrejectreader,
- RCrejectwritedone);
- memcpy(&new->Address, &remote, SA_LEN((struct sockaddr *)&remote));
- new->Rejected = reject_val;
- RCHANremove(new);
- WCHANset(new, reject_message, (int)strlen(reject_message));
- WCHANappend(new, RCterm, strlen(RCterm));
- WCHANadd(new);
- return;
- }
-
- if (new != NULL) {
- memcpy(&new->Address, &remote, SA_LEN((struct sockaddr *)&remote));
- syslog(L_NOTICE, "%s connected %d streaming %s",
- name ? name : sprint_sockaddr((struct sockaddr *)&new->Address),
- new->fd, (!StreamingOff && new->Streaming) ? "allowed" : "not allowed");
- }
-}
-
-
-/*
-** Write-done function. Shouldn't happen.
-*/
-static void
-RCwritedone(CHANNEL *unused)
-{
- unused = unused; /* ARGSUSED */
- syslog(L_ERROR, "%s internal RCwritedone", LogName);
-}
-
-/*
- * New config file style. Old hosts.nntp and hosts.nntp.nolimit are merged
- * into one file called incoming.conf (to avoid confusion).
- * See ../samples/incoming.conf for the new syntax.
- *
- * Fabien Tassin <fta@sofaraway.org>, 21-Dec-1997.
- */
-
-
-/*
- * Read something (a word or a double quoted string) from a file.
- */
-static char *
-RCreaddata(int *num, FILE *F, bool *toolong)
-{
- char *p;
- char *s;
- char *t;
- char *word;
- bool flag;
-
- *toolong = false;
- if (*RCbuff == '\0') {
- if (feof (F)) return (NULL);
- fgets(RCbuff, sizeof RCbuff, F);
- (*num)++;
- if (strlen (RCbuff) == sizeof RCbuff) {
- *toolong = true;
- return (NULL); /* Line too long */
- }
- }
- p = RCbuff;
- do {
- /* Ignore blank and comment lines. */
- if ((p = strchr(RCbuff, '\n')) != NULL)
- *p = '\0';
- if ((p = strchr(RCbuff, '#')) != NULL) {
- if (p == RCbuff || (p > RCbuff && *(p - 1) != '\\'))
- *p = '\0';
- }
- for (p = RCbuff; *p == ' ' || *p == '\t' ; p++);
- flag = true;
- if (*p == '\0' && !feof (F)) {
- flag = false;
- fgets(RCbuff, sizeof RCbuff, F);
- (*num)++;
- if (strlen (RCbuff) == sizeof RCbuff) {
- *toolong = true;
- return (NULL); /* Line too long */
- }
- continue;
- }
- break;
- } while (!feof (F) || !flag);
-
- if (*p == '"') { /* double quoted string ? */
- p++;
- do {
- for (t = p; (*t != '"' || (*t == '"' && *(t - 1) == '\\')) &&
- *t != '\0'; t++);
- if (*t == '\0') {
- *t++ = '\n';
- fgets(t, sizeof RCbuff - strlen (RCbuff), F);
- (*num)++;
- if (strlen (RCbuff) == sizeof RCbuff) {
- *toolong = true;
- return (NULL); /* Line too long */
- }
- if ((s = strchr(t, '\n')) != NULL)
- *s = '\0';
- }
- else
- break;
- } while (!feof (F));
- *t++ = '\0';
- }
- else {
- for (t = p; *t != ' ' && *t != '\t' && *t != '\0'; t++);
- if (*t != '\0')
- *t++ = '\0';
- }
- if (*p == '\0' && feof (F)) return (NULL);
- word = xstrdup (p);
- for (p = RCbuff; *t != '\0'; t++)
- *p++ = *t;
- *p = '\0';
-
- return (word);
-}
-
-/*
- * Add all data into RCpeerlistfile.
- */
-static void
-RCadddata(REMOTEHOST_DATA **d, int *count, int Key, int Type, char* Value)
-{
- (*d)[*count].key = Key;
- (*d)[*count].type = Type;
- (*d)[*count].value = Value;
- (*count)++;
- *d = xrealloc(*d, (*count + 1) * sizeof(REMOTEHOST_DATA));
-}
-
-/*
-** Read in the file listing the hosts we take news from, and fill in the
-** global list of their Internet addresses. A host can have multiple
-** addresses, so we take care to add all of them to the list.
-*/
-static void
-RCreadfile (REMOTEHOST_DATA **data, REMOTEHOST **list, int *count,
- char *filename)
-{
- static char NOPASS[] = "";
- static char NOIDENTD[] = "";
- static char NOEMAIL[] = "";
- static char NOCOMMENT[] = "";
- FILE *F;
- char *p;
- char **q;
- char **r;
-#if !defined( HAVE_INET6)
- struct hostent *hp;
-#endif
-#if !defined(HAVE_UNIX_DOMAIN_SOCKETS) || !defined(HAVE_INET6)
- struct in_addr addr;
-#endif
- int i;
- int j;
- int linecount;
- int infocount;
- int groupcount;
- int maxgroup;
- REMOTEHOST_DATA *dt;
- REMOTEHOST *rp;
- char *word;
- REMOTEHOST *groups;
- REMOTEHOST *group_params = NULL;
- REMOTEHOST peer_params;
- REMOTEHOST default_params;
- bool flag, bit, toolong;
-
- *RCbuff = '\0';
- if (*list) {
- for (rp = *list, i = *count; --i >= 0; rp++) {
- free(rp->Name);
- free(rp->Label);
- free(rp->Email);
- free(rp->Comment);
- free(rp->Password);
- free(rp->Identd);
- if (rp->Patterns) {
- free(rp->Patterns[0]);
- free(rp->Patterns);
- }
- }
- free(*list);
- *list = NULL;
- *count = 0;
- }
- if (*data) {
- for (i = 0; (*data)[i].key != K_END; i++)
- if ((*data)[i].value != NULL)
- free((*data)[i].value);
- free(*data);
- *data = NULL;
- }
-
- *count = 0;
- maxgroup = 0;
- /* Open the server file. */
- if ((F = Fopen(filename, "r", TEMPORARYOPEN)) == NULL) {
- syslog(L_FATAL, "%s cant read %s: %m", LogName, filename);
- exit(1);
- }
- dt = *data = xmalloc(sizeof(REMOTEHOST_DATA));
- rp = *list = xmalloc(sizeof(REMOTEHOST));
-
-#if !defined(HAVE_UNIX_DOMAIN_SOCKETS)
- addr.s_addr = INADDR_LOOPBACK;
- make_sin( (struct sockaddr_in *)&rp->Address, &addr );
- rp->Name = xstrdup("localhost");
- rp->Label = xstrdup("localhost");
- rp->Email = xstrdup(NOEMAIL);
- rp->Comment = xstrdup(NOCOMMENT);
- rp->Password = xstrdup(NOPASS);
- rp->Identd = xstrdup(NOIDENTD);
- rp->Patterns = NULL;
- rp->MaxCnx = 0;
- rp->Streaming = true;
- rp->Skip = false;
- rp->NoResendId = false;
- rp->Nolist = false;
- rp->HoldTime = 0;
- rp++;
- (*count)++;
-#endif /* !defined(HAVE_UNIX_DOMAIN_SOCKETS) */
-
- linecount = 0;
- infocount = 0;
- groupcount = 0; /* no group defined yet */
- groups = 0;
- peer_params.Label = NULL;
- default_params.Streaming = true;
- default_params.Skip = false;
- default_params.NoResendId = false;
- default_params.Nolist = false;
- default_params.MaxCnx = 0;
- default_params.HoldTime = 0;
- default_params.Password = xstrdup(NOPASS);
- default_params.Identd = xstrdup(NOIDENTD);
- default_params.Email = xstrdup(NOEMAIL);
- default_params.Comment = xstrdup(NOCOMMENT);
- default_params.Pattern = NULL;
- peer_params.Keysetbit = 0;
-
- /* Read the file to add all the hosts. */
- while ((word = RCreaddata (&linecount, F, &toolong)) != NULL) {
-
- /* group */
- if (!strncmp (word, GROUP, sizeof GROUP)) {
- free(word);
- /* name of the group */
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
- syslog(L_ERROR, GROUP_NAME, LogName, filename, linecount);
- break;
- }
- RCadddata(data, &infocount, K_BEGIN_GROUP, T_STRING, word);
- groupcount++;
- if (groupcount == 1) {
- /* First group block. */
- group_params = groups = xmalloc(sizeof(REMOTEHOST));
- }
- else if (groupcount >= maxgroup) {
- /* Alloc 5 groups for extra nested group blocks. */
- groups = xrealloc(groups, (groupcount + 4) * sizeof(REMOTEHOST));
- maxgroup += 5;
- group_params = groups + groupcount - 1;
- }
- else {
- /* Nested group block (no need to extend groups). */
- group_params++;
- }
- group_params->Label = word;
- group_params->Skip = groupcount > 1 ?
- groups[groupcount - 2].Skip : default_params.Skip;
- group_params->Streaming = groupcount > 1 ?
- groups[groupcount - 2].Streaming : default_params.Streaming;
- group_params->NoResendId = groupcount > 1 ?
- groups[groupcount - 2].NoResendId : default_params.NoResendId;
- group_params->Nolist = groupcount > 1 ?
- groups[groupcount - 2].Nolist : default_params.Nolist;
- group_params->Email = groupcount > 1 ?
- groups[groupcount - 2].Email : default_params.Email;
- group_params->Comment = groupcount > 1 ?
- groups[groupcount - 2].Comment : default_params.Comment;
- group_params->Pattern = groupcount > 1 ?
- groups[groupcount - 2].Pattern : default_params.Pattern;
- group_params->Password = groupcount > 1 ?
- groups[groupcount - 2].Password : default_params.Password;
- group_params->Identd = groupcount > 1 ?
- groups[groupcount - 2].Identd : default_params.Identd;
- group_params->MaxCnx = groupcount > 1 ?
- groups[groupcount - 2].MaxCnx : default_params.MaxCnx;
- group_params->HoldTime = groupcount > 1 ?
- groups[groupcount - 2].HoldTime : default_params.HoldTime;
-
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
- syslog(L_ERROR, LEFT_BRACE, LogName, filename, linecount);
- break;
- }
- /* left brace */
- if (strncmp (word, "{", 1)) {
- free(word);
- syslog(L_ERROR, LEFT_BRACE, LogName, filename, linecount);
- break;
- }
- else
- free(word);
- peer_params.Keysetbit = 0;
- continue;
- }
-
- /* peer */
- if (!strncmp (word, PEER, sizeof PEER)) {
- free(word);
- if (peer_params.Label != NULL) {
- /* peer can't contain peer */
- syslog(L_ERROR, PEER_IN_PEER, LogName,
- filename, linecount);
- break;
- }
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL)
- {
- syslog(L_ERROR, PEER_NAME, LogName, filename, linecount);
- break;
- }
- RCadddata(data, &infocount, K_BEGIN_PEER, T_STRING, word);
- /* name of the peer */
- peer_params.Label = word;
- peer_params.Name = NULL;
- peer_params.Skip = groupcount > 0 ?
- group_params->Skip : default_params.Skip;
- peer_params.Streaming = groupcount > 0 ?
- group_params->Streaming : default_params.Streaming;
- peer_params.NoResendId = groupcount > 0 ?
- group_params->NoResendId : default_params.NoResendId;
- peer_params.Nolist = groupcount > 0 ?
- group_params->Nolist : default_params.Nolist;
- peer_params.Email = groupcount > 0 ?
- group_params->Email : default_params.Email;
- peer_params.Comment = groupcount > 0 ?
- group_params->Comment : default_params.Comment;
- peer_params.Pattern = groupcount > 0 ?
- group_params->Pattern : default_params.Pattern;
- peer_params.Password = groupcount > 0 ?
- group_params->Password : default_params.Password;
- peer_params.Identd = groupcount > 0 ?
- group_params->Identd : default_params.Identd;
- peer_params.MaxCnx = groupcount > 0 ?
- group_params->MaxCnx : default_params.MaxCnx;
- peer_params.HoldTime = groupcount > 0 ?
- group_params->HoldTime : default_params.HoldTime;
-
- peer_params.Keysetbit = 0;
-
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL)
- {
- syslog(L_ERROR, LEFT_BRACE, LogName, filename, linecount);
- break;
- }
- /* left brace */
- if (strncmp (word, "{", 1)) {
- syslog(L_ERROR, LEFT_BRACE, LogName, filename, linecount);
- free(word);
- break;
- }
- else
- free(word);
- continue;
- }
-
- /* right brace */
- if (!strncmp (word, "}", 1)) {
- free(word);
- if (peer_params.Label != NULL) {
- RCadddata(data, &infocount, K_END_PEER, T_STRING, NULL);
-
- /* Hostname defaults to label if not given */
- if (peer_params.Name == NULL)
- peer_params.Name = xstrdup(peer_params.Label);
-
- for(r = q = RCCommaSplit(xstrdup(peer_params.Name)); *q != NULL; q++) {
-#ifdef HAVE_INET6
- struct addrinfo *res, *res0, hints;
- int gai_ret;
-#endif
- (*count)++;
-
- /* Grow the array */
- j = rp - *list;
- *list = xrealloc(*list, *count * sizeof(REMOTEHOST));
- rp = *list + j;
-
-#ifdef HAVE_INET6
- memset( &hints, 0, sizeof( hints ) );
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_family = PF_UNSPEC;
- if ((gai_ret = getaddrinfo(*q, NULL, &hints, &res0)) != 0) {
- syslog(L_ERROR, "%s cant getaddrinfo %s %s", LogName, *q,
- gai_strerror( gai_ret ) );
- /* decrement *count, since we never got to add this record. */
- (*count)--;
- continue;
- }
- /* Count the addresses and see if we have to grow the list */
- i = 0;
- for (res = res0; res != NULL; res = res->ai_next)
- i++;
- /* Grow the array */
- j = rp - *list;
- *count += i - 1;
- *list = xrealloc(*list, *count * sizeof(REMOTEHOST));
- rp = *list + j;
-
- /* Add all hosts */
- for (res = res0; res != NULL; res = res->ai_next) {
- (void)memcpy(&rp->Address, res->ai_addr, res->ai_addrlen);
- rp->Name = xstrdup (*q);
- rp->Label = xstrdup (peer_params.Label);
- rp->Email = xstrdup(peer_params.Email);
- rp->Comment = xstrdup(peer_params.Comment);
- rp->Streaming = peer_params.Streaming;
- rp->Skip = peer_params.Skip;
- rp->NoResendId = peer_params.NoResendId;
- rp->Nolist = peer_params.Nolist;
- rp->Password = xstrdup(peer_params.Password);
- rp->Identd = xstrdup(peer_params.Identd);
- rp->Patterns = peer_params.Pattern != NULL ?
- RCCommaSplit(xstrdup(peer_params.Pattern)) : NULL;
- rp->MaxCnx = peer_params.MaxCnx;
- rp->HoldTime = peer_params.HoldTime;
- rp++;
- }
- freeaddrinfo(res0);
-#else /* HAVE_INET6 */
- /* Was host specified as a dotted quad ? */
- if (inet_aton(*q, &addr)) {
- make_sin( (struct sockaddr_in *)&rp->Address, &addr );
- rp->Name = xstrdup (*q);
- rp->Label = xstrdup (peer_params.Label);
- rp->Password = xstrdup(peer_params.Password);
- rp->Identd = xstrdup(peer_params.Identd);
- rp->Skip = peer_params.Skip;
- rp->Streaming = peer_params.Streaming;
- rp->NoResendId = peer_params.NoResendId;
- rp->Nolist = peer_params.Nolist;
- rp->Email = xstrdup(peer_params.Email);
- rp->Comment = xstrdup(peer_params.Comment);
- rp->Patterns = peer_params.Pattern != NULL ?
- RCCommaSplit(xstrdup(peer_params.Pattern)) : NULL;
- rp->MaxCnx = peer_params.MaxCnx;
- rp->HoldTime = peer_params.HoldTime;
- rp++;
- continue;
- }
-
- /* Host specified as a text name ? */
- if ((hp = gethostbyname(*q)) == NULL) {
- syslog(L_ERROR, "%s cant gethostbyname %s %m", LogName, *q);
- /* decrement *count, since we never got to add this record. */
- (*count)--;
- continue;
- }
-
- /* Count the adresses and see if we have to grow the list */
- for (i = 0; hp->h_addr_list[i]; i++)
- continue;
- if (i == 0) {
- syslog(L_ERROR, "%s no_address %s %m", LogName, *q);
- continue;
- }
- if (i == 1) {
- char **rr;
- int t = 0;
- /* Strange DNS ? try this.. */
- for (rr = hp->h_aliases; *rr != 0; rr++) {
- if (!inet_aton(*rr, &addr))
- continue;
- (*count)++;
- /* Grow the array */
- j = rp - *list;
- *list = xrealloc(*list, *count * sizeof(REMOTEHOST));
- rp = *list + j;
-
- make_sin( (struct sockaddr_in *)&rp->Address, &addr );
- rp->Name = xstrdup (*q);
- rp->Label = xstrdup (peer_params.Label);
- rp->Email = xstrdup(peer_params.Email);
- rp->Comment = xstrdup(peer_params.Comment);
- rp->Streaming = peer_params.Streaming;
- rp->Skip = peer_params.Skip;
- rp->NoResendId = peer_params.NoResendId;
- rp->Nolist = peer_params.Nolist;
- rp->Password = xstrdup(peer_params.Password);
- rp->Identd = xstrdup(peer_params.Identd);
- rp->Patterns = peer_params.Pattern != NULL ?
- RCCommaSplit(xstrdup(peer_params.Pattern)) : NULL;
- rp->MaxCnx = peer_params.MaxCnx;
- rp->HoldTime = peer_params.HoldTime;
- rp++;
- t++;
- }
- if (t == 0) {
- /* Just one, no need to grow. */
- make_sin( (struct sockaddr_in *)&rp->Address,
- (struct in_addr *)hp->h_addr_list[0] );
- rp->Name = xstrdup (*q);
- rp->Label = xstrdup (peer_params.Label);
- rp->Email = xstrdup(peer_params.Email);
- rp->Comment = xstrdup(peer_params.Comment);
- rp->Streaming = peer_params.Streaming;
- rp->Skip = peer_params.Skip;
- rp->NoResendId = peer_params.NoResendId;
- rp->Nolist = peer_params.Nolist;
- rp->Password = xstrdup(peer_params.Password);
- rp->Identd = xstrdup(peer_params.Identd);
- rp->Patterns = peer_params.Pattern != NULL ?
- RCCommaSplit(xstrdup(peer_params.Pattern)) : NULL;
- rp->MaxCnx = peer_params.MaxCnx;
- rp->HoldTime = peer_params.HoldTime;
- rp++;
- continue;
- }
- }
- /* Grow the array */
- j = rp - *list;
- *count += i - 1;
- *list = xrealloc(*list, *count * sizeof(REMOTEHOST));
- rp = *list + j;
-
- /* Add all the hosts. */
- for (i = 0; hp->h_addr_list[i]; i++) {
- make_sin( (struct sockaddr_in *)&rp->Address,
- (struct in_addr *)hp->h_addr_list[i] );
- rp->Name = xstrdup (*q);
- rp->Label = xstrdup (peer_params.Label);
- rp->Email = xstrdup(peer_params.Email);
- rp->Comment = xstrdup(peer_params.Comment);
- rp->Streaming = peer_params.Streaming;
- rp->Skip = peer_params.Skip;
- rp->NoResendId = peer_params.NoResendId;
- rp->Nolist = peer_params.Nolist;
- rp->Password = xstrdup(peer_params.Password);
- rp->Identd = xstrdup(peer_params.Identd);
- rp->Patterns = peer_params.Pattern != NULL ?
- RCCommaSplit(xstrdup(peer_params.Pattern)) : NULL;
- rp->MaxCnx = peer_params.MaxCnx;
- rp->HoldTime = peer_params.HoldTime;
- rp++;
- }
-#endif /* HAVE_INET6 */
- }
- free(r[0]);
- free(r);
- peer_params.Label = NULL;
- }
- else if (groupcount > 0 && group_params->Label != NULL) {
- RCadddata(data, &infocount, K_END_GROUP, T_STRING, NULL);
- group_params->Label = NULL;
- groupcount--;
- if (groupcount == 0) {
- /* We are now outside a group block. */
- free(groups);
- maxgroup = 0;
- } else {
- group_params--;
- }
- }
- else {
- syslog(L_ERROR, RIGHT_BRACE, LogName, linecount, filename);
- }
- continue;
- }
-
- /* streaming */
- if (!strncmp (word, STREAMING, sizeof STREAMING)) {
- free(word);
- TEST_CONFIG(K_STREAM, bit);
- if (bit) {
- syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
- break;
- }
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
- break;
- }
- if (!strcmp (word, "true"))
- flag = true;
- else
- if (!strcmp (word, "false"))
- flag = false;
- else {
- syslog(L_ERROR, MUST_BE_BOOL, LogName, filename, linecount);
- break;
- }
- RCadddata(data, &infocount, K_STREAM, T_STRING, word);
- if (peer_params.Label != NULL)
- peer_params.Streaming = flag;
- else
- if (groupcount > 0 && group_params->Label != NULL)
- group_params->Streaming = flag;
- else
- default_params.Streaming = flag;
- SET_CONFIG(K_STREAM);
- continue;
- }
-
- /* skip */
- if (!strncmp (word, SKIP, sizeof SKIP)) {
- free(word);
- TEST_CONFIG(K_SKIP, bit);
- if (bit) {
- syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
- break;
- }
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
- break;
- }
- if (!strcmp (word, "true"))
- flag = true;
- else
- if (!strcmp (word, "false"))
- flag = false;
- else {
- syslog(L_ERROR, MUST_BE_BOOL, LogName, filename, linecount);
- break;
- }
- RCadddata(data, &infocount, K_SKIP, T_STRING, word);
- if (peer_params.Label != NULL)
- peer_params.Skip = flag;
- else
- if (groupcount > 0 && group_params->Label != NULL)
- group_params->Skip = flag;
- else
- default_params.Skip = flag;
- SET_CONFIG(K_SKIP);
- continue;
- }
-
- /* noresendid */
- if (!strncmp (word, NORESENDID, sizeof NORESENDID)) {
- free(word);
- TEST_CONFIG(K_NORESENDID, bit);
- if (bit) {
- syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
- break;
- }
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
- break;
- }
- if (!strcmp (word, "true"))
- flag = true;
- else
- if (!strcmp (word, "false"))
- flag = false;
- else {
- syslog(L_ERROR, MUST_BE_BOOL, LogName, filename, linecount);
- break;
- }
- RCadddata(data, &infocount, K_NORESENDID, T_STRING, word);
- if (peer_params.Label != NULL)
- peer_params.NoResendId = flag;
- else
- if (groupcount > 0 && group_params->Label != NULL)
- group_params->NoResendId = flag;
- else
- default_params.NoResendId = flag;
- SET_CONFIG(K_NORESENDID);
- continue;
- }
-
- /* nolist */
- if (!strncmp (word, NOLIST, sizeof NOLIST)) {
- free(word);
- TEST_CONFIG(K_NOLIST, bit);
- if (bit) {
- syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
- break;
- }
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
- break;
- }
- if (!strcmp (word, "true"))
- flag = true;
- else
- if (!strcmp (word, "false"))
- flag = false;
- else {
- syslog(L_ERROR, MUST_BE_BOOL, LogName, filename, linecount);
- break;
- }
- RCadddata(data, &infocount, K_NOLIST, T_STRING, word);
- if (peer_params.Label != NULL)
- peer_params.Nolist = flag;
- else
- if (groupcount > 0 && group_params->Label != NULL)
- group_params->Nolist = flag;
- else
- default_params.Nolist = flag;
- SET_CONFIG(K_NOLIST);
- continue;
- }
-
- /* max-connections */
- if (!strncmp (word, MAX_CONN, sizeof MAX_CONN)) {
- int max;
- free(word);
- TEST_CONFIG(K_MAX_CONN, bit);
- if (bit) {
- syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
- break;
- }
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
- break;
- }
- RCadddata(data, &infocount, K_MAX_CONN, T_STRING, word);
- for (p = word; CTYPE(isdigit, *p) && *p != '\0'; p++);
- if (!strcmp (word, "none") || !strcmp (word, "unlimited")) {
- max = 0;
- } else {
- if (*p != '\0') {
- syslog(L_ERROR, MUST_BE_INT, LogName, filename, linecount);
- break;
- }
- max = atoi(word);
- }
- if (peer_params.Label != NULL)
- peer_params.MaxCnx = max;
- else
- if (groupcount > 0 && group_params->Label != NULL)
- group_params->MaxCnx = max;
- else
- default_params.MaxCnx = max;
- SET_CONFIG(K_MAX_CONN);
- continue;
- }
-
- /* hold-time */
- if (!strncmp (word, HOLD_TIME, sizeof HOLD_TIME)) {
- free(word);
- TEST_CONFIG(K_HOLD_TIME, bit);
- if (bit) {
- syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
- break;
- }
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
- break;
- }
- RCadddata(data, &infocount, K_HOLD_TIME, T_STRING, word);
- for (p = word; CTYPE(isdigit, *p) && *p != '\0'; p++);
- if (*p != '\0') {
- syslog(L_ERROR, MUST_BE_INT, LogName, filename, linecount);
- break;
- }
- if (peer_params.Label != NULL)
- peer_params.HoldTime = atoi(word);
- else
- if (groupcount > 0 && group_params->Label != NULL)
- group_params->HoldTime = atoi(word);
- else
- default_params.HoldTime = atoi(word);
- SET_CONFIG(K_HOLD_TIME);
- continue;
- }
-
- /* hostname */
- if (!strncmp (word, HOSTNAME, sizeof HOSTNAME)) {
- free(word);
- TEST_CONFIG(K_HOSTNAME, bit);
- if (bit) {
- syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
- break;
- }
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
- break;
- }
- RCadddata(data, &infocount, K_HOSTNAME, T_STRING, word);
- peer_params.Name = word;
- SET_CONFIG(K_HOSTNAME);
- continue;
- }
-
- /* password */
- if (!strncmp (word, PASSWORD, sizeof PASSWORD)) {
- free(word);
- TEST_CONFIG(K_PASSWORD, bit);
- if (bit) {
- syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
- break;
- }
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
- break;
- }
- RCadddata(data, &infocount, K_PASSWORD, T_STRING, word);
- if (peer_params.Label != NULL)
- peer_params.Password = word;
- else
- if (groupcount > 0 && group_params->Label != NULL)
- group_params->Password = word;
- else
- default_params.Password = word;
- SET_CONFIG(K_PASSWORD);
- continue;
- }
-
- /* identd */
- if (!strncmp (word, IDENTD, sizeof IDENTD)) {
- free(word);
- TEST_CONFIG(K_IDENTD, bit);
- if (bit) {
- syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
- break;
- }
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
- break;
- }
- RCadddata(data, &infocount, K_IDENTD, T_STRING, word);
- if (peer_params.Label != NULL)
- peer_params.Identd = word;
- else
- if (groupcount > 0 && group_params->Label != NULL)
- group_params->Identd = word;
- else
- default_params.Identd = word;
- SET_CONFIG(K_IDENTD);
- continue;
- }
-
- /* patterns */
- if (!strncmp (word, PATTERNS, sizeof PATTERNS)) {
- TEST_CONFIG(K_PATTERNS, bit);
- if (bit) {
- syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
- break;
- }
- free(word);
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
- break;
- }
- RCadddata(data, &infocount, K_PATTERNS, T_STRING, word);
- if (peer_params.Label != NULL)
- peer_params.Pattern = word;
- else
- if (groupcount > 0 && group_params->Label != NULL)
- group_params->Pattern = word;
- else
- default_params.Pattern = word;
- SET_CONFIG(K_PATTERNS);
- continue;
- }
-
- /* email */
- if (!strncmp (word, EMAIL, sizeof EMAIL)) {
- free(word);
- TEST_CONFIG(K_EMAIL, bit);
- if (bit) {
- syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
- break;
- }
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
- break;
- }
- RCadddata(data, &infocount, K_EMAIL, T_STRING, word);
- if (peer_params.Label != NULL)
- peer_params.Email = word;
- else
- if (groupcount > 0 && group_params->Label != NULL)
- group_params->Email = word;
- else
- default_params.Email = word;
- SET_CONFIG(K_EMAIL);
- continue;
- }
-
- /* comment */
- if (!strncmp (word, COMMENT, sizeof COMMENT)) {
- free(word);
- TEST_CONFIG(K_COMMENT, bit);
- if (bit) {
- syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
- break;
- }
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
- break;
- }
- RCadddata(data, &infocount, K_COMMENT, T_STRING, word);
- if (peer_params.Label != NULL)
- peer_params.Comment = word;
- else
- if (groupcount > 0 && group_params->Label != NULL)
- group_params->Comment = word;
- else
- default_params.Comment = word;
- SET_CONFIG(K_COMMENT);
- continue;
- }
-
- if (toolong)
- syslog(L_ERROR, "%s line too long at %d: %s",
- LogName, --linecount, filename);
- else
- syslog(L_ERROR, "%s Unknown value line %d: %s",
- LogName, linecount, filename);
- free(word);
- break;
- }
- free(default_params.Email);
- free(default_params.Comment);
- RCadddata(data, &infocount, K_END, T_STRING, NULL);
-
- if (feof (F)) {
- if (peer_params.Label != NULL)
- syslog(L_ERROR, INCOMPLETE_PEER, LogName, peer_params.Label,
- filename, linecount);
- if (groupcount > 0 && group_params->Label != NULL)
- syslog(L_ERROR, INCOMPLETE_GROUP, LogName, group_params->Label,
- filename, linecount);
- }
- else
- syslog(L_ERROR, "%s Syntax error in %s at or before line %d", LogName,
- filename, linecount);
-
- if (Fclose(F) == EOF)
- syslog(L_ERROR, "%s cant fclose %s %m", LogName, filename);
-
- free(default_params.Password);
- free(default_params.Identd);
-}
-
-
-/*
-** Indent a line with 3 * c blanks.
-** Used by RCwritelist().
-*/
-static void
-RCwritelistindent(FILE *F, int c)
-{
- int i;
-
- for (i = 0; i < c; i++)
- fprintf(F, " ");
-}
-
-/*
-** Add double quotes around a string, if needed.
-** Used by RCwritelist().
-*/
-static void
-RCwritelistvalue(FILE *F, char *value)
-{
- if (*value == '\0' || strchr (value, '\n') ||
- strchr (value, ' ') || strchr (value, '\t'))
- fprintf(F, "\"%s\"", value);
- else
- fprintf(F, "%s", value);
-}
-
-/*
-** Write the incoming configuration (memory->disk)
-*/
-static void UNUSED
-RCwritelist(char *filename)
-{
- FILE *F;
- int i;
- int inc;
- char *p;
- char *q;
- char *r;
-
- if ((F = Fopen(filename, "w", TEMPORARYOPEN)) == NULL) {
- syslog(L_FATAL, "%s cant write %s: %m", LogName, filename);
- return;
- }
-
- /* Write a standard header.. */
-
- /* Find the filename */
- p = concatpath(innconf->pathetc, _PATH_INNDHOSTS);
- for (r = q = p; *p; p++)
- if (*p == '/')
- q = p + 1;
-
- fprintf (F, "## $Revision: 7751 $\n");
- fprintf (F, "## %s - names and addresses that feed us news\n", q);
- free(r);
- fprintf (F, "##\n\n");
-
- /* ... */
-
- inc = 0;
- for (i = 0; RCpeerlistfile[i].key != K_END; i++) {
- switch (RCpeerlistfile[i].key) {
- case K_BEGIN_PEER:
- fputc ('\n', F);
- RCwritelistindent (F, inc);
- fprintf(F, "%s %s {\n", PEER, RCpeerlistfile[i].value);
- inc++;
- break;
- case K_BEGIN_GROUP:
- fputc ('\n', F);
- RCwritelistindent (F, inc);
- fprintf(F, "%s %s {\n", GROUP, RCpeerlistfile[i].value);
- inc++;
- break;
- case K_END_PEER:
- case K_END_GROUP:
- inc--;
- RCwritelistindent (F, inc);
- fprintf(F, "}\n");
- break;
- case K_STREAM:
- RCwritelistindent (F, inc);
- fprintf(F, "%s\t", STREAMING);
- RCwritelistvalue (F, RCpeerlistfile[i].value);
- fputc ('\n', F);
- break;
- case K_SKIP:
- RCwritelistindent (F, inc);
- fprintf(F, "%s\t", SKIP);
- RCwritelistvalue (F, RCpeerlistfile[i].value);
- fputc ('\n', F);
- break;
- case K_NORESENDID:
- RCwritelistindent (F, inc);
- fprintf(F, "%s\t", NORESENDID);
- RCwritelistvalue (F, RCpeerlistfile[i].value);
- fputc ('\n', F);
- break;
- case K_NOLIST:
- RCwritelistindent (F, inc);
- fprintf(F, "%s\t", NOLIST);
- RCwritelistvalue (F, RCpeerlistfile[i].value);
- fputc ('\n', F);
- break;
- case K_HOSTNAME:
- RCwritelistindent (F, inc);
- fprintf(F, "%s\t", HOSTNAME);
- RCwritelistvalue (F, RCpeerlistfile[i].value);
- fputc ('\n', F);
- break;
- case K_MAX_CONN:
- RCwritelistindent (F, inc);
- fprintf(F, "%s\t", MAX_CONN);
- RCwritelistvalue (F, RCpeerlistfile[i].value);
- fputc ('\n', F);
- break;
- case K_HOLD_TIME:
- RCwritelistindent (F, inc);
- fprintf(F, "%s\t", HOLD_TIME);
- RCwritelistvalue (F, RCpeerlistfile[i].value);
- fputc ('\n', F);
- break;
- case K_PASSWORD:
- RCwritelistindent (F, inc);
- fprintf(F, "%s\t", PASSWORD);
- RCwritelistvalue (F, RCpeerlistfile[i].value);
- fputc ('\n', F);
- break;
- case K_IDENTD:
- RCwritelistindent (F, inc);
- fprintf(F, "%s\t", IDENTD);
- RCwritelistvalue (F, RCpeerlistfile[i].value);
- fputc ('\n', F);
- break;
- case K_EMAIL:
- RCwritelistindent (F, inc);
- fprintf(F, "%s\t", EMAIL);
- RCwritelistvalue (F, RCpeerlistfile[i].value);
- fputc ('\n', F);
- break;
- case K_PATTERNS:
- RCwritelistindent (F, inc);
- fprintf(F, "%s\t", PATTERNS);
- RCwritelistvalue (F, RCpeerlistfile[i].value);
- fputc ('\n', F);
- break;
- case K_COMMENT:
- RCwritelistindent (F, inc);
- fprintf(F, "%s\t", COMMENT);
- RCwritelistvalue (F, RCpeerlistfile[i].value);
- fputc ('\n', F);
- break;
- default:
- fprintf(F, "# ***ERROR***\n");
- }
- }
- if (Fclose(F) == EOF)
- syslog(L_ERROR, "%s cant fclose %s %m", LogName, filename);
-
-}
-
-void
-RCreadlist(void)
-{
- static char *INNDHOSTS = NULL;
-
- if (INNDHOSTS == NULL)
- INNDHOSTS = concatpath(innconf->pathetc, _PATH_INNDHOSTS);
- StreamingOff = false;
- RCreadfile(&RCpeerlistfile, &RCpeerlist, &RCnpeerlist, INNDHOSTS);
- /* RCwritelist("/tmp/incoming.conf.new"); */
-}
-
-/*
-** Find the name of a remote host we've connected to.
-*/
-char *
-RChostname(const CHANNEL *cp)
-{
- static char buff[SMBUF];
- REMOTEHOST *rp;
- int i;
-
- for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++)
- if (RCaddressmatch(&cp->Address, &rp->Address))
- return rp->Name;
- strlcpy(buff, sprint_sockaddr((struct sockaddr *)&cp->Address),
- sizeof(buff));
- return buff;
-}
-
-/*
-** Find the label name of a remote host we've connected to.
-*/
-char *
-RClabelname(CHANNEL *cp) {
- REMOTEHOST *rp;
- int i;
-
- for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++) {
- if (RCaddressmatch(&cp->Address, &rp->Address))
- return rp->Label;
- }
- return NULL;
-}
-
-/*
-** Is the remote site allowed to post to this group?
-*/
-int
-RCcanpost(CHANNEL *cp, char *group)
-{
- REMOTEHOST *rp;
- char match;
- char subvalue;
- char **argv;
- char *pat;
- int i;
-
- /* Connections from lc.c are from local nnrpd and should always work */
- if (cp->Address.ss_family == 0)
- return 1;
-
- for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++) {
- if (!RCaddressmatch(&cp->Address, &rp->Address))
- continue;
- if (rp->Patterns == NULL)
- break;
- for (match = 0, argv = rp->Patterns; (pat = *argv++) != NULL; ) {
- subvalue = (*pat != SUB_NEGATE) && (*pat != SUB_POISON) ?
- 0 : *pat;
- if (subvalue)
- pat++;
- if ((match != subvalue) && uwildmat(group, pat)) {
- if (subvalue == SUB_POISON)
- return -1;
- match = subvalue;
- }
- }
- return !match;
- }
- return 1;
-}
-
-
-/*
-** Create the channel.
-*/
-void
-RCsetup(int i)
-{
-#if defined(SO_REUSEADDR)
- int on;
-#endif /* defined(SO_REUSEADDR) */
- int j;
- CHANNEL *rcchan;
-
- /* This code is called only when inndstart is not being used */
- if (i < 0) {
-#ifdef HAVE_INET6
- syslog(L_FATAL, "%s innd MUST be started with inndstart", LogName);
- exit(1);
-#else
- /* Create a socket and name it. */
- struct sockaddr_in server;
-
- if ((i = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- syslog(L_FATAL, "%s cant socket RCreader %m", LogName);
- exit(1);
- }
-#if defined(SO_REUSEADDR)
- on = 1;
- if (setsockopt(i, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on) < 0)
- syslog(L_ERROR, "%s cant setsockopt RCreader %m", LogName);
-#endif /* defined(SO_REUSEADDR) */
- memset(&server, 0, sizeof server);
- server.sin_port = htons(innconf->port);
- server.sin_family = AF_INET;
-#ifdef HAVE_SOCKADDR_LEN
- server.sin_len = sizeof( struct sockaddr_in );
-#endif
- server.sin_addr.s_addr = htonl(INADDR_ANY);
- if (innconf->bindaddress) {
- if (!inet_aton(innconf->bindaddress, &server.sin_addr)) {
- syslog(L_FATAL, "unable to determine bind ip (%s) %m",
- innconf->bindaddress);
- exit(1);
- }
- }
- if (bind(i, (struct sockaddr *)&server, sizeof server) < 0) {
- syslog(L_FATAL, "%s cant bind RCreader %m", LogName);
- exit(1);
- }
-#endif /* HAVE_INET6 */
- }
-
- /* Set it up to wait for connections. */
- if (listen(i, MAXLISTEN) < 0) {
- j = errno;
- syslog(L_FATAL, "%s cant listen RCreader %m", LogName);
- /* some IPv6 systems already listening on any address will
- return EADDRINUSE when trying to listen on the IPv4 socket */
- if (j == EADDRINUSE)
- return;
- exit(1);
- }
-
- rcchan = CHANcreate(i, CTremconn, CSwaiting, RCreader, RCwritedone);
- syslog(L_NOTICE, "%s rcsetup %s", LogName, CHANname(rcchan));
- RCHANadd(rcchan);
-
- for (j = 0 ; j < chanlimit ; j++ ) {
- if (RCchan[j] == NULL) {
- break;
- }
- }
- if (j < chanlimit) {
- RCchan[j] = rcchan;
- } else if (chanlimit == 0) {
- /* assuming two file descriptors(AF_INET and AF_INET6) */
- chanlimit = 2;
- RCchan = xmalloc(chanlimit * sizeof(CHANNEL **));
- for (j = 0 ; j < chanlimit ; j++ ) {
- RCchan[j] = NULL;
- }
- RCchan[0] = rcchan;
- } else {
- /* extend to double size */
- RCchan = xrealloc(RCchan, chanlimit * 2 * sizeof(CHANNEL **));
- for (j = chanlimit ; j < chanlimit * 2 ; j++ ) {
- RCchan[j] = NULL;
- }
- RCchan[chanlimit] = rcchan;
- chanlimit *= 2;
- }
-
- /* Get the list of hosts we handle. */
- RCreadlist();
-}
-
-
-/*
-** Cleanly shut down the channel.
-*/
-void
-RCclose(void)
-{
- REMOTEHOST *rp;
- int i;
-
- for (i = 0 ; i < chanlimit ; i++) {
- if (RCchan[i] != NULL) {
- CHANclose(RCchan[i], CHANname(RCchan[i]));
- } else {
- break;
- }
- }
- if (chanlimit != 0)
- free(RCchan);
- RCchan = NULL;
- chanlimit = 0;
- if (RCpeerlist) {
- for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++) {
- free(rp->Name);
- free(rp->Label);
- free(rp->Email);
- free(rp->Password);
- free(rp->Identd);
- free(rp->Comment);
- if (rp->Patterns) {
- free(rp->Patterns[0]);
- free(rp->Patterns);
- }
- }
- free(RCpeerlist);
- RCpeerlist = NULL;
- RCnpeerlist = 0;
- }
-
- if (RCpeerlistfile) {
- for (i = 0; RCpeerlistfile[i].key != K_END; i++)
- if (RCpeerlistfile[i].value != NULL)
- free(RCpeerlistfile[i].value);
- free(RCpeerlistfile);
- RCpeerlistfile = NULL;
- }
-}