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
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)
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
-/*
- * 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);
*
*/
-typedef struct maplist maplist;
+typedef struct MapList MapList;
-struct maplist {
- struct maplist *next;
+struct MapList {
+ MapList *next;
StrBuf *remote_nodename;
StrBuf *remote_roomname;
};
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);
-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";
-}
char *newpath = NULL;
struct CtdlMessage *msg = NULL;
RoomNetCfgLine *nptr;
- maplist *mptr;
+ MapList *mptr;
struct ser_ret sermsg;
FILE *fp;
char filename[PATH_MAX];
}
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;
}
/* 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",
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
/* 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) {
/* 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
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",
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) {
"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;
}
spooloutfilename, strerror(errno)
);
close(infd);
- network_talking_to(SKEY(NextHop), NTT_REMOVE);
+ CtdlNetworkTalkingTo(SKEY(NextHop), NTT_REMOVE);
continue;
}
FDIOBufferDelete(&FDIO);
close(infd);
close(outfd);
- network_talking_to(SKEY(NextHop), NTT_REMOVE);
+ CtdlNetworkTalkingTo(SKEY(NextHop), NTT_REMOVE);
}
}
closedir(dp);
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);
}
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,
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();
/* Save the network map back to disk */
if (netmap_changed) {
- StrBuf *MapStr = SerializeNetworkMap(the_netmap);
+ StrBuf *MapStr = CtdlSerializeNetworkMap(the_netmap);
CtdlPutSysConfig(IGNETMAP, SmashStrBuf(&MapStr));
}
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);
-}
* 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';
}
}
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';
}
}
/*
* Module entry point
*/
-void SetNTTDebugEnabled(const int n)
-{
- NTTDebugEnabled = n;
-}
+
void SetNetQDebugEnabled(const int n)
{
NetQDebugEnabled = n;
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");
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
-};
#include "citadel_dirs.h"
#include "threads.h"
#include "context.h"
-#include "netconfig.h"
#include "ctdl_module.h"
struct CitContext networker_client_CC;
{
AsyncNetworker *NW = (AsyncNetworker *)IO->Data;
- network_talking_to(SKEY(NW->node), NTT_REMOVE);
+ CtdlNetworkTalkingTo(SKEY(NW->node), NTT_REMOVE);
DeleteNetworker(IO->Data);
return eAbort;
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);
/* 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));
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;
);
}
- 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
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
}
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);
#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;
*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";
+}
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <libcitadel.h>
+#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";
+}