I should drink more while writing this
[citadel.git] / citadel / netconfig.c
index 41aeae6a6d00431df3e0d23370bf8b1f91a505d0..87f2c2d3cc4bcf4eb17ffee6501cd4ae2d260a0b 100644 (file)
@@ -2,20 +2,22 @@
  * This module handles shared rooms, inter-Citadel mail, and outbound
  * mailing list processing.
  *
- * Copyright (c) 2000-2012 by the citadel.org team
+ * Copyright (c) 2000-2016 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 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.
+ * 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 <sys/types.h>
+#include <dirent.h>
 
 #ifdef HAVE_SYSCALL_H
 # include <syscall.h>
 #include <libcitadel.h>
 
 #include "include/ctdl_module.h"
-
+#include "serv_extensions.h"
+#include "config.h"
 
 void vFreeRoomNetworkStruct(void *vOneRoomNetCfg);
+void FreeRoomNetworkStructContent(OneRoomNetCfg *OneRNCfg);
 
 HashList *CfgTypeHash = NULL;
 HashList *RoomConfigs = NULL;
@@ -132,7 +136,10 @@ void DeleteGenericCfgLine(const CfgLineType *ThisOne, RoomNetCfgLine **data)
 {
        int i;
 
-       for (i = 0; i < ThisOne->nSegments; i++)
+       if (*data == NULL)
+               return;
+
+       for (i = 0; i < (*data)->nValues; i++)
        {
                FreeStrBuf(&(*data)->Value[i]);
        }
@@ -142,16 +149,19 @@ void DeleteGenericCfgLine(const CfgLineType *ThisOne, RoomNetCfgLine **data)
 }
 RoomNetCfgLine *DuplicateOneGenericCfgLine(const RoomNetCfgLine *data)
 {
+       int i;
        RoomNetCfgLine *NewData;
 
        NewData = (RoomNetCfgLine*)malloc(sizeof(RoomNetCfgLine));
-       int i;
+       memset(NewData, 0, sizeof(RoomNetCfgLine));
        NewData->Value = (StrBuf **)malloc(sizeof(StrBuf*) * data->nValues);
+       memset(NewData->Value, 0, sizeof(StrBuf*) * data->nValues);
 
        for (i = 0; i < data->nValues; i++)
        {
                NewData->Value[i] = NewStrBufDup(data->Value[i]);
        }
+       NewData->nValues = data->nValues;
        return NewData;
 }
 int ReadRoomNetConfigFile(OneRoomNetCfg **pOneRNCfg, char *filename)
@@ -162,26 +172,32 @@ int ReadRoomNetConfigFile(OneRoomNetCfg **pOneRNCfg, char *filename)
        const CfgLineType *pCfg;
        StrBuf *Line;
        StrBuf *InStr;
-       OneRoomNetCfg *OneRNCfg;
+       OneRoomNetCfg *OneRNCfg = NULL;
 
        fd = open(filename, O_NONBLOCK|O_RDONLY);
        if (fd == -1) {
                *pOneRNCfg = NULL;
                return 0;
        }
+       fchown(fd, CTDLUID, (-1));
+       fchmod(fd, 0600);
+
        if (*pOneRNCfg != NULL)
+       {
                OneRNCfg = *pOneRNCfg;
+               FreeRoomNetworkStructContent (OneRNCfg);
+       }
        else
                OneRNCfg = malloc(sizeof(OneRoomNetCfg));
        memset(OneRNCfg, 0, sizeof(OneRoomNetCfg));
        *pOneRNCfg = OneRNCfg;
        Line = NewStrBuf();
