60b364850c913be28a94a7c0d850806878c23eee
[citadel.git] / citadel / modules / upgrade / serv_upgrade.c
1 /*
2  * $Id$
3  *
4  * Transparently handle the upgrading of server data formats.
5  *
6  */
7
8 #include "sysdep.h"
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <stdio.h>
12 #include <fcntl.h>
13 #include <signal.h>
14 #include <pwd.h>
15 #include <errno.h>
16 #include <sys/types.h>
17
18 #if TIME_WITH_SYS_TIME
19 # include <sys/time.h>
20 # include <time.h>
21 #else
22 # if HAVE_SYS_TIME_H
23 #  include <sys/time.h>
24 # else
25 #  include <time.h>
26 # endif
27 #endif
28
29 #include <sys/wait.h>
30 #include <string.h>
31 #include <limits.h>
32 #include <libcitadel.h>
33 #include "citadel.h"
34 #include "server.h"
35 #include "citserver.h"
36 #include "support.h"
37 #include "config.h"
38 #include "control.h"
39 #include "database.h"
40 #include "room_ops.h"
41 #include "user_ops.h"
42 #include "msgbase.h"
43 #include "serv_upgrade.h"
44 #include "euidindex.h"
45
46
47 #include "ctdl_module.h"
48
49
50
51 /*
52  * Fix up the name for Citadel user 0 and try to remove any extra users with number 0
53  */
54 void fix_sys_user_name(void)
55 {
56         struct ctdluser usbuf;
57         char usernamekey[USERNAME_SIZE];
58
59         /** If we have a user called Citadel rename them to SYS_Citadel */
60         if (getuser(&usbuf, "Citadel") == 0)
61         {
62                 rename_user("Citadel", "SYS_Citadel");
63         }
64
65         while (getuserbynumber(&usbuf, 0) == 0)
66         {
67                 /* delete user with number 0 and no name */
68                 if (IsEmptyStr(usbuf.fullname))
69                         cdb_delete(CDB_USERS, "", 0);
70                 else
71                 { /* temporarily set this user to -1 */
72                         usbuf.usernum = -1;
73                         putuser(&usbuf);
74                 }
75         }
76
77         /** Make sure user SYS_* is user 0 */
78         while (getuserbynumber(&usbuf, -1) == 0)
79         {
80                 if (strncmp(usbuf.fullname, "SYS_", 4))
81                 {       /** Delete any user 0 that doesn't start with SYS_ */
82                         makeuserkey(usernamekey, usbuf.fullname);
83                         cdb_delete(CDB_USERS, usernamekey, strlen(usernamekey));
84                 }
85                 else
86                 {
87                         usbuf.usernum = 0;
88                         putuser(&usbuf);
89                 }
90         }
91 }
92
93
94 /* 
95  * Back end processing function for cmd_bmbx
96  */
97 void cmd_bmbx_backend(struct ctdlroom *qrbuf, void *data) {
98         static struct RoomProcList *rplist = NULL;
99         struct RoomProcList *ptr;
100         struct ctdlroom qr;
101
102         /* Lazy programming here.  Call this function as a ForEachRoom backend
103          * in order to queue up the room names, or call it with a null room
104          * to make it do the processing.
105          */
106         if (qrbuf != NULL) {
107                 ptr = (struct RoomProcList *)
108                         malloc(sizeof (struct RoomProcList));
109                 if (ptr == NULL) return;
110
111                 safestrncpy(ptr->name, qrbuf->QRname, sizeof ptr->name);
112                 ptr->next = rplist;
113                 rplist = ptr;
114                 return;
115         }
116
117         while (rplist != NULL) {
118
119                 if (lgetroom(&qr, rplist->name) == 0) {
120                         CtdlLogPrintf(CTDL_DEBUG, "Processing <%s>...\n", rplist->name);
121                         if ( (qr.QRflags & QR_MAILBOX) == 0) {
122                                 CtdlLogPrintf(CTDL_DEBUG, "  -- not a mailbox\n");
123                         }
124                         else {
125
126                                 qr.QRgen = time(NULL);
127                                 CtdlLogPrintf(CTDL_DEBUG, "  -- fixed!\n");
128                         }
129                         lputroom(&qr);
130                 }
131
132                 ptr = rplist;
133                 rplist = rplist->next;
134                 free(ptr);
135         }
136 }
137
138 /*
139  * quick fix to bump mailbox generation numbers
140  */
141 void bump_mailbox_generation_numbers(void) {
142         CtdlLogPrintf(CTDL_WARNING, "Applying security fix to mailbox rooms\n");
143         ForEachRoom(cmd_bmbx_backend, NULL);
144         cmd_bmbx_backend(NULL, NULL);
145         return;
146 }
147
148
149 /* 
150  * Back end processing function for convert_ctdluid_to_minusone()
151  */
152 void cbtm_backend(struct ctdluser *usbuf, void *data) {
153         static struct UserProcList *uplist = NULL;
154         struct UserProcList *ptr;
155         struct ctdluser us;
156
157         /* Lazy programming here.  Call this function as a ForEachUser backend
158          * in order to queue up the room names, or call it with a null user
159          * to make it do the processing.
160          */
161         if (usbuf != NULL) {
162                 ptr = (struct UserProcList *)
163                         malloc(sizeof (struct UserProcList));
164                 if (ptr == NULL) return;
165
166                 safestrncpy(ptr->user, usbuf->fullname, sizeof ptr->user);
167                 ptr->next = uplist;
168                 uplist = ptr;
169                 return;
170         }
171
172         while (uplist != NULL) {
173
174                 if (lgetuser(&us, uplist->user) == 0) {
175                         CtdlLogPrintf(CTDL_DEBUG, "Processing <%s>...\n", uplist->user);
176                         if (us.uid == CTDLUID) {
177                                 us.uid = (-1);
178                         }
179                         lputuser(&us);
180                 }
181
182                 ptr = uplist;
183                 uplist = uplist->next;
184                 free(ptr);
185         }
186 }
187
188 /*
189  * quick fix to change all CTDLUID users to (-1)
190  */
191 void convert_ctdluid_to_minusone(void) {
192         CtdlLogPrintf(CTDL_WARNING, "Applying uid changes\n");
193         ForEachUser(cbtm_backend, NULL);
194         cbtm_backend(NULL, NULL);
195         return;
196 }
197
198
199 /*
200  * Attempt to guess the name of the time zone currently in use
201  * on the underlying host system.
202  */
203 void guess_time_zone(void) {
204         FILE *fp;
205         char buf[PATH_MAX];
206
207         fp = popen(file_guesstimezone, "r");
208         if (fp) {
209                 if (fgets(buf, sizeof buf, fp) && (strlen(buf) > 2)) {
210                         buf[strlen(buf)-1] = 0;
211                         safestrncpy(config.c_default_cal_zone, buf, sizeof config.c_default_cal_zone);
212                         CtdlLogPrintf(CTDL_INFO, "Configuring timezone: %s\n", config.c_default_cal_zone);
213                 }
214                 fclose(fp);
215         }
216 }
217
218
219 /*
220  * Do various things to our configuration file
221  */
222 void update_config(void) {
223         get_config();
224
225         if (CitControl.version < 606) {
226                 config.c_rfc822_strict_from = 0;
227         }
228
229         if (CitControl.version < 609) {
230                 config.c_purge_hour = 3;
231         }
232
233         if (CitControl.version < 615) {
234                 config.c_ldap_port = 389;
235         }
236
237         if (CitControl.version < 623) {
238                 strcpy(config.c_ip_addr, "0.0.0.0");
239         }
240
241         if (CitControl.version < 650) {
242                 config.c_enable_fulltext = 0;
243         }
244
245         if (CitControl.version < 652) {
246                 config.c_auto_cull = 1;
247         }
248
249         if (CitControl.version < 725) {
250                 config.c_xmpp_c2s_port = 5222;
251                 config.c_xmpp_s2s_port = 5269;
252         }
253
254         /* Erase LDAP config that might be left over from the old connector
255          * which served a different purpose.
256          */
257         if (CitControl.version < 760) {
258                 strcpy(config.c_ldap_host, "");
259                 config.c_ldap_port = 389;
260                 strcpy(config.c_ldap_base_dn, "");
261                 strcpy(config.c_ldap_bind_dn, "");
262                 strcpy(config.c_ldap_bind_pw, "");
263         }
264
265         if (IsEmptyStr(config.c_default_cal_zone)) {
266                 guess_time_zone();
267         }
268
269         put_config();
270 }
271
272
273
274
275 void check_server_upgrades(void) {
276
277         get_control();
278         CtdlLogPrintf(CTDL_INFO, "Server-hosted upgrade level is %d.%02d\n",
279                 (CitControl.version / 100),
280                 (CitControl.version % 100) );
281
282         if (CitControl.version < REV_LEVEL) {
283                 CtdlLogPrintf(CTDL_WARNING,
284                         "Server hosted updates need to be processed at "
285                         "this time.  Please wait...\n");
286         }
287         else {
288                 return;
289         }
290
291         update_config();
292
293         if ((CitControl.version > 000) && (CitControl.version < 555)) {
294                 CtdlLogPrintf(CTDL_EMERG,
295                         "Your data files are from a version of Citadel\n"
296                         "that is too old to be upgraded.  Sorry.\n");
297                 exit(EXIT_FAILURE);
298         }
299         if ((CitControl.version > 000) && (CitControl.version < 591)) {
300                 bump_mailbox_generation_numbers();
301         }
302         if ((CitControl.version > 000) && (CitControl.version < 608)) {
303                 convert_ctdluid_to_minusone();
304         }
305         if ((CitControl.version > 000) && (CitControl.version < 659)) {
306                 rebuild_euid_index();
307         }
308         if (CitControl.version < 735) {
309                 fix_sys_user_name();
310         }
311         if (CitControl.version < 736) {
312                 rebuild_usersbynumber();
313         }
314         CitControl.version = REV_LEVEL;
315         put_control();
316 }
317
318
319 CTDL_MODULE_UPGRADE(upgrade)
320 {
321         check_server_upgrades();
322         
323         /* return our Subversion id for the Log */
324         return "$Id$";
325 }