SNET: fix writing of files.
[citadel.git] / citadel / modules / network / serv_netconfig.c
index 4f5eac42194a6c97f9f36791640262cd807c5719..12662f066564a786d71137f963c92dcb3e14715b 100644 (file)
@@ -2,22 +2,16 @@
  * This module handles shared rooms, inter-Citadel mail, and outbound
  * mailing list processing.
  *
- * Copyright (c) 2000-2011 by the citadel.org team
+ * 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.
+ *  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.
  *
- *  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
 #include "file_ops.h"
 #include "citadel_dirs.h"
 #include "threads.h"
-
-#ifndef HAVE_SNPRINTF
-#include "snprintf.h"
-#endif
-
 #include "context.h"
 #include "netconfig.h"
 #include "netspool.h"
 #include "ctdl_module.h"
 
 
+
+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.
  */
-char* load_working_ignetcfg(void) {
-       return CtdlGetSysConfig(IGNETCFG);
+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);
+}
 
-/* 
- * Read the network map from its configuration file into memory.
- */
-NetMap *read_network_map(void) {
-       char *serialized_map = NULL;
-       int i;
-       char buf[SIZ];
-       NetMap *nmptr, *the_netmap;
-
-       the_netmap = NULL;
-       serialized_map = CtdlGetSysConfig(IGNETMAP);
-       if (serialized_map == NULL) return NULL;        /* if null, no entries */
-
-       /* Use the string tokenizer to grab one line at a time */
-       for (i=0; i<num_tokens(serialized_map, '\n'); ++i) {
-               extract_token(buf, serialized_map, i, '\n', sizeof buf);
-               nmptr = (NetMap *) malloc(sizeof(NetMap));
-               extract_token(nmptr->nodename, buf, 0, '|', sizeof nmptr->nodename);
-               nmptr->lastcontact = extract_long(buf, 1);
-               extract_token(nmptr->nexthop, buf, 2, '|', sizeof nmptr->nexthop);
-               nmptr->next = the_netmap;
-               the_netmap = nmptr;
+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;
        }
 
-       free(serialized_map);
-       return the_netmap;
+       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;
 }
 
 
 /*
- * Write the network map from memory back to the configuration file.
+ * Learn topology from path fields
  */