+       InStr = NewStrBuf();
 
        while (StrBufTCP_read_line(Line, &fd, 0, &ErrStr) >= 0) {
                if (StrLength(Line) == 0)
                        continue;
                Pos = NULL;
-               InStr = NewStrBufPlain(NULL, StrLength(Line));
                StrBufExtract_NextToken(InStr, Line, &Pos, '|');
 
                pCfg = GetCfgTypeByStr(SKEY(InStr));
@@ -239,7 +255,7 @@ int SaveRoomNetConfigFile(OneRoomNetCfg *OneRNCfg, char *filename)
        TmpFD = open(tempfilename, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR);
        Cfg = NewStrBuf();
        if ((TmpFD < 0) || (errno != 0)) {
-               syslog(LOG_CRIT, "ERROR: cannot open %s: %s\n",
+               syslog(LOG_CRIT, "ERROR: cannot open %s: %s",
                        filename, strerror(errno));
                unlink(tempfilename);
                FreeStrBuf(&Cfg);
@@ -248,7 +264,7 @@ int SaveRoomNetConfigFile(OneRoomNetCfg *OneRNCfg, char *filename)
        else {
                OutBuffer = NewStrBuf();
                CfgIt = GetNewHashPos(CfgTypeHash, 1);
-               fchown(TmpFD, config.c_ctdluid, 0);
+               fchown(TmpFD, ctdluid, 0);
                for (eCfg = subpending; eCfg < maxRoomNetCfg; eCfg ++)
                {
                        const CfgLineType *pCfg;
@@ -286,9 +302,10 @@ int SaveRoomNetConfigFile(OneRoomNetCfg *OneRNCfg, char *filename)
                }
                else {
                        syslog(LOG_EMERG, 
-                                     "unable to write %s; [%s]; not enough space on the disk?\n", 
-                                     tempfilename, 
-                                     strerror(errno));
+                             "unable to write %s; [%s]; not enough space on the disk?", 
+                             tempfilename, 
+                             strerror(errno)
+                       );
                        close(TmpFD);
                        unlink(tempfilename);
                        rc = 0;
@@ -300,6 +317,7 @@ int SaveRoomNetConfigFile(OneRoomNetCfg *OneRNCfg, char *filename)
        return rc;
 }
 
+
 void SaveModifiedRooms(struct ctdlroom *qrbuf, void *data, OneRoomNetCfg *OneRNCfg)
 {
        char filename[PATH_MAX];
@@ -311,11 +329,11 @@ void SaveModifiedRooms(struct ctdlroom *qrbuf, void *data, OneRoomNetCfg *OneRNC
                OneRNCfg->changed = 0;
        }
 }
+
+
 void SaveChangedConfigs(void)
 {
-       CtdlForEachNetCfgRoom(SaveModifiedRooms,
-                             NULL, 
-                             maxRoomNetCfg);
+       CtdlForEachNetCfgRoom(SaveModifiedRooms, NULL, maxRoomNetCfg);
 }
 
 
@@ -345,6 +363,7 @@ void AddRoomCfgLine(OneRoomNetCfg *OneRNCfg, struct ctdlroom *qrbuf, RoomNetCfg
        }
 }
 
+
 void FreeRoomNetworkStructContent(OneRoomNetCfg *OneRNCfg)
 {
        RoomNetCfg eCfg;
@@ -357,11 +376,18 @@ void FreeRoomNetworkStructContent(OneRoomNetCfg *OneRNCfg)
                RoomNetCfgLine *pNext, *pName;
                
                pCfg = GetCfgTypeByEnum(eCfg, CfgIt);
-               pName= OneRNCfg->NetConfigs[pCfg->C];
+               pName= OneRNCfg->NetConfigs[eCfg];
                while (pName != NULL)
                {
                        pNext = pName->next;
-                       pCfg->DeAllocator(pCfg, &pName);
+                       if (pCfg != NULL)
+                       {
+                               pCfg->DeAllocator(pCfg, &pName);
+                       }
+                       else
+                       {
+                               DeleteGenericCfgLine(NULL, &pName);
+                       }
                        pName = pNext;
                }
        }
@@ -370,7 +396,10 @@ void FreeRoomNetworkStructContent(OneRoomNetCfg *OneRNCfg)
        FreeStrBuf(&OneRNCfg->Sender);
        FreeStrBuf(&OneRNCfg->RoomInfo);
        FreeStrBuf(&OneRNCfg->misc);
+       memset(OneRNCfg, 0, sizeof(OneRoomNetCfg));
 }
+
+
 void vFreeRoomNetworkStruct(void *vOneRoomNetCfg)
 {
        OneRoomNetCfg *OneRNCfg;
@@ -378,12 +407,15 @@ void vFreeRoomNetworkStruct(void *vOneRoomNetCfg)
        FreeRoomNetworkStructContent(OneRNCfg);
        free(OneRNCfg);
 }
+
+
 void FreeRoomNetworkStruct(OneRoomNetCfg **pOneRNCfg)
 {
        vFreeRoomNetworkStruct(*pOneRNCfg);
        *pOneRNCfg=NULL;
 }
 
+
 OneRoomNetCfg* CtdlGetNetCfgForRoom(long QRNumber)
 {
        void *pv;
@@ -421,7 +453,7 @@ void LoadAllNetConfigs(void)
               (filedir_entry != NULL))
        {
 #ifdef _DIRENT_HAVE_D_NAMLEN
-               d_namelen = filedir_entry->d_namelen;
+               d_namelen = filedir_entry->d_namlen;
 #else
                d_namelen = strlen(filedir_entry->d_name);
 #endif
@@ -487,7 +519,6 @@ void LoadAllNetConfigs(void)
 
                                if (OneRNCfg != NULL)
                                        Put(RoomConfigs, LKEY(RoomNumber), OneRNCfg, vFreeRoomNetworkStruct);
-                               /* syslog(9, "[%s | %s]\n", ChrPtr(OneWebName), ChrPtr(FileName)); */
                        }
                        break;
                default:
@@ -558,7 +589,6 @@ const ConstStr ForceAliases[nForceAliases] = {
        {HKEY("postmaster,")},
        {HKEY("abuse,")}
 };
-
 void cmd_snet(char *argbuf)
 {
        struct CitContext *CCC = CC;
@@ -701,7 +731,6 @@ void cmd_snet(char *argbuf)
                RNCfg = CtdlGetNetCfgForRoom(CCC->room.QRnumber);
                if (RNCfg != NULL)
                {
-                       FreeRoomNetworkStructContent(RNCfg);
                        ReadRoomNetConfigFile(&RNCfg, filename);
                }
                else
@@ -709,6 +738,8 @@ void cmd_snet(char *argbuf)
                        ReadRoomNetConfigFile(&RNCfg, filename);
                        Put(RoomConfigs, LKEY(CCC->room.QRnumber), RNCfg, vFreeRoomNetworkStruct);
                }
+
+               PerformRoomHooks(&CCC->room);
        }
        end_critical_section(S_NETCONFIGS);
 }
