cfb8cc27385d9a886458b8f1dfe326f86d8d8010
[citadel.git] / citadel / server / netconfig.c
1 // This module handles loading, saving, and parsing of room network configurations.
2 //
3 // Copyright (c) 2000-2023 by the citadel.org team
4 //
5 // This program is open source software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License, version 3.
7
8 #include "sysdep.h"
9 #include <stdio.h>
10 #include <sys/types.h>
11 #include <dirent.h>
12 #include <assert.h>
13 #include <libcitadel.h>
14 #include "ctdl_module.h"
15 #include "serv_extensions.h"
16 #include "config.h"
17
18
19 // Create a config key for a room's netconfig entry
20 void netcfg_keyname(char *keybuf, long roomnum) {
21         if (!keybuf) return;
22         sprintf(keybuf, "c_netconfig_%010ld", roomnum);
23 }
24
25
26 // Given a room number and a textual netconfig, convert to base64 and write to the configdb
27 void SaveRoomNetConfigFile(long roomnum, const char *raw_netconfig) {
28         char keyname[25];
29         char *enc;
30         int enc_len;
31         int len;
32
33         len = strlen(raw_netconfig);
34         netcfg_keyname(keyname, roomnum);
35         enc = malloc(len * 2);
36
37         if (enc) {
38                 enc_len = CtdlEncodeBase64(enc, raw_netconfig, len, BASE64_NO_LINEBREAKS);
39                 if ((enc_len > 1) && (enc[enc_len-2] == 13)) enc[enc_len-2] = 0;
40                 if ((enc_len > 0) && (enc[enc_len-1] == 10)) enc[enc_len-1] = 0;
41                 enc[enc_len] = 0;
42                 syslog(LOG_DEBUG, "netconfig: writing key '%s' (length=%d)", keyname, enc_len);
43                 CtdlSetConfigStr(keyname, enc);
44                 free(enc);
45         }
46 }
47
48
49 // Given a room number, attempt to load the netconfig configdb entry for that room.
50 // If it returns NULL, there is no netconfig.
51 // Otherwise the caller owns the returned memory and is responsible for freeing it.
52 char *LoadRoomNetConfigFile(long roomnum) {
53         char keyname[25];
54         char *encoded_netconfig = NULL;
55         char *decoded_netconfig = NULL;
56
57         netcfg_keyname(keyname, roomnum);
58         encoded_netconfig = CtdlGetConfigStr(keyname);
59         if (!encoded_netconfig) return NULL;
60
61         decoded_netconfig = malloc(strlen(encoded_netconfig));  // yeah, way bigger than it needs to be, but safe
62         CtdlDecodeBase64(decoded_netconfig, encoded_netconfig, strlen(encoded_netconfig));
63         return decoded_netconfig;
64 }
65
66
67 //-----------------------------------------------------------------------------
68 //              Per room network configs : exchange with client                
69 //-----------------------------------------------------------------------------
70 void cmd_gnet(char *argbuf) {
71         if ( (CC->room.QRflags & QR_MAILBOX) && (CC->user.usernum == atol(CC->room.QRname)) ) {
72                 // users can edit the netconfigs for their own mailbox rooms
73         }
74         else if (CtdlAccessCheck(ac_room_aide)) return;
75         
76         cprintf("%d Network settings for room #%ld <%s>\n", LISTING_FOLLOWS, CC->room.QRnumber, CC->room.QRname);
77
78         char *c = LoadRoomNetConfigFile(CC->room.QRnumber);
79         if (c) {
80                 int len = strlen(c);
81                 client_write(c, len);                   // Can't use cprintf() here, it has a limit of 1024 bytes
82                 if (c[len] != '\n') {
83                         client_write(HKEY("\n"));
84                 }
85                 free(c);
86         }
87         cprintf("000\n");
88 }
89
90
91 void cmd_snet(char *argbuf) {
92         StrBuf *Line = NULL;
93         StrBuf *TheConfig = NULL;
94         int rc;
95
96         unbuffer_output();
97         Line = NewStrBuf();
98         TheConfig = NewStrBuf();
99         cprintf("%d send new netconfig now\n", SEND_LISTING);
100
101         while (rc = CtdlClientGetLine(Line), (rc >= 0)) {
102                 if ((rc == 3) && (strcmp(ChrPtr(Line), "000") == 0))
103                         break;
104
105                 StrBufAppendBuf(TheConfig, Line, 0);
106                 StrBufAppendBufPlain(TheConfig, HKEY("\n"), 0);
107         }
108         FreeStrBuf(&Line);
109
110         begin_critical_section(S_NETCONFIGS);
111         SaveRoomNetConfigFile(CC->room.QRnumber, ChrPtr(TheConfig));
112         end_critical_section(S_NETCONFIGS);
113         FreeStrBuf(&TheConfig);
114 }
115
116
117 // Convert any legacy configuration files in the "netconfigs" directory
118 void convert_legacy_netcfg_files(void) {
119         DIR *dh = NULL;
120         struct dirent *dit = NULL;
121         char filename[PATH_MAX];
122         long roomnum;
123         FILE *fp;
124         long len;
125         char *v;
126
127         dh = opendir(ctdl_netcfg_dir);
128         if (!dh) return;
129
130         syslog(LOG_INFO, "netconfig: legacy netconfig files exist - converting them!");
131
132         while (dit = readdir(dh), dit != NULL) {        // yes, we use the non-reentrant version; we're not in threaded mode yet
133                 roomnum = atol(dit->d_name);
134                 if (roomnum > 0) {
135                         snprintf(filename, sizeof filename, "%s/%ld", ctdl_netcfg_dir, roomnum);
136                         fp = fopen(filename, "r");
137                         if (fp) {
138                                 fseek(fp, 0L, SEEK_END);
139                                 len = ftell(fp);
140                                 if (len > 0) {
141                                         v = malloc(len);
142                                         if (v) {
143                                                 rewind(fp);
144                                                 if (fread(v, len, 1, fp)) {
145                                                         SaveRoomNetConfigFile(roomnum, v);
146                                                         unlink(filename);
147                                                 }
148                                                 free(v);
149                                         }
150                                 }
151                                 else {
152                                         unlink(filename);       // zero length netconfig, just delete it
153                                 }
154                                 fclose(fp);
155                         }
156                 }
157         }
158
159         closedir(dh);
160         rmdir(ctdl_netcfg_dir);
161 }
162
163
164 /*
165  * Module entry point
166  */
167 char *ctdl_module_init_netconfig(void) {
168         if (!threading) {
169                 convert_legacy_netcfg_files();
170                 CtdlRegisterProtoHook(cmd_gnet, "GNET", "Get network config");
171                 CtdlRegisterProtoHook(cmd_snet, "SNET", "Set network config");
172         }
173         return "netconfig";
174 }