X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fnetconfig.c;h=682d4e05acb301b59eb54a3293862e508743cb38;hb=66f09fdd7c3f58e13ed01431dd5148302327ca6e;hp=6137bd3d48d99202e0d3ca0f779ea2f80d7e21e3;hpb=91a7cb6daf6be6f3c0e4de318d13299ae8e11953;p=citadel.git diff --git a/citadel/netconfig.c b/citadel/netconfig.c index 6137bd3d4..682d4e05a 100644 --- a/citadel/netconfig.c +++ b/citadel/netconfig.c @@ -24,27 +24,34 @@ # include # endif #endif +#include #include #include "include/ctdl_module.h" -HashList *CfgTypeHash = NULL; +#include "serv_extensions.h" + +void vFreeRoomNetworkStruct(void *vOneRoomNetCfg); +void FreeRoomNetworkStructContent(OneRoomNetCfg *OneRNCfg); +HashList *CfgTypeHash = NULL; +HashList *RoomConfigs = NULL; /*-----------------------------------------------------------------------------* * Per room network configs * *-----------------------------------------------------------------------------*/ -void RegisterRoomCfgType(const char* Name, long len, RoomNetCfg eCfg, CfgLineParser p, int uniq, CfgLineSerializer s, CfgLineDeAllocator d) +void RegisterRoomCfgType(const char* Name, long len, RoomNetCfg eCfg, CfgLineParser p, int uniq, int nSegments, CfgLineSerializer s, CfgLineDeAllocator d) { CfgLineType *pCfg; pCfg = (CfgLineType*) malloc(sizeof(CfgLineType)); pCfg->Parser = p; pCfg->Serializer = s; + pCfg->DeAllocator = d; pCfg->C = eCfg; pCfg->Str.Key = Name; pCfg->Str.len = len; pCfg->IsSingleLine = uniq; - + pCfg->nSegments = nSegments; if (CfgTypeHash == NULL) CfgTypeHash = NewHash(1, NULL); Put(CfgTypeHash, Name, len, pCfg, NULL); @@ -81,31 +88,80 @@ const CfgLineType *GetCfgTypeByEnum(RoomNetCfg eCfg, HashPos *It) } return NULL; } -void ParseGeneric(const CfgLineType *ThisOne, StrBuf *Line, const char *LinePos, OneRoomNetCfg *OneRNCFG) +void ParseGeneric(const CfgLineType *ThisOne, StrBuf *Line, const char *LinePos, OneRoomNetCfg *OneRNCfg) { RoomNetCfgLine *nptr; + int i; nptr = (RoomNetCfgLine *) malloc(sizeof(RoomNetCfgLine)); - nptr->next = OneRNCFG->NetConfigs[ThisOne->C]; - nptr->Value = NewStrBufPlain(LinePos, StrLength(Line) - ( LinePos - ChrPtr(Line)) ); - OneRNCFG->NetConfigs[ThisOne->C] = nptr; + nptr->next = OneRNCfg->NetConfigs[ThisOne->C]; + nptr->Value = malloc(sizeof(StrBuf*) * ThisOne->nSegments); + nptr->nValues = 0; + memset(nptr->Value, 0, sizeof(StrBuf*) * ThisOne->nSegments); + if (ThisOne->nSegments == 1) + { + nptr->Value[0] = NewStrBufPlain(LinePos, StrLength(Line) - ( LinePos - ChrPtr(Line)) ); + nptr->nValues = 1; + } + else for (i = 0; i < ThisOne->nSegments; i++) + { + nptr->nValues++; + nptr->Value[i] = NewStrBufPlain(NULL, StrLength(Line) - ( LinePos - ChrPtr(Line)) ); + StrBufExtract_NextToken(nptr->Value[i], Line, &LinePos, '|'); + } + + OneRNCfg->NetConfigs[ThisOne->C] = nptr; } -void SerializeGeneric(const CfgLineType *ThisOne, StrBuf *OutputBuffer, OneRoomNetCfg *OneRNCFG, RoomNetCfgLine *data) +void SerializeGeneric(const CfgLineType *ThisOne, StrBuf *OutputBuffer, OneRoomNetCfg *OneRNCfg, RoomNetCfgLine *data) { + int i; + StrBufAppendBufPlain(OutputBuffer, CKEY(ThisOne->Str), 0); - StrBufAppendBuf(OutputBuffer, data->Value, 0); + StrBufAppendBufPlain(OutputBuffer, HKEY("|"), 0); + for (i = 0; i < ThisOne->nSegments; i++) + { + StrBufAppendBuf(OutputBuffer, data->Value[i], 0); + if (i + 1 < ThisOne->nSegments) + StrBufAppendBufPlain(OutputBuffer, HKEY("|"), 0); + } StrBufAppendBufPlain(OutputBuffer, HKEY("\n"), 0); } void DeleteGenericCfgLine(const CfgLineType *ThisOne, RoomNetCfgLine **data) { - FreeStrBuf(&(*data)->Value); + int i; + + if (*data == NULL) + return; + + for (i = 0; i < (*data)->nValues; i++) + { + FreeStrBuf(&(*data)->Value[i]); + } + free ((*data)->Value); free(*data); *data = NULL; } -int read_spoolcontrol_file(OneRoomNetCfg **pOneRNCFG, char *filename) +RoomNetCfgLine *DuplicateOneGenericCfgLine(const RoomNetCfgLine *data) +{ + int i; + RoomNetCfgLine *NewData; + + NewData = (RoomNetCfgLine*)malloc(sizeof(RoomNetCfgLine)); + 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) { int fd; const char *ErrStr = NULL; @@ -113,40 +169,47 @@ int read_spoolcontrol_file(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; + *pOneRNCfg = NULL; return 0; } - OneRNCFG = malloc(sizeof(OneRoomNetCfg)); - memset(OneRNCFG, 0, sizeof(OneRoomNetCfg)); - *pOneRNCFG = OneRNCFG; + 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)); if (pCfg != NULL) { - pCfg->Parser(pCfg, Line, Pos, OneRNCFG); + pCfg->Parser(pCfg, Line, Pos, OneRNCfg); } else { - if (OneRNCFG->misc == NULL) + if (OneRNCfg->misc == NULL) { - OneRNCFG->misc = NewStrBufDup(Line); + OneRNCfg->misc = NewStrBufDup(Line); } else { - if(StrLength(OneRNCFG->misc) > 0) - StrBufAppendBufPlain(OneRNCFG->misc, HKEY("\n"), 0); - StrBufAppendBuf(OneRNCFG->misc, Line, 0); + if(StrLength(OneRNCfg->misc) > 0) + StrBufAppendBufPlain(OneRNCfg->misc, HKEY("\n"), 0); + StrBufAppendBuf(OneRNCfg->misc, Line, 0); } } } @@ -157,25 +220,25 @@ int read_spoolcontrol_file(OneRoomNetCfg **pOneRNCFG, char *filename) return 1; } -int save_spoolcontrol_file(OneRoomNetCfg *OneRNCFG, char *filename) +int SaveRoomNetConfigFile(OneRoomNetCfg *OneRNCfg, char *filename) { RoomNetCfg eCfg; - StrBuf *Cfg; + StrBuf *Cfg = NULL; + StrBuf *OutBuffer = NULL; char tempfilename[PATH_MAX]; int TmpFD; long len; time_t unixtime; struct timeval tv; long reltid; /* if we don't have SYS_gettid, use "random" value */ - StrBuf *OutBuffer; int rc; HashPos *CfgIt; len = strlen(filename); memcpy(tempfilename, filename, len + 1); -#if defined(HAVE_SYONERNCFGALL_H) && defined (SYS_gettid) - reltid = syOneRNCFGall(SYS_gettid); +#if defined(HAVE_SYSCALL_H) && defined (SYS_gettid) + reltid = syscall(SYS_gettid); #endif gettimeofday(&tv, NULL); /* Promote to time_t; types differ on some OSes (like darwin) */ @@ -189,9 +252,11 @@ int save_spoolcontrol_file(OneRoomNetCfg *OneRNCFG, char *filename) syslog(LOG_CRIT, "ERROR: cannot open %s: %s\n", filename, strerror(errno)); unlink(tempfilename); + FreeStrBuf(&Cfg); return 0; } else { + OutBuffer = NewStrBuf(); CfgIt = GetNewHashPos(CfgTypeHash, 1); fchown(TmpFD, config.c_ctdluid, 0); for (eCfg = subpending; eCfg < maxRoomNetCfg; eCfg ++) @@ -200,14 +265,14 @@ int save_spoolcontrol_file(OneRoomNetCfg *OneRNCFG, char *filename) pCfg = GetCfgTypeByEnum(eCfg, CfgIt); if (pCfg->IsSingleLine) { - pCfg->Serializer(pCfg, OutBuffer, OneRNCFG, NULL); + pCfg->Serializer(pCfg, OutBuffer, OneRNCfg, NULL); } else { - RoomNetCfgLine *pName = OneRNCFG->NetConfigs[pCfg->C]; + RoomNetCfgLine *pName = OneRNCfg->NetConfigs[pCfg->C]; while (pName != NULL) { - pCfg->Serializer(pCfg, OutBuffer, OneRNCFG, pName); + pCfg->Serializer(pCfg, OutBuffer, OneRNCfg, pName); pName = pName->next; } @@ -218,12 +283,12 @@ int save_spoolcontrol_file(OneRoomNetCfg *OneRNCFG, char *filename) DeleteHashPos(&CfgIt); - if (OneRNCFG->misc != NULL) { - StrBufAppendBuf(OutBuffer, OneRNCFG->misc, 0); + if (OneRNCfg->misc != NULL) { + StrBufAppendBuf(OutBuffer, OneRNCfg->misc, 0); } rc = write(TmpFD, ChrPtr(OutBuffer), StrLength(OutBuffer)); - if ((rc >=0 ) && (rc == StrLength(Cfg))) + if ((rc >=0 ) && (rc == StrLength(OutBuffer))) { close(TmpFD); rename(tempfilename, filename); @@ -241,18 +306,60 @@ int save_spoolcontrol_file(OneRoomNetCfg *OneRNCFG, char *filename) FreeStrBuf(&OutBuffer); } + FreeStrBuf(&Cfg); return rc; } +void SaveModifiedRooms(struct ctdlroom *qrbuf, void *data, OneRoomNetCfg *OneRNCfg) +{ + char filename[PATH_MAX]; + + if (OneRNCfg->changed) + { + assoc_file_name(filename, sizeof filename, qrbuf, ctdl_netcfg_dir); + SaveRoomNetConfigFile(OneRNCfg, filename); + OneRNCfg->changed = 0; + } +} +void SaveChangedConfigs(void) +{ + CtdlForEachNetCfgRoom(SaveModifiedRooms, + NULL, + maxRoomNetCfg); +} -void free_spoolcontrol_struct(OneRoomNetCfg **pOneRNCFG) +void AddRoomCfgLine(OneRoomNetCfg *OneRNCfg, struct ctdlroom *qrbuf, RoomNetCfg LineType, RoomNetCfgLine *Line) +{ + int new = 0; + RoomNetCfgLine **pLine; + char filename[PATH_MAX]; + + if (OneRNCfg == NULL) + { + new = 1; + OneRNCfg = (OneRoomNetCfg*) malloc(sizeof(OneRoomNetCfg)); + memset(OneRNCfg, 0, sizeof(OneRoomNetCfg)); + } + pLine = &OneRNCfg->NetConfigs[LineType]; + + while(*pLine != NULL) pLine = &((*pLine)->next); + *pLine = Line; + + assoc_file_name(filename, sizeof filename, qrbuf, ctdl_netcfg_dir); + SaveRoomNetConfigFile(OneRNCfg, filename); + OneRNCfg->changed = 0; + if (new) + { + Put(RoomConfigs, LKEY(qrbuf->QRnumber), OneRNCfg, vFreeRoomNetworkStruct); + } +} + +void FreeRoomNetworkStructContent(OneRoomNetCfg *OneRNCfg) { RoomNetCfg eCfg; HashPos *CfgIt; - OneRoomNetCfg *OneRNCFG; - OneRNCFG = *pOneRNCFG; CfgIt = GetNewHashPos(CfgTypeHash, 1); for (eCfg = subpending; eCfg < maxRoomNetCfg; eCfg ++) { @@ -260,21 +367,155 @@ void free_spoolcontrol_struct(OneRoomNetCfg **pOneRNCFG) 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; } } DeleteHashPos(&CfgIt); - FreeStrBuf(&OneRNCFG->Sender); - FreeStrBuf(&OneRNCFG->RoomInfo); - FreeStrBuf(&OneRNCFG->misc); - free(OneRNCFG); - *pOneRNCFG=NULL; + FreeStrBuf(&OneRNCfg->Sender); + FreeStrBuf(&OneRNCfg->RoomInfo); + FreeStrBuf(&OneRNCfg->misc); + memset(OneRNCfg, 0, sizeof(OneRoomNetCfg)); +} +void vFreeRoomNetworkStruct(void *vOneRoomNetCfg) +{ + OneRoomNetCfg *OneRNCfg; + OneRNCfg = (OneRoomNetCfg*)vOneRoomNetCfg; + FreeRoomNetworkStructContent(OneRNCfg); + free(OneRNCfg); +} +void FreeRoomNetworkStruct(OneRoomNetCfg **pOneRNCfg) +{ + vFreeRoomNetworkStruct(*pOneRNCfg); + *pOneRNCfg=NULL; +} + +OneRoomNetCfg* CtdlGetNetCfgForRoom(long QRNumber) +{ + void *pv; + GetHash(RoomConfigs, LKEY(QRNumber), &pv); + return (OneRoomNetCfg*)pv; +} + + +void LoadAllNetConfigs(void) +{ + DIR *filedir = NULL; + struct dirent *d; + struct dirent *filedir_entry; + int d_type = 0; + int d_namelen; + long RoomNumber; + OneRoomNetCfg *OneRNCfg; + int IsNumOnly; + const char *pch; + char path[PATH_MAX]; + + RoomConfigs = NewHash(1, NULL); + filedir = opendir (ctdl_netcfg_dir); + if (filedir == NULL) { + return ; /// todo: panic! + } + + d = (struct dirent *)malloc(offsetof(struct dirent, d_name) + PATH_MAX + 1); + if (d == NULL) { + closedir(filedir); + return ; + } + + while ((readdir_r(filedir, d, &filedir_entry) == 0) && + (filedir_entry != NULL)) + { +#ifdef _DIRENT_HAVE_D_NAMLEN + d_namelen = filedir_entry->d_namelen; +#else + d_namelen = strlen(filedir_entry->d_name); +#endif + +#ifdef _DIRENT_HAVE_D_TYPE + d_type = filedir_entry->d_type; +#else + +#ifndef DT_UNKNOWN +#define DT_UNKNOWN 0 +#define DT_DIR 4 +#define DT_REG 8 +#define DT_LNK 10 + +#define IFTODT(mode) (((mode) & 0170000) >> 12) +#define DTTOIF(dirtype) ((dirtype) << 12) +#endif + d_type = DT_UNKNOWN; +#endif + if ((d_namelen > 1) && filedir_entry->d_name[d_namelen - 1] == '~') + continue; /* Ignore backup files... */ + + if ((d_namelen == 1) && + (filedir_entry->d_name[0] == '.')) + continue; + + if ((d_namelen == 2) && + (filedir_entry->d_name[0] == '.') && + (filedir_entry->d_name[1] == '.')) + continue; + + snprintf(path, PATH_MAX, "%s/%s", + ctdl_netcfg_dir, filedir_entry->d_name); + + if (d_type == DT_UNKNOWN) { + struct stat s; + if (lstat(path, &s) == 0) { + d_type = IFTODT(s.st_mode); + } + } + + switch (d_type) + { + case DT_DIR: + break; + case DT_LNK: /* TODO: check whether its a file or a directory */ + case DT_REG: + IsNumOnly = 1; + pch = filedir_entry->d_name; + while (*pch != '\0') + { + if (!isdigit(*pch)) + { + IsNumOnly = 0; + } + pch ++; + } + if (IsNumOnly) + { + OneRNCfg = NULL; + RoomNumber = atol(filedir_entry->d_name); + ReadRoomNetConfigFile(&OneRNCfg, path); + + if (OneRNCfg != NULL) + Put(RoomConfigs, LKEY(RoomNumber), OneRNCfg, vFreeRoomNetworkStruct); + /* syslog(9, "[%s | %s]\n", ChrPtr(OneWebName), ChrPtr(FileName)); */ + } + break; + default: + break; + } + + + } + free(d); + closedir(filedir); } @@ -335,8 +576,9 @@ const ConstStr ForceAliases[nForceAliases] = { {HKEY("postmaster,")}, {HKEY("abuse,")} }; - -void cmd_snet(char *argbuf) { +void cmd_snet(char *argbuf) +{ + struct CitContext *CCC = CC; char tempfilename[PATH_MAX]; char filename[PATH_MAX]; int TmpFD; @@ -365,19 +607,19 @@ void cmd_snet(char *argbuf) { } else { - if ( (CC->room.QRflags & QR_MAILBOX) && (CC->user.usernum == atol(CC->room.QRname)) ) { + if ( (CCC->room.QRflags & QR_MAILBOX) && (CCC->user.usernum == atol(CCC->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); + len = assoc_file_name(filename, sizeof filename, &CCC->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); + sprintf(tempfilename + len, ".%d", CCC->cs_pid); errno = 0; TmpFD = open(tempfilename, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR); @@ -470,6 +712,22 @@ void cmd_snet(char *argbuf) { */ begin_critical_section(S_NETCONFIGS); rename(tempfilename, filename); + if (!IsMailAlias) + { + OneRoomNetCfg *RNCfg; + RNCfg = CtdlGetNetCfgForRoom(CCC->room.QRnumber); + if (RNCfg != NULL) + { + ReadRoomNetConfigFile(&RNCfg, filename); + } + else + { + ReadRoomNetConfigFile(&RNCfg, filename); + Put(RoomConfigs, LKEY(CCC->room.QRnumber), RNCfg, vFreeRoomNetworkStruct); + } + + PerformRoomHooks(&CCC->room); + } end_critical_section(S_NETCONFIGS); } @@ -574,8 +832,8 @@ int is_recipient(OneRoomNetCfg *RNCfg, const char *Name) while (nptr != NULL) { - if ((StrLength(nptr->Value) == len) && - (!strcmp(Name, ChrPtr(nptr->Value)))) + if ((StrLength(nptr->Value[0]) == len) && + (!strcmp(Name, ChrPtr(nptr->Value[0])))) { return 1; } @@ -593,7 +851,6 @@ int CtdlNetconfigCheckRoomaccess( const char* RemoteIdentifier) { OneRoomNetCfg *RNCfg; - char filename[SIZ]; int found; if (RemoteIdentifier == NULL) @@ -602,18 +859,18 @@ int CtdlNetconfigCheckRoomaccess( 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)) + 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); - free_spoolcontrol_struct(&RNCfg); + end_critical_section(S_NETCONFIGS); + if (found) { return (0); } @@ -669,7 +926,8 @@ void cmd_netp(char *cmdbuf) CtdlAideFPMessage( err_buf, "IGNet Networking.", - 2, strs, (long*) &lens); + 2, strs, (long*) &lens, + time(NULL)); DeleteHash(&working_ignetcfg); FreeStrBuf(&NodeStr); @@ -694,7 +952,9 @@ void cmd_netp(char *cmdbuf) CtdlAideFPMessage( err_buf, "IGNet Networking.", - 2, strs, (long*) &lens); + 2, strs, + (long*) &lens, + time(NULL)); DeleteHash(&working_ignetcfg); FreeStrBuf(&NodeStr); @@ -761,14 +1021,14 @@ HashList* CtdlReadNetworkMap(void) HashList *Hash; CtdlNetMap *TheNetMap; + Hash = NewHash(1, NULL); Cfg = CtdlGetSysConfig(IGNETMAP); if ((Cfg == NULL) || IsEmptyStr(Cfg)) { if (Cfg != NULL) free(Cfg); - return NULL; + return Hash; } - Hash = NewHash(1, NULL); Buf = NewStrBufPlain(Cfg, -1); free(Cfg); LineBuf = NewStrBufPlain(NULL, StrLength(Buf)); @@ -906,6 +1166,18 @@ int CtdlIsValidNode(const StrBuf **nexthop, } +void destroy_network_cfgs(void) +{ + HashList *pCfgTypeHash = CfgTypeHash; + HashList *pRoomConfigs = RoomConfigs; + + CfgTypeHash = NULL; + RoomConfigs = NULL; + + DeleteHash(&pCfgTypeHash); + DeleteHash(&pRoomConfigs); +} + /* * Module entry point */ @@ -913,7 +1185,8 @@ CTDL_MODULE_INIT(netconfig) { if (!threading) { - + CtdlRegisterCleanupHook(destroy_network_cfgs); + LoadAllNetConfigs (); CtdlRegisterProtoHook(cmd_gnet, "GNET", "Get network config"); CtdlRegisterProtoHook(cmd_snet, "SNET", "Set network config"); CtdlRegisterProtoHook(cmd_netp, "NETP", "Identify as network poller");