@@ -821,6 +852,7 @@ int is_recipient(OneRoomNetCfg *RNCfg, const char *Name)
                        }
                        nptr = nptr->next;
                }
+               i++;
        }
        return 0;
 }
@@ -833,7 +865,6 @@ int CtdlNetconfigCheckRoomaccess(
        const char* RemoteIdentifier)
 {
        OneRoomNetCfg *RNCfg;
-       char filename[SIZ];
        int found;
 
        if (RemoteIdentifier == NULL)
@@ -842,18 +873,18 @@ int CtdlNetconfigCheckRoomaccess(
                return (ERROR + USERNAME_REQUIRED);
        }
 
-       assoc_file_name(filename, sizeof filename, &CC->room, ctdl_netcfg_dir);
        begin_critical_section(S_NETCONFIGS);
-       if (!ReadRoomNetConfigFile(&RNCfg, filename))
+       RNCfg = CtdlGetNetCfgForRoom (CC->room.QRnumber);
+       if (RNCfg == NULL)
        {
                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);
-       vFreeRoomNetworkStruct(&RNCfg);
+       end_critical_section(S_NETCONFIGS);
+
        if (found) {
                return (0);
        }
@@ -904,12 +935,14 @@ void cmd_netp(char *cmdbuf)
                lens[0] = strlen(CCC->cs_addr);
                
                strs[1] = "SRV_UNKNOWN";
-               lens[1] = sizeof("SRV_UNKNOWN" - 1);
+               lens[1] = sizeof("SRV_UNKNOWN") - 1;
 
                CtdlAideFPMessage(
                        err_buf,
                        "IGNet Networking.",
-                       2, strs, (long*) &lens);
+                       2, strs, (long*) &lens,
+                       CCC->cs_pid, 0,
+                       time(NULL));
 
                DeleteHash(&working_ignetcfg);
                FreeStrBuf(&NodeStr);
@@ -929,12 +962,15 @@ void cmd_netp(char *cmdbuf)
                lens[0] = strlen(CCC->cs_addr);
                
                strs[1] = "SRV_PW";
-               lens[1] = sizeof("SRV_PW" - 1);
+               lens[1] = sizeof("SRV_PW") - 1;
 
                CtdlAideFPMessage(
                        err_buf,
                        "IGNet Networking.",
-                       2, strs, (long*) &lens);
+                       2, strs,
+                       (long*) &lens,
+                       CCC->cs_pid, 0,
+                       time(NULL));
 
                DeleteHash(&working_ignetcfg);
                FreeStrBuf(&NodeStr);
@@ -950,7 +986,7 @@ void cmd_netp(char *cmdbuf)
        }
        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",
+       syslog(LOG_NOTICE, "Network node <%s> logged in from %s [%s]",
                CCC->net_node, CCC->cs_host, CCC->cs_addr
        );
        cprintf("%d authenticated as network node '%s'\n", CIT_OK, CCC->net_node);
