From 91a7cb6daf6be6f3c0e4de318d13299ae8e11953 Mon Sep 17 00:00:00 2001 From: Wilfried Goesgens Date: Tue, 1 Jan 2013 16:28:43 +0100 Subject: [PATCH] NetworkConfig: move to RoomNetworkConfig; move NTT-List into its own file. --- citadel/Makefile.in | 4 +- citadel/include/ctdl_module.h | 43 ++ citadel/modules/network/netconfig.h | 54 -- citadel/modules/network/netspool.h | 7 +- citadel/modules/network/serv_netconfig.c | 592 ----------------- citadel/modules/network/serv_netmail.c | 24 +- citadel/modules/network/serv_netspool.c | 69 +- citadel/modules/network/serv_network.c | 73 +-- citadel/modules/network/serv_network.h | 10 - citadel/modules/network/serv_networkclient.c | 11 +- citadel/msgbase.c | 7 +- citadel/netconfig.c | 648 ++++++++++++++++++- citadel/nttlist.c | 105 +++ 13 files changed, 843 insertions(+), 804 deletions(-) create mode 100644 citadel/nttlist.c diff --git a/citadel/Makefile.in b/citadel/Makefile.in index c2ecdb7ee..d6210e08c 100644 --- a/citadel/Makefile.in +++ b/citadel/Makefile.in @@ -83,7 +83,7 @@ SOURCES=utils/aidepost.c utils/citmail.c \ locate_host.c md5.c auth.c msgbase.c parsedate.c \ room_ops.c euidindex.c server_main.c ldap.c \ support.c sysdep.c user_ops.c journaling.c threads.c \ - context.c event_client.c netconfig.c + context.c event_client.c netconfig.c nttlist.c include Make_sources @@ -138,7 +138,7 @@ SERV_OBJS = server_main.o utillib/citadel_dirs.o event_client.o \ internet_addressing.o journaling.o \ parsedate.o genstamp.o ecrash.o threads.o context.o \ clientsocket.o modules_init.o modules_upgrade.o $(SERV_MODULES) \ - svn_revision.o ldap.o netconfig.o + svn_revision.o ldap.o netconfig.o nttlist.o citserver$(EXEEXT): $(SERV_OBJS) $(CC) $(SERV_OBJS) $(LDFLAGS) $(SERVER_LDFLAGS) $(LIBS) $(SERVER_LIBS) $(RESOLV) -o citserver$(EXEEXT) diff --git a/citadel/include/ctdl_module.h b/citadel/include/ctdl_module.h index eddcbeffc..7dad38745 100644 --- a/citadel/include/ctdl_module.h +++ b/citadel/include/ctdl_module.h @@ -416,7 +416,50 @@ void SerializeGeneric(const CfgLineType *ThisOne, StrBuf *OutputBuffer, OneRoomN void DeleteGenericCfgLine(const CfgLineType *ThisOne, RoomNetCfgLine **data); +typedef struct _nodeconf { + int DeleteMe; + StrBuf *NodeName; + StrBuf *Secret; + StrBuf *Host; + StrBuf *Port; +}CtdlNodeConf; +HashList* CtdlLoadIgNetCfg(void); + + +int CtdlNetconfigCheckRoomaccess(char *errmsgbuf, + size_t n, + const char* RemoteIdentifier); + + +typedef struct __NetMap { + StrBuf *NodeName; + time_t lastcontact; + StrBuf *NextHop; +}CtdlNetMap; + +HashList* CtdlReadNetworkMap(void); +StrBuf *CtdlSerializeNetworkMap(HashList *Map); +void NetworkLearnTopology(char *node, char *path, HashList *the_netmap, int *netmap_changed); +int CtdlIsValidNode(const StrBuf **nexthop, + const StrBuf **secret, + StrBuf *node, + HashList *IgnetCfg, + HashList *the_netmap); + + + + +int CtdlNetworkTalkingTo(const char *nodename, long len, int operation); + +/* + * Operations that can be performed by network_talking_to() + */ +enum { + NTT_ADD, + NTT_REMOVE, + NTT_CHECK +}; /* * Expose API calls from user_ops.c diff --git a/citadel/modules/network/netconfig.h b/citadel/modules/network/netconfig.h index 6168f0402..e69de29bb 100644 --- a/citadel/modules/network/netconfig.h +++ b/citadel/modules/network/netconfig.h @@ -1,54 +0,0 @@ -/* - * This module handles shared rooms, inter-Citadel mail, and outbound - * mailing list processing. - * - * Copyright (c) 2000-2012 by the citadel.org team - * - * This program is open source software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * ** NOTE ** A word on the S_NETCONFIGS semaphore: - * This is a fairly high-level type of critical section. It ensures that no - * two threads work on the netconfigs files at the same time. Since we do - * so many things inside these, here are the rules: - * 1. begin_critical_section(S_NETCONFIGS) *before* begin_ any others. - * 2. Do *not* perform any I/O with the client during these sections. - * - */ - -typedef struct _nodeconf { - int DeleteMe; - StrBuf *NodeName; - StrBuf *Secret; - StrBuf *Host; - StrBuf *Port; -}NodeConf; - -typedef struct __NetMap { - StrBuf *NodeName; - time_t lastcontact; - StrBuf *NextHop; -}NetMap; - -HashList* load_ignetcfg(void); - -HashList* read_network_map(void); -StrBuf *SerializeNetworkMap(HashList *Map); -void network_learn_topology(char *node, char *path, HashList *the_netmap, int *netmap_changed); - -int is_valid_node(const StrBuf **nexthop, - const StrBuf **secret, - StrBuf *node, - HashList *IgnetCfg, - HashList *the_netmap); diff --git a/citadel/modules/network/netspool.h b/citadel/modules/network/netspool.h index 34e13acae..7d7517277 100644 --- a/citadel/modules/network/netspool.h +++ b/citadel/modules/network/netspool.h @@ -27,10 +27,10 @@ * */ -typedef struct maplist maplist; +typedef struct MapList MapList; -struct maplist { - struct maplist *next; +struct MapList { + MapList *next; StrBuf *remote_nodename; StrBuf *remote_roomname; }; @@ -56,4 +56,3 @@ void network_consolidate_spoolout(HashList *working_ignetcfg, HashList *the_netm void free_spoolcontrol_struct(SpoolControl **scc); int writenfree_spoolcontrol_file(SpoolControl **scc, char *filename); int read_spoolcontrol_file(SpoolControl **scc, char *filename); -int is_recipient(OneRoomNetCfg *RNCfg, const char *Name); diff --git a/citadel/modules/network/serv_netconfig.c b/citadel/modules/network/serv_netconfig.c index 34ef2529b..94aeb62d3 100644 --- a/citadel/modules/network/serv_netconfig.c +++ b/citadel/modules/network/serv_netconfig.c @@ -82,595 +82,3 @@ -void DeleteNodeConf(void *vNode) -{ - NodeConf *Node = (NodeConf*) vNode; - FreeStrBuf(&Node->NodeName); - FreeStrBuf(&Node->Secret); - FreeStrBuf(&Node->Host); - FreeStrBuf(&Node->Port); - free(Node); -} - -NodeConf *NewNode(StrBuf *SerializedNode) -{ - const char *Pos = NULL; - NodeConf *Node; - - /* we need at least 4 pipes and some other text so its invalid. */ - if (StrLength(SerializedNode) < 8) - return NULL; - Node = (NodeConf *) malloc(sizeof(NodeConf)); - - Node->DeleteMe = 0; - - Node->NodeName=NewStrBuf(); - StrBufExtract_NextToken(Node->NodeName, SerializedNode, &Pos, '|'); - - Node->Secret=NewStrBuf(); - StrBufExtract_NextToken(Node->Secret, SerializedNode, &Pos, '|'); - - Node->Host=NewStrBuf(); - StrBufExtract_NextToken(Node->Host, SerializedNode, &Pos, '|'); - - Node->Port=NewStrBuf(); - StrBufExtract_NextToken(Node->Port, SerializedNode, &Pos, '|'); - return Node; -} - - -/* - * Load or refresh the Citadel network (IGnet) configuration for this node. - */ -HashList* load_ignetcfg(void) -{ - const char *LinePos; - char *Cfg; - StrBuf *Buf; - StrBuf *LineBuf; - HashList *Hash; - NodeConf *Node; - - Cfg = CtdlGetSysConfig(IGNETCFG); - if ((Cfg == NULL) || IsEmptyStr(Cfg)) { - if (Cfg != NULL) - free(Cfg); - return NULL; - } - - Hash = NewHash(1, NULL); - Buf = NewStrBufPlain(Cfg, -1); - free(Cfg); - LineBuf = NewStrBufPlain(NULL, StrLength(Buf)); - LinePos = NULL; - do - { - StrBufSipLine(LineBuf, Buf, &LinePos); - if (StrLength(LineBuf) != 0) { - Node = NewNode(LineBuf); - if (Node != NULL) { - Put(Hash, SKEY(Node->NodeName), Node, DeleteNodeConf); - } - } - } while (LinePos != StrBufNOTNULL); - FreeStrBuf(&Buf); - FreeStrBuf(&LineBuf); - return Hash; -} - -void DeleteNetMap(void *vNetMap) -{ - NetMap *TheNetMap = (NetMap*) vNetMap; - FreeStrBuf(&TheNetMap->NodeName); - FreeStrBuf(&TheNetMap->NextHop); - free(TheNetMap); -} - -NetMap *NewNetMap(StrBuf *SerializedNetMap) -{ - const char *Pos = NULL; - NetMap *NM; - - /* we need at least 3 pipes and some other text so its invalid. */ - if (StrLength(SerializedNetMap) < 6) - return NULL; - NM = (NetMap *) malloc(sizeof(NetMap)); - - NM->NodeName=NewStrBuf(); - StrBufExtract_NextToken(NM->NodeName, SerializedNetMap, &Pos, '|'); - - NM->lastcontact = StrBufExtractNext_long(SerializedNetMap, &Pos, '|'); - - NM->NextHop=NewStrBuf(); - StrBufExtract_NextToken(NM->NextHop, SerializedNetMap, &Pos, '|'); - - return NM; -} - -HashList* read_network_map(void) -{ - const char *LinePos; - char *Cfg; - StrBuf *Buf; - StrBuf *LineBuf; - HashList *Hash; - NetMap *TheNetMap; - - Cfg = CtdlGetSysConfig(IGNETMAP); - if ((Cfg == NULL) || IsEmptyStr(Cfg)) { - if (Cfg != NULL) - free(Cfg); - return NULL; - } - - Hash = NewHash(1, NULL); - Buf = NewStrBufPlain(Cfg, -1); - free(Cfg); - LineBuf = NewStrBufPlain(NULL, StrLength(Buf)); - LinePos = NULL; - while (StrBufSipLine(Buf, LineBuf, &LinePos)) - { - TheNetMap = NewNetMap(LineBuf); - if (TheNetMap != NULL) { /* TODO: is the NodeName Uniq? */ - Put(Hash, SKEY(TheNetMap->NodeName), TheNetMap, DeleteNetMap); - } - } - FreeStrBuf(&Buf); - FreeStrBuf(&LineBuf); - return Hash; -} - -StrBuf *SerializeNetworkMap(HashList *Map) -{ - void *vMap; - const char *key; - long len; - StrBuf *Ret = NewStrBuf(); - HashPos *Pos = GetNewHashPos(Map, 0); - - while (GetNextHashPos(Map, Pos, &len, &key, &vMap)) - { - NetMap *pMap = (NetMap*) vMap; - StrBufAppendBuf(Ret, pMap->NodeName, 0); - StrBufAppendBufPlain(Ret, HKEY("|"), 0); - - StrBufAppendPrintf(Ret, "%ld", pMap->lastcontact, 0); - StrBufAppendBufPlain(Ret, HKEY("|"), 0); - - StrBufAppendBuf(Ret, pMap->NextHop, 0); - StrBufAppendBufPlain(Ret, HKEY("\n"), 0); - } - DeleteHashPos(&Pos); - return Ret; -} - - -/* - * Learn topology from path fields - */ -void network_learn_topology(char *node, char *path, HashList *the_netmap, int *netmap_changed) -{ - NetMap *pNM = NULL; - void *vptr; - char nexthop[256]; - NetMap *nmptr; - - if (GetHash(the_netmap, node, strlen(node), &vptr) && - (vptr != NULL))/* TODO: is the NodeName Uniq? */ - { - pNM = (NetMap*)vptr; - extract_token(nexthop, path, 0, '!', sizeof nexthop); - if (!strcmp(nexthop, ChrPtr(pNM->NextHop))) { - pNM->lastcontact = time(NULL); - (*netmap_changed) ++; - return; - } - } - - /* If we got here then it's not in the map, so add it. */ - nmptr = (NetMap *) malloc(sizeof (NetMap)); - nmptr->NodeName = NewStrBufPlain(node, -1); - nmptr->lastcontact = time(NULL); - nmptr->NextHop = NewStrBuf (); - StrBufExtract_tokenFromStr(nmptr->NextHop, path, strlen(path), 0, '!'); - /* TODO: is the NodeName Uniq? */ - Put(the_netmap, SKEY(nmptr->NodeName), nmptr, DeleteNetMap); - (*netmap_changed) ++; -} - - -/* - * Check the network map and determine whether the supplied node name is - * valid. If it is not a neighbor node, supply the name of a neighbor node - * which is the next hop. If it *is* a neighbor node, we also fill in the - * shared secret. - */ -int is_valid_node(const StrBuf **nexthop, - const StrBuf **secret, - StrBuf *node, - HashList *IgnetCfg, - HashList *the_netmap) -{ - void *vNetMap; - void *vNodeConf; - NodeConf *TheNode; - NetMap *TheNetMap; - - if (StrLength(node) == 0) { - return(-1); - } - - /* - * First try the neighbor nodes - */ - if (GetCount(IgnetCfg) == 0) { - syslog(LOG_INFO, "IgnetCfg is empty!\n"); - if (nexthop != NULL) { - *nexthop = NULL; - } - return(-1); - } - - /* try to find a neigbour with the name 'node' */ - if (GetHash(IgnetCfg, SKEY(node), &vNodeConf) && - (vNodeConf != NULL)) - { - TheNode = (NodeConf*)vNodeConf; - if (secret != NULL) - *secret = TheNode->Secret; - return 0; /* yup, it's a direct neighbor */ - } - - /* - * If we get to this point we have to see if we know the next hop - *//* TODO: is the NodeName Uniq? */ - if ((GetCount(the_netmap) > 0) && - (GetHash(the_netmap, SKEY(node), &vNetMap))) - { - TheNetMap = (NetMap*)vNetMap; - if (nexthop != NULL) - *nexthop = TheNetMap->NextHop; - return(0); - } - - /* - * If we get to this point, the supplied node name is bogus. - */ - syslog(LOG_ERR, "Invalid node name <%s>\n", ChrPtr(node)); - return(-1); -} - - -void cmd_gnet(char *argbuf) -{ - char filename[PATH_MAX]; - char buf[SIZ]; - FILE *fp; - - - if (!IsEmptyStr(argbuf)) - { - if (CtdlAccessCheck(ac_aide)) return; - if (strcmp(argbuf, FILE_MAILALIAS)) - { - cprintf("%d No such file or directory\n", - ERROR + INTERNAL_ERROR); - return; - } - safestrncpy(filename, file_mail_aliases, sizeof(filename)); - cprintf("%d Settings for <%s>\n", - LISTING_FOLLOWS, - filename); - } - else - { - if ( (CC->room.QRflags & QR_MAILBOX) && (CC->user.usernum == atol(CC->room.QRname)) ) { - /* users can edit the netconfigs for their own mailbox rooms */ - } - else if (CtdlAccessCheck(ac_room_aide)) return; - - assoc_file_name(filename, sizeof filename, &CC->room, ctdl_netcfg_dir); - cprintf("%d Network settings for room #%ld <%s>\n", - LISTING_FOLLOWS, - CC->room.QRnumber, CC->room.QRname); - } - - fp = fopen(filename, "r"); - if (fp != NULL) { - while (fgets(buf, sizeof buf, fp) != NULL) { - buf[strlen(buf)-1] = 0; - cprintf("%s\n", buf); - } - fclose(fp); - } - - cprintf("000\n"); -} - -#define nForceAliases 5 -const ConstStr ForceAliases[nForceAliases] = { - {HKEY("bbs,")}, - {HKEY("root,")}, - {HKEY("Auto,")}, - {HKEY("postmaster,")}, - {HKEY("abuse,")} -}; - -void cmd_snet(char *argbuf) { - char tempfilename[PATH_MAX]; - char filename[PATH_MAX]; - int TmpFD; - StrBuf *Line; - struct stat StatBuf; - long len; - int rc; - int IsMailAlias = 0; - int MailAliasesFound[nForceAliases]; - - unbuffer_output(); - - if (!IsEmptyStr(argbuf)) - { - if (CtdlAccessCheck(ac_aide)) return; - if (strcmp(argbuf, FILE_MAILALIAS)) - { - cprintf("%d No such file or directory\n", - ERROR + INTERNAL_ERROR); - return; - } - len = safestrncpy(filename, file_mail_aliases, sizeof(filename)); - memset(MailAliasesFound, 0, sizeof(MailAliasesFound)); - memcpy(tempfilename, filename, len + 1); - IsMailAlias = 1; - } - else - { - if ( (CC->room.QRflags & QR_MAILBOX) && (CC->user.usernum == atol(CC->room.QRname)) ) { - /* users can edit the netconfigs for their own mailbox rooms */ - } - else if (CtdlAccessCheck(ac_room_aide)) return; - - len = assoc_file_name(filename, sizeof filename, &CC->room, ctdl_netcfg_dir); - memcpy(tempfilename, filename, len + 1); - } - memset(&StatBuf, 0, sizeof(struct stat)); - if ((stat(filename, &StatBuf) == -1) || (StatBuf.st_size == 0)) - StatBuf.st_size = 80; /* Not there or empty? guess 80 chars line. */ - - sprintf(tempfilename + len, ".%d", CC->cs_pid); - errno = 0; - TmpFD = open(tempfilename, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR); - - if ((TmpFD > 0) && (errno == 0)) - { - char *tmp = malloc(StatBuf.st_size * 2); - memset(tmp, ' ', StatBuf.st_size * 2); - rc = write(TmpFD, tmp, StatBuf.st_size * 2); - free(tmp); - if ((rc <= 0) || (rc != StatBuf.st_size * 2)) - { - close(TmpFD); - cprintf("%d Unable to allocate the space required for %s: %s\n", - ERROR + INTERNAL_ERROR, - tempfilename, - strerror(errno)); - unlink(tempfilename); - return; - } - lseek(TmpFD, SEEK_SET, 0); - } - else { - cprintf("%d Unable to allocate the space required for %s: %s\n", - ERROR + INTERNAL_ERROR, - tempfilename, - strerror(errno)); - unlink(tempfilename); - return; - } - Line = NewStrBuf(); - - cprintf("%d %s\n", SEND_LISTING, tempfilename); - - len = 0; - while (rc = CtdlClientGetLine(Line), - (rc >= 0)) - { - if ((rc == 3) && (strcmp(ChrPtr(Line), "000") == 0)) - break; - if (IsMailAlias) - { - int i; - - for (i = 0; i < nForceAliases; i++) - { - if ((!MailAliasesFound[i]) && - (strncmp(ForceAliases[i].Key, - ChrPtr(Line), - ForceAliases[i].len) == 0) - ) - { - MailAliasesFound[i] = 1; - break; - } - } - } - - StrBufAppendBufPlain(Line, HKEY("\n"), 0); - write(TmpFD, ChrPtr(Line), StrLength(Line)); - len += StrLength(Line); - } - FreeStrBuf(&Line); - ftruncate(TmpFD, len); - close(TmpFD); - - if (IsMailAlias) - { - int i, state; - /* - * Sanity check whether all aliases required by the RFCs were set - * else bail out. - */ - state = 1; - for (i = 0; i < nForceAliases; i++) - { - if (!MailAliasesFound[i]) - state = 0; - } - if (state == 0) - { - cprintf("%d won't do this - you're missing an RFC required alias.\n", - ERROR + INTERNAL_ERROR); - unlink(tempfilename); - return; - } - } - - /* Now copy the temp file to its permanent location. - * (We copy instead of link because they may be on different filesystems) - */ - begin_critical_section(S_NETCONFIGS); - rename(tempfilename, filename); - end_critical_section(S_NETCONFIGS); -} - -/* - * cmd_netp() - authenticate to the server as another Citadel node polling - * for network traffic - */ -void cmd_netp(char *cmdbuf) -{ - struct CitContext *CCC = CC; - HashList *working_ignetcfg; - char *node; - StrBuf *NodeStr; - long nodelen; - int v; - long lens[2]; - const char *strs[2]; - - const StrBuf *secret = NULL; - const StrBuf *nexthop = NULL; - char err_buf[SIZ] = ""; - - /* Authenticate */ - node = CCC->curr_user; - nodelen = extract_token(CCC->curr_user, cmdbuf, 0, '|', sizeof CCC->curr_user); - NodeStr = NewStrBufPlain(node, nodelen); - /* load the IGnet Configuration to check node validity */ - working_ignetcfg = load_ignetcfg(); - v = is_valid_node(&nexthop, &secret, NodeStr, working_ignetcfg, NULL); - if (v != 0) { - snprintf(err_buf, sizeof err_buf, - "An unknown Citadel server called \"%s\" attempted to connect from %s [%s].\n", - node, CCC->cs_host, CCC->cs_addr - ); - syslog(LOG_WARNING, "%s", err_buf); - cprintf("%d authentication failed\n", ERROR + PASSWORD_REQUIRED); - - strs[0] = CCC->cs_addr; - lens[0] = strlen(CCC->cs_addr); - - strs[1] = "SRV_UNKNOWN"; - lens[1] = sizeof("SRV_UNKNOWN" - 1); - - CtdlAideFPMessage( - err_buf, - "IGNet Networking.", - 2, strs, (long*) &lens); - - DeleteHash(&working_ignetcfg); - FreeStrBuf(&NodeStr); - return; - } - - extract_token(CCC->user.password, cmdbuf, 1, '|', sizeof CCC->user.password); - if (strcasecmp(CCC->user.password, ChrPtr(secret))) { - snprintf(err_buf, sizeof err_buf, - "A Citadel server at %s [%s] failed to authenticate as network node \"%s\".\n", - CCC->cs_host, CCC->cs_addr, node - ); - syslog(LOG_WARNING, "%s", err_buf); - cprintf("%d authentication failed\n", ERROR + PASSWORD_REQUIRED); - - strs[0] = CCC->cs_addr; - lens[0] = strlen(CCC->cs_addr); - - strs[1] = "SRV_PW"; - lens[1] = sizeof("SRV_PW" - 1); - - CtdlAideFPMessage( - err_buf, - "IGNet Networking.", - 2, strs, (long*) &lens); - - DeleteHash(&working_ignetcfg); - FreeStrBuf(&NodeStr); - return; - } - - if (network_talking_to(node, nodelen, NTT_CHECK)) { - syslog(LOG_WARNING, "Duplicate session for network node <%s>", node); - cprintf("%d Already talking to %s right now\n", ERROR + RESOURCE_BUSY, node); - DeleteHash(&working_ignetcfg); - FreeStrBuf(&NodeStr); - return; - } - nodelen = safestrncpy(CCC->net_node, node, sizeof CCC->net_node); - network_talking_to(CCC->net_node, nodelen, NTT_ADD); - syslog(LOG_NOTICE, "Network node <%s> logged in from %s [%s]\n", - CCC->net_node, CCC->cs_host, CCC->cs_addr - ); - cprintf("%d authenticated as network node '%s'\n", CIT_OK, CCC->net_node); - DeleteHash(&working_ignetcfg); - FreeStrBuf(&NodeStr); -} - -int netconfig_check_roomaccess( - char *errmsgbuf, - size_t n, - const char* RemoteIdentifier) -{ - SpoolControl *sc; - char filename[SIZ]; - int found; - - if (RemoteIdentifier == NULL) - { - snprintf(errmsgbuf, n, "Need sender to permit access."); - return (ERROR + USERNAME_REQUIRED); - } - - assoc_file_name(filename, sizeof filename, &CC->room, ctdl_netcfg_dir); - begin_critical_section(S_NETCONFIGS); - if (!read_spoolcontrol_file(&sc, filename)) - { - end_critical_section(S_NETCONFIGS); - snprintf(errmsgbuf, n, - "This mailing list only accepts posts from subscribers."); - return (ERROR + NO_SUCH_USER); - } - end_critical_section(S_NETCONFIGS); - found = is_recipient (sc->RNCfg, RemoteIdentifier); - free_spoolcontrol_struct(&sc); - if (found) { - return (0); - } - else { - snprintf(errmsgbuf, n, - "This mailing list only accepts posts from subscribers."); - return (ERROR + NO_SUCH_USER); - } -} -/* - * Module entry point - */ -CTDL_MODULE_INIT(netconfig) -{ - if (!threading) - { - CtdlRegisterProtoHook(cmd_gnet, "GNET", "Get network config"); - CtdlRegisterProtoHook(cmd_snet, "SNET", "Set network config"); - CtdlRegisterProtoHook(cmd_netp, "NETP", "Identify as network poller"); - } - return "netconfig"; -} diff --git a/citadel/modules/network/serv_netmail.c b/citadel/modules/network/serv_netmail.c index 2078c32cc..b440105be 100644 --- a/citadel/modules/network/serv_netmail.c +++ b/citadel/modules/network/serv_netmail.c @@ -264,7 +264,7 @@ void network_spool_msg(long msgnum, char *newpath = NULL; struct CtdlMessage *msg = NULL; RoomNetCfgLine *nptr; - maplist *mptr; + MapList *mptr; struct ser_ret sermsg; FILE *fp; char filename[PATH_MAX]; @@ -466,11 +466,11 @@ void network_spool_msg(long msgnum, } Buf = NewStrBufPlain(msg->cm_fields['N'], -1); - if (is_valid_node(NULL, - NULL, - Buf, - sc->working_ignetcfg, - sc->the_netmap) == 0) + if (CtdlIsValidNode(NULL, + NULL, + Buf, + sc->working_ignetcfg, + sc->the_netmap) == 0) { ok_to_participate = 1; } @@ -552,18 +552,18 @@ void network_spool_msg(long msgnum, /* Now send it to every node */ if (sc->RNCfg->NetConfigs[ignet_push_share] != NULL) - for (mptr = (maplist*)sc->RNCfg->NetConfigs[ignet_push_share]; mptr != NULL; + for (mptr = (MapList*)sc->RNCfg->NetConfigs[ignet_push_share]; mptr != NULL; mptr = mptr->next) { send = 1; NewStrBufDupAppendFlush(&Buf, mptr->remote_nodename, NULL, 1); /* Check for valid node name */ - if (is_valid_node(NULL, - NULL, - Buf, - sc->working_ignetcfg, - sc->the_netmap) != 0) + if (CtdlIsValidNode(NULL, + NULL, + Buf, + sc->working_ignetcfg, + sc->the_netmap) != 0) { QN_syslog(LOG_ERR, "Invalid node <%s>\n", diff --git a/citadel/modules/network/serv_netspool.c b/citadel/modules/network/serv_netspool.c index d66161bcc..040930b3e 100644 --- a/citadel/modules/network/serv_netspool.c +++ b/citadel/modules/network/serv_netspool.c @@ -157,37 +157,6 @@ void SerializeIgnetPushShare(const CfgLineType *ThisOne, StrBuf *OutputBuffer, O StrBufAppendBufPlain(OutputBuffer, HKEY("\n"), 0); } -int is_recipient(OneRoomNetCfg *RNCfg, const char *Name) -{ - const RoomNetCfg RecipientCfgs[] = { - listrecp, - digestrecp, - participate, - maxRoomNetCfg - }; - int i; - RoomNetCfgLine *nptr; - size_t len; - - len = strlen(Name); - i = 0; - while (RecipientCfgs[i] != maxRoomNetCfg) - { - nptr = RNCfg->NetConfigs[RecipientCfgs[i]]; - - while (nptr != NULL) - { - if ((StrLength(nptr->Value) == len) && - (!strcmp(Name, ChrPtr(nptr->Value)))) - { - return 1; - } - nptr = nptr->next; - } - } - return 0; -} - /* * Batch up and send all outbound traffic from the current room @@ -313,11 +282,11 @@ void network_process_buffer(char *buffer, long size, HashList *working_ignetcfg, /* route the message */ Buf = NewStrBufPlain(msg->cm_fields['D'], -1); - if (is_valid_node(&nexthop, - NULL, - Buf, - working_ignetcfg, - the_netmap) == 0) + if (CtdlIsValidNode(&nexthop, + NULL, + Buf, + working_ignetcfg, + the_netmap) == 0) { /* prepend our node to the path */ if (msg->cm_fields['P'] != NULL) { @@ -389,10 +358,10 @@ void network_process_buffer(char *buffer, long size, HashList *working_ignetcfg, /* Learn network topology from the path */ if ((msg->cm_fields['N'] != NULL) && (msg->cm_fields['P'] != NULL)) { - network_learn_topology(msg->cm_fields['N'], - msg->cm_fields['P'], - the_netmap, - netmap_changed); + NetworkLearnTopology(msg->cm_fields['N'], + msg->cm_fields['P'], + the_netmap, + netmap_changed); } /* Is the sending node giving us a very persuasive suggestion about @@ -673,7 +642,7 @@ void network_consolidate_spoolout(HashList *working_ignetcfg, HashList *the_netm ChrPtr(NextHop)); QN_syslog(LOG_DEBUG, "Consolidate %s to %s\n", filename, ChrPtr(NextHop)); - if (network_talking_to(SKEY(NextHop), NTT_CHECK)) { + if (CtdlNetworkTalkingTo(SKEY(NextHop), NTT_CHECK)) { nFailed++; QN_syslog(LOG_DEBUG, "Currently online with %s - skipping for now\n", @@ -685,7 +654,7 @@ void network_consolidate_spoolout(HashList *working_ignetcfg, HashList *the_netm size_t fsize; int infd, outfd; const char *err = NULL; - network_talking_to(SKEY(NextHop), NTT_ADD); + CtdlNetworkTalkingTo(SKEY(NextHop), NTT_ADD); infd = open(filename, O_RDONLY); if (infd == -1) { @@ -694,7 +663,7 @@ void network_consolidate_spoolout(HashList *working_ignetcfg, HashList *the_netm "failed to open %s for reading due to %s; skipping.\n", filename, strerror(errno) ); - network_talking_to(SKEY(NextHop), NTT_REMOVE); + CtdlNetworkTalkingTo(SKEY(NextHop), NTT_REMOVE); continue; } @@ -714,7 +683,7 @@ void network_consolidate_spoolout(HashList *working_ignetcfg, HashList *the_netm spooloutfilename, strerror(errno) ); close(infd); - network_talking_to(SKEY(NextHop), NTT_REMOVE); + CtdlNetworkTalkingTo(SKEY(NextHop), NTT_REMOVE); continue; } @@ -748,7 +717,7 @@ void network_consolidate_spoolout(HashList *working_ignetcfg, HashList *the_netm FDIOBufferDelete(&FDIO); close(infd); close(outfd); - network_talking_to(SKEY(NextHop), NTT_REMOVE); + CtdlNetworkTalkingTo(SKEY(NextHop), NTT_REMOVE); } } closedir(dp); @@ -814,11 +783,11 @@ void network_consolidate_spoolout(HashList *working_ignetcfg, HashList *the_netm filedir_entry->d_name ); - i = is_valid_node(&nexthop, - NULL, - NextHop, - working_ignetcfg, - the_netmap); + i = CtdlIsValidNode(&nexthop, + NULL, + NextHop, + working_ignetcfg, + the_netmap); if ( (i != 0) || (StrLength(nexthop) > 0) ) { unlink(filename); diff --git a/citadel/modules/network/serv_network.c b/citadel/modules/network/serv_network.c index 094aedf73..ff579cb5f 100644 --- a/citadel/modules/network/serv_network.c +++ b/citadel/modules/network/serv_network.c @@ -254,7 +254,7 @@ int network_sync_to(char *target_node, long len) } sc.working_ignetcfg = load_ignetcfg(); - sc.the_netmap = read_network_map(); + sc.the_netmap = CtdlReadNetworkMap(); /* Send ALL messages */ num_spooled = CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, NULL, @@ -554,13 +554,13 @@ void network_do_queue(void) return; } /* Load the IGnet Configuration into memory */ - working_ignetcfg = load_ignetcfg(); + working_ignetcfg = CtdlLoadIgNetCfg(); /* * Load the network map and filter list into memory. */ if (!server_shutting_down) - the_netmap = read_network_map(); + the_netmap = CtdlReadNetworkMap(); if (!server_shutting_down) load_network_filter_list(); @@ -612,7 +612,7 @@ void network_do_queue(void) /* Save the network map back to disk */ if (netmap_changed) { - StrBuf *MapStr = SerializeNetworkMap(the_netmap); + StrBuf *MapStr = CtdlSerializeNetworkMap(the_netmap); CtdlPutSysConfig(IGNETMAP, SmashStrBuf(&MapStr)); } @@ -644,60 +644,6 @@ int network_room_handler (struct ctdlroom *room) return 0; } -int NTTDebugEnabled = 0; - -/* - * network_talking_to() -- concurrency checker - */ -static HashList *nttlist = NULL; -int network_talking_to(const char *nodename, long len, int operation) { - - int retval = 0; - HashPos *Pos = NULL; - void *vdata; - - begin_critical_section(S_NTTLIST); - - switch(operation) { - - case NTT_ADD: - if (nttlist == NULL) - nttlist = NewHash(1, NULL); - Put(nttlist, nodename, len, NewStrBufPlain(nodename, len), HFreeStrBuf); - if (NTTDebugEnabled) syslog(LOG_DEBUG, "nttlist: added <%s>\n", nodename); - break; - case NTT_REMOVE: - if ((nttlist == NULL) || - (GetCount(nttlist) == 0)) - break; - Pos = GetNewHashPos(nttlist, 1); - if (GetHashPosFromKey (nttlist, nodename, len, Pos)) - DeleteEntryFromHash(nttlist, Pos); - DeleteHashPos(&Pos); - if (NTTDebugEnabled) syslog(LOG_DEBUG, "nttlist: removed <%s>\n", nodename); - - break; - - case NTT_CHECK: - if ((nttlist == NULL) || - (GetCount(nttlist) == 0)) - break; - if (GetHash(nttlist, nodename, len, &vdata)) - retval ++; - if (NTTDebugEnabled) syslog(LOG_DEBUG, "nttlist: have [%d] <%s>\n", retval, nodename); - break; - } - - end_critical_section(S_NTTLIST); - return(retval); -} - -void cleanup_nttlist(void) -{ - begin_critical_section(S_NTTLIST); - DeleteHash(&nttlist); - end_critical_section(S_NTTLIST); -} @@ -709,7 +655,7 @@ void network_logout_hook(void) * If we were talking to a network node, we're not anymore... */ if (!IsEmptyStr(CCC->net_node)) { - network_talking_to(CCC->net_node, strlen(CCC->net_node), NTT_REMOVE); + CtdlNetworkTalkingTo(CCC->net_node, strlen(CCC->net_node), NTT_REMOVE); CCC->net_node[0] = '\0'; } } @@ -718,7 +664,7 @@ void network_cleanup_function(void) struct CitContext *CCC = CC; if (!IsEmptyStr(CCC->net_node)) { - network_talking_to(CCC->net_node, strlen(CCC->net_node), NTT_REMOVE); + CtdlNetworkTalkingTo(CCC->net_node, strlen(CCC->net_node), NTT_REMOVE); CCC->net_node[0] = '\0'; } } @@ -727,10 +673,7 @@ void network_cleanup_function(void) /* * Module entry point */ -void SetNTTDebugEnabled(const int n) -{ - NTTDebugEnabled = n; -} + void SetNetQDebugEnabled(const int n) { NetQDebugEnabled = n; @@ -741,9 +684,7 @@ CTDL_MODULE_INIT(network) if (!threading) { CtdlFillSystemContext(&networker_spool_CC, "CitNetSpool"); - CtdlRegisterDebugFlagHook(HKEY("networktalkingto"), SetNTTDebugEnabled, &NTTDebugEnabled); CtdlRegisterDebugFlagHook(HKEY("networkqueue"), SetNetQDebugEnabled, &NetQDebugEnabled); - CtdlRegisterCleanupHook(cleanup_nttlist); CtdlRegisterSessionHook(network_cleanup_function, EVT_STOP, PRIO_STOP + 30); CtdlRegisterSessionHook(network_logout_hook, EVT_LOGOUT, PRIO_LOGOUT + 10); CtdlRegisterProtoHook(cmd_nsyn, "NSYN", "Synchronize room to node"); diff --git a/citadel/modules/network/serv_network.h b/citadel/modules/network/serv_network.h index 1cc61f460..7de793905 100644 --- a/citadel/modules/network/serv_network.h +++ b/citadel/modules/network/serv_network.h @@ -42,13 +42,3 @@ void network_queue_room(struct ctdlroom *, void *); void network_bounce(struct CtdlMessage *msg, char *reason); int network_usetable(struct CtdlMessage *msg); -int network_talking_to(const char *nodename, long len, int operation); - -/* - * Operations that can be performed by network_talking_to() - */ -enum { - NTT_ADD, - NTT_REMOVE, - NTT_CHECK -}; diff --git a/citadel/modules/network/serv_networkclient.c b/citadel/modules/network/serv_networkclient.c index 92ae1f78b..c3cd1e700 100644 --- a/citadel/modules/network/serv_networkclient.c +++ b/citadel/modules/network/serv_networkclient.c @@ -71,7 +71,6 @@ #include "citadel_dirs.h" #include "threads.h" #include "context.h" -#include "netconfig.h" #include "ctdl_module.h" struct CitContext networker_client_CC; @@ -220,7 +219,7 @@ eNextState FinalizeNetworker(AsyncIO *IO) { AsyncNetworker *NW = (AsyncNetworker *)IO->Data; - network_talking_to(SKEY(NW->node), NTT_REMOVE); + CtdlNetworkTalkingTo(SKEY(NW->node), NTT_REMOVE); DeleteNetworker(IO->Data); return eAbort; @@ -957,7 +956,7 @@ static int NetworkerCount = 0; void RunNetworker(AsyncNetworker *NW) { NW->n = NetworkerCount++; - network_talking_to(SKEY(NW->node), NTT_ADD); + CtdlNetworkTalkingTo(SKEY(NW->node), NTT_ADD); syslog(LOG_DEBUG, "NW[%s][%ld]: polling\n", ChrPtr(NW->node), NW->n); ParseURL(&NW->IO.ConnectMe, NW->Url, 504); @@ -1021,7 +1020,7 @@ void network_poll_other_citadel_nodes(int full_poll, HashList *ignetcfg) /* Use the string tokenizer to grab one line at a time */ if(server_shutting_down) return;/* TODO free stuff*/ - NodeConf *pNode = (NodeConf*) vCfg; + CtdlNodeConf *pNode = (CtdlNodeConf*) vCfg; poll = 0; NW = (AsyncNetworker*)malloc(sizeof(AsyncNetworker)); memset(NW, 0, sizeof(AsyncNetworker)); @@ -1057,7 +1056,7 @@ void network_poll_other_citadel_nodes(int full_poll, HashList *ignetcfg) ChrPtr(NW->secret), ChrPtr(NW->host), ChrPtr(NW->port)); - if (!network_talking_to(SKEY(NW->node), NTT_CHECK)) + if (!CtdlNetworkTalkingTo(SKEY(NW->node), NTT_CHECK)) { RunNetworker(NW); continue; @@ -1087,7 +1086,7 @@ void network_do_clientqueue(void) ); } - working_ignetcfg = load_ignetcfg(); + working_ignetcfg = CtdlLoadIgNetCfg(); /* * Poll other Citadel nodes. Maybe. If "full_processing" is set * then we poll everyone. Otherwise we only poll nodes we have stuff diff --git a/citadel/msgbase.c b/citadel/msgbase.c index dc407afdc..6320144f4 100644 --- a/citadel/msgbase.c +++ b/citadel/msgbase.c @@ -4011,11 +4011,6 @@ struct CtdlMessage *CtdlMakeMessage( return(msg); } -extern int netconfig_check_roomaccess( - char *errmsgbuf, - size_t n, - const char* RemoteIdentifier); /* TODO: find a smarter way */ - /* * Check to see whether we have permission to post a message in the current * room. Returns a *CITADEL ERROR CODE* and puts a message in errmsgbuf, or @@ -4050,7 +4045,7 @@ int CtdlDoIHavePermissionToPostInThisRoom( } if ((PostPublic!=POST_LMTP) &&(CC->room.QRflags2 & QR2_SMTP_PUBLIC) == 0) { - return netconfig_check_roomaccess(errmsgbuf, n, RemoteIdentifier); + return CtdlNetconfigCheckRoomaccess(errmsgbuf, n, RemoteIdentifier); } return (0); diff --git a/citadel/netconfig.c b/citadel/netconfig.c index 3c20541c0..6137bd3d4 100644 --- a/citadel/netconfig.c +++ b/citadel/netconfig.c @@ -30,8 +30,9 @@ #include "include/ctdl_module.h" HashList *CfgTypeHash = NULL; - - +/*-----------------------------------------------------------------------------* + * Per room network configs * + *-----------------------------------------------------------------------------*/ void RegisterRoomCfgType(const char* Name, long len, RoomNetCfg eCfg, CfgLineParser p, int uniq, CfgLineSerializer s, CfgLineDeAllocator d) { CfgLineType *pCfg; @@ -276,3 +277,646 @@ void free_spoolcontrol_struct(OneRoomNetCfg **pOneRNCFG) *pOneRNCFG=NULL; } + +/*-----------------------------------------------------------------------------* + * Per room network configs : exchange with client * + *-----------------------------------------------------------------------------*/ +void cmd_gnet(char *argbuf) +{ + char filename[PATH_MAX]; + char buf[SIZ]; + FILE *fp; + + + if (!IsEmptyStr(argbuf)) + { + if (CtdlAccessCheck(ac_aide)) return; + if (strcmp(argbuf, FILE_MAILALIAS)) + { + cprintf("%d No such file or directory\n", + ERROR + INTERNAL_ERROR); + return; + } + safestrncpy(filename, file_mail_aliases, sizeof(filename)); + cprintf("%d Settings for <%s>\n", + LISTING_FOLLOWS, + filename); + } + else + { + if ( (CC->room.QRflags & QR_MAILBOX) && (CC->user.usernum == atol(CC->room.QRname)) ) { + /* users can edit the netconfigs for their own mailbox rooms */ + } + else if (CtdlAccessCheck(ac_room_aide)) return; + + assoc_file_name(filename, sizeof filename, &CC->room, ctdl_netcfg_dir); + cprintf("%d Network settings for room #%ld <%s>\n", + LISTING_FOLLOWS, + CC->room.QRnumber, CC->room.QRname); + } + + fp = fopen(filename, "r"); + if (fp != NULL) { + while (fgets(buf, sizeof buf, fp) != NULL) { + buf[strlen(buf)-1] = 0; + cprintf("%s\n", buf); + } + fclose(fp); + } + + cprintf("000\n"); +} + +#define nForceAliases 5 +const ConstStr ForceAliases[nForceAliases] = { + {HKEY("bbs,")}, + {HKEY("root,")}, + {HKEY("Auto,")}, + {HKEY("postmaster,")}, + {HKEY("abuse,")} +}; + +void cmd_snet(char *argbuf) { + char tempfilename[PATH_MAX]; + char filename[PATH_MAX]; + int TmpFD; + StrBuf *Line; + struct stat StatBuf; + long len; + int rc; + int IsMailAlias = 0; + int MailAliasesFound[nForceAliases]; + + unbuffer_output(); + + if (!IsEmptyStr(argbuf)) + { + if (CtdlAccessCheck(ac_aide)) return; + if (strcmp(argbuf, FILE_MAILALIAS)) + { + cprintf("%d No such file or directory\n", + ERROR + INTERNAL_ERROR); + return; + } + len = safestrncpy(filename, file_mail_aliases, sizeof(filename)); + memset(MailAliasesFound, 0, sizeof(MailAliasesFound)); + memcpy(tempfilename, filename, len + 1); + IsMailAlias = 1; + } + else + { + if ( (CC->room.QRflags & QR_MAILBOX) && (CC->user.usernum == atol(CC->room.QRname)) ) { + /* users can edit the netconfigs for their own mailbox rooms */ + } + else if (CtdlAccessCheck(ac_room_aide)) return; + + len = assoc_file_name(filename, sizeof filename, &CC->room, ctdl_netcfg_dir); + memcpy(tempfilename, filename, len + 1); + } + memset(&StatBuf, 0, sizeof(struct stat)); + if ((stat(filename, &StatBuf) == -1) || (StatBuf.st_size == 0)) + StatBuf.st_size = 80; /* Not there or empty? guess 80 chars line. */ + + sprintf(tempfilename + len, ".%d", CC->cs_pid); + errno = 0; + TmpFD = open(tempfilename, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR); + + if ((TmpFD > 0) && (errno == 0)) + { + char *tmp = malloc(StatBuf.st_size * 2); + memset(tmp, ' ', StatBuf.st_size * 2); + rc = write(TmpFD, tmp, StatBuf.st_size * 2); + free(tmp); + if ((rc <= 0) || (rc != StatBuf.st_size * 2)) + { + close(TmpFD); + cprintf("%d Unable to allocate the space required for %s: %s\n", + ERROR + INTERNAL_ERROR, + tempfilename, + strerror(errno)); + unlink(tempfilename); + return; + } + lseek(TmpFD, SEEK_SET, 0); + } + else { + cprintf("%d Unable to allocate the space required for %s: %s\n", + ERROR + INTERNAL_ERROR, + tempfilename, + strerror(errno)); + unlink(tempfilename); + return; + } + Line = NewStrBuf(); + + cprintf("%d %s\n", SEND_LISTING, tempfilename); + + len = 0; + while (rc = CtdlClientGetLine(Line), + (rc >= 0)) + { + if ((rc == 3) && (strcmp(ChrPtr(Line), "000") == 0)) + break; + if (IsMailAlias) + { + int i; + + for (i = 0; i < nForceAliases; i++) + { + if ((!MailAliasesFound[i]) && + (strncmp(ForceAliases[i].Key, + ChrPtr(Line), + ForceAliases[i].len) == 0) + ) + { + MailAliasesFound[i] = 1; + break; + } + } + } + + StrBufAppendBufPlain(Line, HKEY("\n"), 0); + write(TmpFD, ChrPtr(Line), StrLength(Line)); + len += StrLength(Line); + } + FreeStrBuf(&Line); + ftruncate(TmpFD, len); + close(TmpFD); + + if (IsMailAlias) + { + int i, state; + /* + * Sanity check whether all aliases required by the RFCs were set + * else bail out. + */ + state = 1; + for (i = 0; i < nForceAliases; i++) + { + if (!MailAliasesFound[i]) + state = 0; + } + if (state == 0) + { + cprintf("%d won't do this - you're missing an RFC required alias.\n", + ERROR + INTERNAL_ERROR); + unlink(tempfilename); + return; + } + } + + /* Now copy the temp file to its permanent location. + * (We copy instead of link because they may be on different filesystems) + */ + begin_critical_section(S_NETCONFIGS); + rename(tempfilename, filename); + end_critical_section(S_NETCONFIGS); +} + + +/*-----------------------------------------------------------------------------* + * Per node network configs * + *-----------------------------------------------------------------------------*/ +void DeleteCtdlNodeConf(void *vNode) +{ + CtdlNodeConf *Node = (CtdlNodeConf*) vNode; + FreeStrBuf(&Node->NodeName); + FreeStrBuf(&Node->Secret); + FreeStrBuf(&Node->Host); + FreeStrBuf(&Node->Port); + free(Node); +} + +CtdlNodeConf *NewNode(StrBuf *SerializedNode) +{ + const char *Pos = NULL; + CtdlNodeConf *Node; + + /* we need at least 4 pipes and some other text so its invalid. */ + if (StrLength(SerializedNode) < 8) + return NULL; + Node = (CtdlNodeConf *) malloc(sizeof(CtdlNodeConf)); + + Node->DeleteMe = 0; + + Node->NodeName=NewStrBuf(); + StrBufExtract_NextToken(Node->NodeName, SerializedNode, &Pos, '|'); + + Node->Secret=NewStrBuf(); + StrBufExtract_NextToken(Node->Secret, SerializedNode, &Pos, '|'); + + Node->Host=NewStrBuf(); + StrBufExtract_NextToken(Node->Host, SerializedNode, &Pos, '|'); + + Node->Port=NewStrBuf(); + StrBufExtract_NextToken(Node->Port, SerializedNode, &Pos, '|'); + return Node; +} + + +/* + * Load or refresh the Citadel network (IGnet) configuration for this node. + */ +HashList* CtdlLoadIgNetCfg(void) +{ + const char *LinePos; + char *Cfg; + StrBuf *Buf; + StrBuf *LineBuf; + HashList *Hash; + CtdlNodeConf *Node; + + Cfg = CtdlGetSysConfig(IGNETCFG); + if ((Cfg == NULL) || IsEmptyStr(Cfg)) { + if (Cfg != NULL) + free(Cfg); + return NULL; + } + + Hash = NewHash(1, NULL); + Buf = NewStrBufPlain(Cfg, -1); + free(Cfg); + LineBuf = NewStrBufPlain(NULL, StrLength(Buf)); + LinePos = NULL; + do + { + StrBufSipLine(LineBuf, Buf, &LinePos); + if (StrLength(LineBuf) != 0) { + Node = NewNode(LineBuf); + if (Node != NULL) { + Put(Hash, SKEY(Node->NodeName), Node, DeleteCtdlNodeConf); + } + } + } while (LinePos != StrBufNOTNULL); + FreeStrBuf(&Buf); + FreeStrBuf(&LineBuf); + return Hash; +} + + +int is_recipient(OneRoomNetCfg *RNCfg, const char *Name) +{ + const RoomNetCfg RecipientCfgs[] = { + listrecp, + digestrecp, + participate, + maxRoomNetCfg + }; + int i; + RoomNetCfgLine *nptr; + size_t len; + + len = strlen(Name); + i = 0; + while (RecipientCfgs[i] != maxRoomNetCfg) + { + nptr = RNCfg->NetConfigs[RecipientCfgs[i]]; + + while (nptr != NULL) + { + if ((StrLength(nptr->Value) == len) && + (!strcmp(Name, ChrPtr(nptr->Value)))) + { + return 1; + } + nptr = nptr->next; + } + } + return 0; +} + + + +int CtdlNetconfigCheckRoomaccess( + char *errmsgbuf, + size_t n, + const char* RemoteIdentifier) +{ + OneRoomNetCfg *RNCfg; + char filename[SIZ]; + int found; + + if (RemoteIdentifier == NULL) + { + snprintf(errmsgbuf, n, "Need sender to permit access."); + return (ERROR + USERNAME_REQUIRED); + } + + assoc_file_name(filename, sizeof filename, &CC->room, ctdl_netcfg_dir); + begin_critical_section(S_NETCONFIGS); + if (!read_spoolcontrol_file(&RNCfg, filename)) + { + end_critical_section(S_NETCONFIGS); + snprintf(errmsgbuf, n, + "This mailing list only accepts posts from subscribers."); + return (ERROR + NO_SUCH_USER); + } + end_critical_section(S_NETCONFIGS); + found = is_recipient (RNCfg, RemoteIdentifier); + free_spoolcontrol_struct(&RNCfg); + if (found) { + return (0); + } + else { + snprintf(errmsgbuf, n, + "This mailing list only accepts posts from subscribers."); + return (ERROR + NO_SUCH_USER); + } +} + + + +/* + * cmd_netp() - authenticate to the server as another Citadel node polling + * for network traffic + */ +void cmd_netp(char *cmdbuf) +{ + struct CitContext *CCC = CC; + HashList *working_ignetcfg; + char *node; + StrBuf *NodeStr; + long nodelen; + int v; + long lens[2]; + const char *strs[2]; + + const StrBuf *secret = NULL; + const StrBuf *nexthop = NULL; + char err_buf[SIZ] = ""; + + /* Authenticate */ + node = CCC->curr_user; + nodelen = extract_token(CCC->curr_user, cmdbuf, 0, '|', sizeof CCC->curr_user); + NodeStr = NewStrBufPlain(node, nodelen); + /* load the IGnet Configuration to check node validity */ + working_ignetcfg = CtdlLoadIgNetCfg(); + v = CtdlIsValidNode(&nexthop, &secret, NodeStr, working_ignetcfg, NULL); + if (v != 0) { + snprintf(err_buf, sizeof err_buf, + "An unknown Citadel server called \"%s\" attempted to connect from %s [%s].\n", + node, CCC->cs_host, CCC->cs_addr + ); + syslog(LOG_WARNING, "%s", err_buf); + cprintf("%d authentication failed\n", ERROR + PASSWORD_REQUIRED); + + strs[0] = CCC->cs_addr; + lens[0] = strlen(CCC->cs_addr); + + strs[1] = "SRV_UNKNOWN"; + lens[1] = sizeof("SRV_UNKNOWN" - 1); + + CtdlAideFPMessage( + err_buf, + "IGNet Networking.", + 2, strs, (long*) &lens); + + DeleteHash(&working_ignetcfg); + FreeStrBuf(&NodeStr); + return; + } + + extract_token(CCC->user.password, cmdbuf, 1, '|', sizeof CCC->user.password); + if (strcasecmp(CCC->user.password, ChrPtr(secret))) { + snprintf(err_buf, sizeof err_buf, + "A Citadel server at %s [%s] failed to authenticate as network node \"%s\".\n", + CCC->cs_host, CCC->cs_addr, node + ); + syslog(LOG_WARNING, "%s", err_buf); + cprintf("%d authentication failed\n", ERROR + PASSWORD_REQUIRED); + + strs[0] = CCC->cs_addr; + lens[0] = strlen(CCC->cs_addr); + + strs[1] = "SRV_PW"; + lens[1] = sizeof("SRV_PW" - 1); + + CtdlAideFPMessage( + err_buf, + "IGNet Networking.", + 2, strs, (long*) &lens); + + DeleteHash(&working_ignetcfg); + FreeStrBuf(&NodeStr); + return; + } + + if (CtdlNetworkTalkingTo(node, nodelen, NTT_CHECK)) { + syslog(LOG_WARNING, "Duplicate session for network node <%s>", node); + cprintf("%d Already talking to %s right now\n", ERROR + RESOURCE_BUSY, node); + DeleteHash(&working_ignetcfg); + FreeStrBuf(&NodeStr); + return; + } + nodelen = safestrncpy(CCC->net_node, node, sizeof CCC->net_node); + CtdlNetworkTalkingTo(CCC->net_node, nodelen, NTT_ADD); + syslog(LOG_NOTICE, "Network node <%s> logged in from %s [%s]\n", + CCC->net_node, CCC->cs_host, CCC->cs_addr + ); + cprintf("%d authenticated as network node '%s'\n", CIT_OK, CCC->net_node); + DeleteHash(&working_ignetcfg); + FreeStrBuf(&NodeStr); +} + + +/*-----------------------------------------------------------------------------* + * Network maps: evaluate other nodes * + *-----------------------------------------------------------------------------*/ + +void DeleteNetMap(void *vNetMap) +{ + CtdlNetMap *TheNetMap = (CtdlNetMap*) vNetMap; + FreeStrBuf(&TheNetMap->NodeName); + FreeStrBuf(&TheNetMap->NextHop); + free(TheNetMap); +} + +CtdlNetMap *NewNetMap(StrBuf *SerializedNetMap) +{ + const char *Pos = NULL; + CtdlNetMap *NM; + + /* we need at least 3 pipes and some other text so its invalid. */ + if (StrLength(SerializedNetMap) < 6) + return NULL; + NM = (CtdlNetMap *) malloc(sizeof(CtdlNetMap)); + + NM->NodeName=NewStrBuf(); + StrBufExtract_NextToken(NM->NodeName, SerializedNetMap, &Pos, '|'); + + NM->lastcontact = StrBufExtractNext_long(SerializedNetMap, &Pos, '|'); + + NM->NextHop=NewStrBuf(); + StrBufExtract_NextToken(NM->NextHop, SerializedNetMap, &Pos, '|'); + + return NM; +} + +HashList* CtdlReadNetworkMap(void) +{ + const char *LinePos; + char *Cfg; + StrBuf *Buf; + StrBuf *LineBuf; + HashList *Hash; + CtdlNetMap *TheNetMap; + + Cfg = CtdlGetSysConfig(IGNETMAP); + if ((Cfg == NULL) || IsEmptyStr(Cfg)) { + if (Cfg != NULL) + free(Cfg); + return NULL; + } + + Hash = NewHash(1, NULL); + Buf = NewStrBufPlain(Cfg, -1); + free(Cfg); + LineBuf = NewStrBufPlain(NULL, StrLength(Buf)); + LinePos = NULL; + while (StrBufSipLine(Buf, LineBuf, &LinePos)) + { + TheNetMap = NewNetMap(LineBuf); + if (TheNetMap != NULL) { /* TODO: is the NodeName Uniq? */ + Put(Hash, SKEY(TheNetMap->NodeName), TheNetMap, DeleteNetMap); + } + } + FreeStrBuf(&Buf); + FreeStrBuf(&LineBuf); + return Hash; +} + +StrBuf *CtdlSerializeNetworkMap(HashList *Map) +{ + void *vMap; + const char *key; + long len; + StrBuf *Ret = NewStrBuf(); + HashPos *Pos = GetNewHashPos(Map, 0); + + while (GetNextHashPos(Map, Pos, &len, &key, &vMap)) + { + CtdlNetMap *pMap = (CtdlNetMap*) vMap; + StrBufAppendBuf(Ret, pMap->NodeName, 0); + StrBufAppendBufPlain(Ret, HKEY("|"), 0); + + StrBufAppendPrintf(Ret, "%ld", pMap->lastcontact, 0); + StrBufAppendBufPlain(Ret, HKEY("|"), 0); + + StrBufAppendBuf(Ret, pMap->NextHop, 0); + StrBufAppendBufPlain(Ret, HKEY("\n"), 0); + } + DeleteHashPos(&Pos); + return Ret; +} + + +/* + * Learn topology from path fields + */ +void NetworkLearnTopology(char *node, char *path, HashList *the_netmap, int *netmap_changed) +{ + CtdlNetMap *pNM = NULL; + void *vptr; + char nexthop[256]; + CtdlNetMap *nmptr; + + if (GetHash(the_netmap, node, strlen(node), &vptr) && + (vptr != NULL))/* TODO: is the NodeName Uniq? */ + { + pNM = (CtdlNetMap*)vptr; + extract_token(nexthop, path, 0, '!', sizeof nexthop); + if (!strcmp(nexthop, ChrPtr(pNM->NextHop))) { + pNM->lastcontact = time(NULL); + (*netmap_changed) ++; + return; + } + } + + /* If we got here then it's not in the map, so add it. */ + nmptr = (CtdlNetMap *) malloc(sizeof (CtdlNetMap)); + nmptr->NodeName = NewStrBufPlain(node, -1); + nmptr->lastcontact = time(NULL); + nmptr->NextHop = NewStrBuf (); + StrBufExtract_tokenFromStr(nmptr->NextHop, path, strlen(path), 0, '!'); + /* TODO: is the NodeName Uniq? */ + Put(the_netmap, SKEY(nmptr->NodeName), nmptr, DeleteNetMap); + (*netmap_changed) ++; +} + + +/* + * Check the network map and determine whether the supplied node name is + * valid. If it is not a neighbor node, supply the name of a neighbor node + * which is the next hop. If it *is* a neighbor node, we also fill in the + * shared secret. + */ +int CtdlIsValidNode(const StrBuf **nexthop, + const StrBuf **secret, + StrBuf *node, + HashList *IgnetCfg, + HashList *the_netmap) +{ + void *vNetMap; + void *vNodeConf; + CtdlNodeConf *TheNode; + CtdlNetMap *TheNetMap; + + if (StrLength(node) == 0) { + return(-1); + } + + /* + * First try the neighbor nodes + */ + if (GetCount(IgnetCfg) == 0) { + syslog(LOG_INFO, "IgnetCfg is empty!\n"); + if (nexthop != NULL) { + *nexthop = NULL; + } + return(-1); + } + + /* try to find a neigbour with the name 'node' */ + if (GetHash(IgnetCfg, SKEY(node), &vNodeConf) && + (vNodeConf != NULL)) + { + TheNode = (CtdlNodeConf*)vNodeConf; + if (secret != NULL) + *secret = TheNode->Secret; + return 0; /* yup, it's a direct neighbor */ + } + + /* + * If we get to this point we have to see if we know the next hop + *//* TODO: is the NodeName Uniq? */ + if ((GetCount(the_netmap) > 0) && + (GetHash(the_netmap, SKEY(node), &vNetMap))) + { + TheNetMap = (CtdlNetMap*)vNetMap; + if (nexthop != NULL) + *nexthop = TheNetMap->NextHop; + return(0); + } + + /* + * If we get to this point, the supplied node name is bogus. + */ + syslog(LOG_ERR, "Invalid node name <%s>\n", ChrPtr(node)); + return(-1); +} + + +/* + * Module entry point + */ +CTDL_MODULE_INIT(netconfig) +{ + if (!threading) + { + + CtdlRegisterProtoHook(cmd_gnet, "GNET", "Get network config"); + CtdlRegisterProtoHook(cmd_snet, "SNET", "Set network config"); + CtdlRegisterProtoHook(cmd_netp, "NETP", "Identify as network poller"); + } + return "netconfig"; +} diff --git a/citadel/nttlist.c b/citadel/nttlist.c new file mode 100644 index 000000000..5831d4a7d --- /dev/null +++ b/citadel/nttlist.c @@ -0,0 +1,105 @@ +/* + * This module handles shared rooms, inter-Citadel mail, and outbound + * mailing list processing. + * + * Copyright (c) 2000-2012 by the citadel.org team + * + * This program is open source software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "sysdep.h" +#include +#include +#include "ctdl_module.h" +#include "serv_extensions.h" + +/*-----------------------------------------------------------------------------* + * Network maps: evaluate other nodes * + *-----------------------------------------------------------------------------*/ +int NTTDebugEnabled = 0; + +/* + * network_talking_to() -- concurrency checker + */ +static HashList *nttlist = NULL; +int CtdlNetworkTalkingTo(const char *nodename, long len, int operation) +{ + + int retval = 0; + HashPos *Pos = NULL; + void *vdata; + + begin_critical_section(S_NTTLIST); + + switch(operation) { + + case NTT_ADD: + if (nttlist == NULL) + nttlist = NewHash(1, NULL); + Put(nttlist, nodename, len, NewStrBufPlain(nodename, len), HFreeStrBuf); + if (NTTDebugEnabled) syslog(LOG_DEBUG, "nttlist: added <%s>\n", nodename); + break; + case NTT_REMOVE: + if ((nttlist == NULL) || + (GetCount(nttlist) == 0)) + break; + Pos = GetNewHashPos(nttlist, 1); + if (GetHashPosFromKey (nttlist, nodename, len, Pos)) + DeleteEntryFromHash(nttlist, Pos); + DeleteHashPos(&Pos); + if (NTTDebugEnabled) syslog(LOG_DEBUG, "nttlist: removed <%s>\n", nodename); + + break; + + case NTT_CHECK: + if ((nttlist == NULL) || + (GetCount(nttlist) == 0)) + break; + if (GetHash(nttlist, nodename, len, &vdata)) + retval ++; + if (NTTDebugEnabled) syslog(LOG_DEBUG, "nttlist: have [%d] <%s>\n", retval, nodename); + break; + } + + end_critical_section(S_NTTLIST); + return(retval); +} + +void cleanup_nttlist(void) +{ + begin_critical_section(S_NTTLIST); + DeleteHash(&nttlist); + end_critical_section(S_NTTLIST); +} + + + +/* + * Module entry point + */ +void SetNTTDebugEnabled(const int n) +{ + NTTDebugEnabled = n; +} + + + +/* + * Module entry point + */ +CTDL_MODULE_INIT(nttlist) +{ + if (!threading) + { + CtdlRegisterDebugFlagHook(HKEY("networktalkingto"), SetNTTDebugEnabled, &NTTDebugEnabled); + + CtdlRegisterCleanupHook(cleanup_nttlist); + } + return "nttlist"; +} -- 2.30.2