X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fnetconfig.c;h=73ab22f4f67f32ad3ff9b3a27cef433feaee0cb5;hb=51b18018ff923284d76a36cbd421d62abf6afcf4;hp=3c20541c0f7fd51714b0a750e96ae78506ddd030;hpb=e24d4d39b9e026d260c7745014bafe63e19f9b0b;p=citadel.git diff --git a/citadel/netconfig.c b/citadel/netconfig.c index 3c20541c0..73ab22f4f 100644 --- a/citadel/netconfig.c +++ b/citadel/netconfig.c @@ -1,21 +1,22 @@ /* - * This module handles shared rooms, inter-Citadel mail, and outbound - * mailing list processing. + * This module handles loading, saving, and parsing of room network configurations. * - * Copyright (c) 2000-2012 by the citadel.org team + * Copyright (c) 2000-2021 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 +#include +#include #ifdef HAVE_SYSCALL_H # include @@ -24,255 +25,181 @@ # include # endif #endif +#include +#include #include -#include "include/ctdl_module.h" -HashList *CfgTypeHash = NULL; +#include "ctdl_module.h" +#include "serv_extensions.h" +#include "config.h" - -void RegisterRoomCfgType(const char* Name, long len, RoomNetCfg eCfg, CfgLineParser p, int uniq, CfgLineSerializer s, CfgLineDeAllocator d) -{ - CfgLineType *pCfg; - - pCfg = (CfgLineType*) malloc(sizeof(CfgLineType)); - pCfg->Parser = p; - pCfg->Serializer = s; - pCfg->C = eCfg; - pCfg->Str.Key = Name; - pCfg->Str.len = len; - pCfg->IsSingleLine = uniq; - - if (CfgTypeHash == NULL) - CfgTypeHash = NewHash(1, NULL); - Put(CfgTypeHash, Name, len, pCfg, NULL); +/* + * 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); } -const CfgLineType *GetCfgTypeByStr(const char *Key, long len) -{ - void *pv; - - if (GetHash(CfgTypeHash, Key, len, &pv) && (pv != NULL)) - { - return (const CfgLineType *) pv; - } - else - { - return NULL; +/* + * Given a room number and a textual netconfig, convert to base64 and write to the configdb + */ +void SaveRoomNetConfigFile(long roomnum, const char *raw_netconfig) { + char keyname[25]; + char *enc; + int enc_len; + int len; + + len = strlen(raw_netconfig); + netcfg_keyname(keyname, roomnum); + enc = malloc(len * 2); + + if (enc) { + enc_len = CtdlEncodeBase64(enc, raw_netconfig, 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, "netconfig: writing key '%s' (length=%d)", keyname, enc_len); + CtdlSetConfigStr(keyname, enc); + free(enc); } } -const CfgLineType *GetCfgTypeByEnum(RoomNetCfg eCfg, HashPos *It) -{ - const char *Key; - long len; - void *pv; - CfgLineType *pCfg; - RewindHashPos(CfgTypeHash, It, 1); - while (GetNextHashPos(CfgTypeHash, It, &len, &Key, &pv) && (pv != NULL)) - { - pCfg = (CfgLineType*) pv; - if (pCfg->C == eCfg) - return pCfg; - } - return NULL; +/* + * Given a room number, attempt to load the netconfig configdb entry for that room. + * If it returns NULL, there is no netconfig. + * Otherwise the caller owns the returned memory and is responsible for freeing it. + */ +char *LoadRoomNetConfigFile(long roomnum) { + char keyname[25]; + char *encoded_netconfig = NULL; + char *decoded_netconfig = NULL; + + netcfg_keyname(keyname, roomnum); + encoded_netconfig = CtdlGetConfigStr(keyname); + if (!encoded_netconfig) return NULL; + + decoded_netconfig = malloc(strlen(encoded_netconfig)); // yeah, way bigger than it needs to be, but safe + CtdlDecodeBase64(decoded_netconfig, encoded_netconfig, strlen(encoded_netconfig)); + return decoded_netconfig; } -void ParseGeneric(const CfgLineType *ThisOne, StrBuf *Line, const char *LinePos, OneRoomNetCfg *OneRNCFG) -{ - RoomNetCfgLine *nptr; - 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; -} -void SerializeGeneric(const CfgLineType *ThisOne, StrBuf *OutputBuffer, OneRoomNetCfg *OneRNCFG, RoomNetCfgLine *data) -{ - StrBufAppendBufPlain(OutputBuffer, CKEY(ThisOne->Str), 0); - StrBufAppendBuf(OutputBuffer, data->Value, 0); - StrBufAppendBufPlain(OutputBuffer, HKEY("\n"), 0); -} +/*-----------------------------------------------------------------------------* + * Per room network configs : exchange with client * + *-----------------------------------------------------------------------------*/ -void DeleteGenericCfgLine(const CfgLineType *ThisOne, RoomNetCfgLine **data) -{ - FreeStrBuf(&(*data)->Value); - free(*data); - *data = NULL; -} -int read_spoolcontrol_file(OneRoomNetCfg **pOneRNCFG, char *filename) -{ - int fd; - const char *ErrStr = NULL; - const char *Pos; - const CfgLineType *pCfg; - StrBuf *Line; - StrBuf *InStr; - OneRoomNetCfg *OneRNCFG; - - fd = open(filename, O_NONBLOCK|O_RDONLY); - if (fd == -1) { - *pOneRNCFG = NULL; - return 0; +void cmd_gnet(char *argbuf) { + if ( (CC->room.QRflags & QR_MAILBOX) && (CC->user.usernum == atol(CC->room.QRname)) ) { + /* users can edit the netconfigs for their own mailbox rooms */ } - OneRNCFG = malloc(sizeof(OneRoomNetCfg)); - memset(OneRNCFG, 0, sizeof(OneRoomNetCfg)); - *pOneRNCFG = OneRNCFG; - - 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); - } - else - { - if (OneRNCFG->misc == NULL) - { - OneRNCFG->misc = NewStrBufDup(Line); - } - else - { - if(StrLength(OneRNCFG->misc) > 0) - StrBufAppendBufPlain(OneRNCFG->misc, HKEY("\n"), 0); - StrBufAppendBuf(OneRNCFG->misc, Line, 0); - } + else if (CtdlAccessCheck(ac_room_aide)) return; + + cprintf("%d Network settings for room #%ld <%s>\n", LISTING_FOLLOWS, CC->room.QRnumber, CC->room.QRname); + + char *c = LoadRoomNetConfigFile(CC->room.QRnumber); + if (c) { + int len = strlen(c); + client_write(c, len); // Can't use cprintf() here, it has a limit of 1024 bytes + if (c[len] != '\n') { + client_write(HKEY("\n")); } + free(c); } - if (fd > 0) - close(fd); - FreeStrBuf(&InStr); - FreeStrBuf(&Line); - return 1; + cprintf("000\n"); } -int save_spoolcontrol_file(OneRoomNetCfg *OneRNCFG, char *filename) -{ - RoomNetCfg eCfg; - StrBuf *Cfg; - 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; + +void cmd_snet(char *argbuf) { + StrBuf *Line = NULL; + StrBuf *TheConfig = NULL; int rc; - HashPos *CfgIt; - len = strlen(filename); - memcpy(tempfilename, filename, len + 1); + unbuffer_output(); + Line = NewStrBuf(); + TheConfig = NewStrBuf(); + cprintf("%d send new netconfig now\n", SEND_LISTING); -#if defined(HAVE_SYONERNCFGALL_H) && defined (SYS_gettid) - reltid = syOneRNCFGall(SYS_gettid); -#endif - gettimeofday(&tv, NULL); - /* Promote to time_t; types differ on some OSes (like darwin) */ - unixtime = tv.tv_sec; - - sprintf(tempfilename + len, ".%ld-%ld", reltid, unixtime); - errno = 0; - 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", - filename, strerror(errno)); - unlink(tempfilename); - return 0; - } - else { - CfgIt = GetNewHashPos(CfgTypeHash, 1); - fchown(TmpFD, config.c_ctdluid, 0); - for (eCfg = subpending; eCfg < maxRoomNetCfg; eCfg ++) - { - const CfgLineType *pCfg; - pCfg = GetCfgTypeByEnum(eCfg, CfgIt); - if (pCfg->IsSingleLine) - { - pCfg->Serializer(pCfg, OutBuffer, OneRNCFG, NULL); - } - else - { - RoomNetCfgLine *pName = OneRNCFG->NetConfigs[pCfg->C]; - while (pName != NULL) - { - pCfg->Serializer(pCfg, OutBuffer, OneRNCFG, pName); - pName = pName->next; - } - - - } + while (rc = CtdlClientGetLine(Line), (rc >= 0)) { + if ((rc == 3) && (strcmp(ChrPtr(Line), "000") == 0)) + break; - } - DeleteHashPos(&CfgIt); + StrBufAppendBuf(TheConfig, Line, 0); + StrBufAppendBufPlain(TheConfig, HKEY("\n"), 0); + } + FreeStrBuf(&Line); + begin_critical_section(S_NETCONFIGS); + SaveRoomNetConfigFile(CC->room.QRnumber, ChrPtr(TheConfig)); + end_critical_section(S_NETCONFIGS); + FreeStrBuf(&TheConfig); +} - if (OneRNCFG->misc != NULL) { - StrBufAppendBuf(OutBuffer, OneRNCFG->misc, 0); - } - rc = write(TmpFD, ChrPtr(OutBuffer), StrLength(OutBuffer)); - if ((rc >=0 ) && (rc == StrLength(Cfg))) - { - close(TmpFD); - rename(tempfilename, filename); - rc = 1; - } - else { - syslog(LOG_EMERG, - "unable to write %s; [%s]; not enough space on the disk?\n", - tempfilename, - strerror(errno)); - close(TmpFD); - unlink(tempfilename); - rc = 0; +/* + * Convert any legacy configuration files in the "netconfigs" directory + */ +void convert_legacy_netcfg_files(void) +{ + DIR *dh = NULL; + struct dirent *dit = NULL; + char filename[PATH_MAX]; + long roomnum; + FILE *fp; + long len; + char *v; + + dh = opendir(ctdl_netcfg_dir); + if (!dh) return; + + syslog(LOG_INFO, "netconfig: 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) { + snprintf(filename, sizeof filename, "%s/%ld", ctdl_netcfg_dir, roomnum); + fp = fopen(filename, "r"); + if (fp) { + fseek(fp, 0L, SEEK_END); + len = ftell(fp); + if (len > 0) { + v = malloc(len); + if (v) { + rewind(fp); + if (fread(v, len, 1, fp)) { + SaveRoomNetConfigFile(roomnum, v); + unlink(filename); + } + free(v); + } + } + else { + unlink(filename); // zero length netconfig, just delete it + } + fclose(fp); + } } - FreeStrBuf(&OutBuffer); - } - return rc; -} + closedir(dh); + rmdir(ctdl_netcfg_dir); +} -void free_spoolcontrol_struct(OneRoomNetCfg **pOneRNCFG) +/* + * Module entry point + */ +CTDL_MODULE_INIT(netconfig) { - RoomNetCfg eCfg; - HashPos *CfgIt; - OneRoomNetCfg *OneRNCFG; - - OneRNCFG = *pOneRNCFG; - CfgIt = GetNewHashPos(CfgTypeHash, 1); - for (eCfg = subpending; eCfg < maxRoomNetCfg; eCfg ++) + if (!threading) { - const CfgLineType *pCfg; - RoomNetCfgLine *pNext, *pName; - - pCfg = GetCfgTypeByEnum(eCfg, CfgIt); - pName= OneRNCFG->NetConfigs[pCfg->C]; - while (pName != NULL) - { - pNext = pName->next; - pCfg->DeAllocator(pCfg, &pName); - pName = pNext; - } + convert_legacy_netcfg_files(); + CtdlRegisterProtoHook(cmd_gnet, "GNET", "Get network config"); + CtdlRegisterProtoHook(cmd_snet, "SNET", "Set network config"); } - DeleteHashPos(&CfgIt); - - FreeStrBuf(&OneRNCFG->Sender); - FreeStrBuf(&OneRNCFG->RoomInfo); - FreeStrBuf(&OneRNCFG->misc); - free(OneRNCFG); - *pOneRNCFG=NULL; + return "netconfig"; } -