@@ -1109,7 +1145,7 @@ int CtdlIsValidNode(const StrBuf **nexthop,
         * First try the neighbor nodes
         */
        if (GetCount(IgnetCfg) == 0) {
-               syslog(LOG_INFO, "IgnetCfg is empty!\n");
+               syslog(LOG_INFO, "IgnetCfg is empty!");
                if (nexthop != NULL) {
                        *nexthop = NULL;
                }
@@ -1141,7 +1177,7 @@ int CtdlIsValidNode(const StrBuf **nexthop,
        /*
         * If we get to this point, the supplied node name is bogus.
         */
-       syslog(LOG_ERR, "Invalid node name <%s>\n", ChrPtr(node));
+       syslog(LOG_ERR, "Invalid node name <%s>", ChrPtr(node));
        return(-1);
 }
 
@@ -1149,15 +1185,91 @@ int CtdlIsValidNode(const StrBuf **nexthop,
 void destroy_network_cfgs(void)
 {
        HashList *pCfgTypeHash = CfgTypeHash;
-       HashList *pRoomConfigs = RoomConfigs;
+       HashList *pRoomConfigs;
 
-       CfgTypeHash = NULL;
+       begin_critical_section(S_NETCONFIGS);
+       pRoomConfigs = RoomConfigs;
        RoomConfigs = NULL;
-       
-       DeleteHash(&pCfgTypeHash);
+       end_critical_section(S_NETCONFIGS);
        DeleteHash(&pRoomConfigs);
+
+       CfgTypeHash = NULL;
+       DeleteHash(&pCfgTypeHash);
+}
+
+
+
+
+/*
+ * Create a config key for a room's netconfig entry
+ */
+void netcfg_keyname(char *keybuf, long roomnum)
+{
+       if (!keybuf) return;
+       sprintf(keybuf, "c_netconfig_%010ld", roomnum);
+}
+
+
+
+
+/*
+ * Convert any legacy configuration files in the "netconfigs" directory
+ */
+void convert_legacy_netcfg_files(void)
+{
+       DIR *dh = NULL;
+       struct dirent *dit = NULL;
+       char keyname[25];
+       char filename[PATH_MAX];
+       long roomnum;
+       FILE *fp;
+       long len;
+       char *v;
+
+       dh = opendir(ctdl_netcfg_dir);
+       if (!dh) return;
+
+       syslog(LOG_INFO, "Legacy netconfig files exist - converting them!");
+
+       while (dit = readdir(dh), dit != NULL) {                // yes, we use the non-reentrant version; we're not in threaded mode yet
+               roomnum = atol(dit->d_name);
+               if (roomnum > 0) {
+                       netcfg_keyname(keyname, roomnum);
+                       snprintf(filename, sizeof filename, "%s/%ld", ctdl_netcfg_dir, roomnum);
+                       fp = fopen(filename, "r");
+                       if (fp) {
+                               fseek(fp, 0L, SEEK_END);
+                               len = ftell(fp);
+                               v = malloc(len);
+                               if (v) {
+                                       rewind(fp);
+                                       if (fread(v, len, 1, fp)) {
+                                               char *enc = malloc(len * 2);
+                                               int enc_len;
+                                               if (enc) {
+                                                       enc_len = CtdlEncodeBase64(enc, v, len, 0);
+                                                       if ((enc_len > 1) && (enc[enc_len-2] == 13)) enc[enc_len-2] = 0;
+                                                       if ((enc_len > 0) && (enc[enc_len-1] == 10)) enc[enc_len-1] = 0;
+                                                       enc[enc_len] = 0;
+                                                       syslog(LOG_DEBUG, "Writing key '%s' (length=%d)", keyname, enc_len);
+                                                       CtdlSetConfigStr(keyname, enc);
+                                                       free(enc);
+                                                       // unlink(filename);            // FIXME uncomment this when ready
+                                                       fclose(fp);
+                                               }
+                                       }
+                               free(v);
+                               }
+                       }
+               }
+       }
+
+       closedir(dh);
+       // rmdir(ctdl_netcfg_dir);              // FIXME uncomment this when ready
 }
 
+
+
 /*
  * Module entry point
  */
@@ -1166,7 +1278,8 @@ CTDL_MODULE_INIT(netconfig)
        if (!threading)
        {
                CtdlRegisterCleanupHook(destroy_network_cfgs);
-               LoadAllNetConfigs ();
+               convert_legacy_netcfg_files();
+               LoadAllNetConfigs();
                CtdlRegisterProtoHook(cmd_gnet, "GNET", "Get network config");
                CtdlRegisterProtoHook(cmd_snet, "SNET", "Set network config");
                CtdlRegisterProtoHook(cmd_netp, "NETP", "Identify as network poller");