-void write_network_map(NetMap *the_netmap, int netmap_changed) {
-       char *serialized_map = NULL;
+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 (netmap_changed) {
-               serialized_map = strdup("");
-       
-               if (the_netmap != NULL) {
-                       for (nmptr = the_netmap; nmptr != NULL; nmptr = nmptr->next) {
-                               serialized_map = realloc(serialized_map,
-                                                       (strlen(serialized_map)+SIZ) );
-                               if (!IsEmptyStr(nmptr->nodename)) {
-                                       snprintf(&serialized_map[strlen(serialized_map)],
-                                               SIZ,
-                                               "%s|%ld|%s\n",
-                                               nmptr->nodename,
-                                               (long)nmptr->lastcontact,
-                                               nmptr->nexthop);
-                               }
-                       }
+       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;
                }
-
-               CtdlPutSysConfig(IGNETMAP, serialized_map);
-               free(serialized_map);
        }
 
-       /* Now free the list */
-       while (the_netmap != NULL) {
-               nmptr = the_netmap->next;
-               free(the_netmap);
-               the_netmap = nmptr;
-       }
-       netmap_changed = 0;
+       /* 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(char *nexthop, 
-                 char *secret, 
-                 char *node, 
-                 char *working_ignetcfg, 
-                 NetMap *the_netmap)
+int is_valid_node(const StrBuf **nexthop,
+                 const StrBuf **secret,
+                 StrBuf *node,
+                 HashList *IgnetCfg,
+                 HashList *the_netmap)
 {
-       int i;
-       char linebuf[SIZ];
-       char buf[SIZ];
-       int retval;
-       NetMap *nmptr;
+       void *vNetMap;
+       void *vNodeConf;
+       NodeConf *TheNode;
+       NetMap *TheNetMap;
 
-       if (node == NULL) {
+       if (StrLength(node) == 0) {
                return(-1);
        }
 
        /*
         * First try the neighbor nodes
         */
-       if ((working_ignetcfg == NULL) || (*working_ignetcfg == '\0')) {
-               syslog(LOG_ERR, "working_ignetcfg is empty!\n");
+       if (GetCount(IgnetCfg) == 0) {
+               syslog(LOG_INFO, "IgnetCfg is empty!\n");
                if (nexthop != NULL) {
-                       strcpy(nexthop, "");
+                       *nexthop = NULL;
                }
                return(-1);
        }
 
-       retval = (-1);
-       if (nexthop != NULL) {
-               strcpy(nexthop, "");
-       }
-
-       /* Use the string tokenizer to grab one line at a time */
-       for (i=0; i<num_tokens(working_ignetcfg, '\n'); ++i) {
-               extract_token(linebuf, working_ignetcfg, i, '\n', sizeof linebuf);
-               extract_token(buf, linebuf, 0, '|', sizeof buf);
-               if (!strcasecmp(buf, node)) {
-                       if (nexthop != NULL) {
-                               strcpy(nexthop, "");
-                       }
-                       if (secret != NULL) {
-                               extract_token(secret, linebuf, 1, '|', 256);
-                       }
-                       retval = 0;
-               }
-       }
-
-       if (retval == 0) {
-               return(retval);         /* yup, it's a direct neighbor */
+       /* 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
-        */
-       if (the_netmap != NULL) {
-               for (nmptr = the_netmap; nmptr != NULL; nmptr = nmptr->next) {
-                       if (!strcasecmp(nmptr->nodename, node)) {
-                               if (nexthop != NULL) {
-                                       strcpy(nexthop, nmptr->nexthop);
-                               }
-                               return(0);
-                       }
-               }
+        *//* 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", node);
+       syslog(LOG_ERR, "Invalid node name <%s>\n", ChrPtr(node));
        return(-1);
 }
 
 
-
-void cmd_gnet(char *argbuf) {
+void cmd_gnet(char *argbuf)
+{
        char filename[PATH_MAX];
        char buf[SIZ];
        FILE *fp;
 
-       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);
+       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) {
@@ -277,6 +387,14 @@ void cmd_gnet(char *argbuf) {
        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];
@@ -286,17 +404,35 @@ void cmd_snet(char *argbuf) {
        struct stat StatBuf;
        long len;
        int rc;
+       int IsMailAlias = 0;
+       int MailAliasesFound[nForceAliases];
 
        unbuffer_output();
 
-       if ( (CC->room.QRflags & QR_MAILBOX) && (CC->user.usernum == atol(CC->room.QRname)) ) {
-               /* users can edit the netconfigs for their own mailbox rooms */
+       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);
        }
-       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. */
@@ -341,6 +477,24 @@ void cmd_snet(char *argbuf) {
        {
                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);
@@ -349,6 +503,28 @@ void cmd_snet(char *argbuf) {
        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)
         */
@@ -363,62 +539,90 @@ void cmd_snet(char *argbuf) {
  */
 void cmd_netp(char *cmdbuf)
 {
-       char *working_ignetcfg;
-       char node[256];
+       struct CitContext *CCC = CC;
+       HashList *working_ignetcfg;
+       char *node;
+       StrBuf *NodeStr;
        long nodelen;
-       char pass[256];
        int v;
+       long lens[2];
+       const char *strs[2];
 
-       char secret[256];
-       char nexthop[256];
-       char err_buf[SIZ];
+       const StrBuf *secret = NULL;
+       const StrBuf *nexthop = NULL;
+       char err_buf[SIZ] = "";
 
        /* Authenticate */
-       nodelen = extract_token(node, cmdbuf, 0, '|', sizeof node);
-       extract_token(pass, cmdbuf, 1, '|', sizeof pass);
-
+       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_working_ignetcfg();
-       v = is_valid_node(nexthop, secret, node, working_ignetcfg, NULL); //// TODO do we need the netmap?
-
+       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, CC->cs_host, CC->cs_addr
+                       node, CCC->cs_host, CCC->cs_addr
                );
                syslog(LOG_WARNING, "%s", err_buf);
                cprintf("%d authentication failed\n", ERROR + PASSWORD_REQUIRED);
-               CtdlAideMessage(err_buf, "IGNet Networking.");
-               free(working_ignetcfg);
+
+               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;
        }
 
-       if (strcasecmp(pass, secret)) {
+       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",
-                       CC->cs_host, CC->cs_addr, node
+                       CCC->cs_host, CCC->cs_addr, node
                );
                syslog(LOG_WARNING, "%s", err_buf);
                cprintf("%d authentication failed\n", ERROR + PASSWORD_REQUIRED);
-               CtdlAideMessage(err_buf, "IGNet Networking.");
-               free(working_ignetcfg);
+
+               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);
-               free(working_ignetcfg);
+               DeleteHash(&working_ignetcfg);
+               FreeStrBuf(&NodeStr);
                return;
        }
-
-       safestrncpy(CC->net_node, node, sizeof CC->net_node);
-       network_talking_to(node, nodelen, NTT_ADD);
+       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",
-               CC->net_node, CC->cs_host, CC->cs_addr
+               CCC->net_node, CCC->cs_host, CCC->cs_addr
        );
-       cprintf("%d authenticated as network node '%s'\n", CIT_OK, CC->net_node);
-       free(working_ignetcfg);
+       cprintf("%d authenticated as network node '%s'\n", CIT_OK, CCC->net_node);
+       DeleteHash(&working_ignetcfg);
+       FreeStrBuf(&NodeStr);
 }
 
 int netconfig_check_roomaccess(