2 * Transparently handle the upgrading of server data formats.
4 * Copyright (c) 1987-2015 by the citadel.org team
6 * This program is open source software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version 3.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
23 #include <sys/types.h>
25 #if TIME_WITH_SYS_TIME
26 # include <sys/time.h>
30 # include <sys/time.h>
39 #include <libcitadel.h>
42 #include "citserver.h"
49 #include "serv_upgrade.h"
50 #include "euidindex.h"
51 #include "ctdl_module.h"
55 * Fix up the name for Citadel user 0 and try to remove any extra users with number 0
57 void fix_sys_user_name(void)
59 struct ctdluser usbuf;
60 char usernamekey[USERNAME_SIZE];
62 /** If we have a user called Citadel rename them to SYS_Citadel */
63 if (CtdlGetUser(&usbuf, "Citadel") == 0)
65 rename_user("Citadel", "SYS_Citadel");
68 while (CtdlGetUserByNumber(&usbuf, 0) == 0)
70 /* delete user with number 0 and no name */
71 if (IsEmptyStr(usbuf.fullname)) {
72 cdb_delete(CDB_USERS, "", 0);
75 /* temporarily set this user to -1 */
81 /* Make sure user SYS_* is user 0 */
82 while (CtdlGetUserByNumber(&usbuf, -1) == 0)
84 if (strncmp(usbuf.fullname, "SYS_", 4))
85 { /* Delete any user 0 that doesn't start with SYS_ */
86 makeuserkey(usernamekey, usbuf.fullname, cutuserkey(usbuf.fullname));
87 cdb_delete(CDB_USERS, usernamekey, strlen(usernamekey));
98 * Back end processing function for cmd_bmbx
100 void cmd_bmbx_backend(struct ctdlroom *qrbuf, void *data) {
101 static struct RoomProcList *rplist = NULL;
102 struct RoomProcList *ptr;
105 /* Lazy programming here. Call this function as a CtdlForEachRoom backend
106 * in order to queue up the room names, or call it with a null room
107 * to make it do the processing.
110 ptr = (struct RoomProcList *) malloc(sizeof (struct RoomProcList));
111 if (ptr == NULL) return;
113 safestrncpy(ptr->name, qrbuf->QRname, sizeof ptr->name);
119 while (rplist != NULL) {
121 if (CtdlGetRoomLock(&qr, rplist->name) == 0) {
122 syslog(LOG_DEBUG, "Processing <%s>...", rplist->name);
123 if ( (qr.QRflags & QR_MAILBOX) == 0) {
124 syslog(LOG_DEBUG, " -- not a mailbox");
128 qr.QRgen = time(NULL);
129 syslog(LOG_DEBUG, " -- fixed!");
131 CtdlPutRoomLock(&qr);
135 rplist = rplist->next;
141 * quick fix to bump mailbox generation numbers
143 void bump_mailbox_generation_numbers(void) {
144 syslog(LOG_WARNING, "Applying security fix to mailbox rooms");
145 CtdlForEachRoom(cmd_bmbx_backend, NULL);
146 cmd_bmbx_backend(NULL, NULL);
152 * Back end processing function for convert_ctdluid_to_minusone()
154 void cbtm_backend(struct ctdluser *usbuf, void *data) {
155 static struct UserProcList *uplist = NULL;
156 struct UserProcList *ptr;
159 /* Lazy programming here. Call this function as a ForEachUser backend
160 * in order to queue up the room names, or call it with a null user
161 * to make it do the processing.
164 ptr = (struct UserProcList *)
165 malloc(sizeof (struct UserProcList));
166 if (ptr == NULL) return;
168 safestrncpy(ptr->user, usbuf->fullname, sizeof ptr->user);
174 while (uplist != NULL) {
176 if (CtdlGetUserLock(&us, uplist->user) == 0) {
177 syslog(LOG_DEBUG, "Processing <%s>...", uplist->user);
178 if (us.uid == CTDLUID) {
181 CtdlPutUserLock(&us);
185 uplist = uplist->next;
191 * quick fix to change all CTDLUID users to (-1)
193 void convert_ctdluid_to_minusone(void) {
194 syslog(LOG_WARNING, "Applying uid changes");
195 ForEachUser(cbtm_backend, NULL);
196 cbtm_backend(NULL, NULL);
203 * These accounts may have been created by code that ran between mid 2008 and early 2011.
204 * If present they are no longer in use and may be deleted.
206 void remove_thread_users(void) {
207 char *deleteusers[] = {
216 "SYS_select_on_master",
221 struct ctdluser usbuf;
222 for (i=0; i<(sizeof(deleteusers)/sizeof(char *)); ++i) {
223 if (CtdlGetUser(&usbuf, deleteusers[i]) == 0) {
225 strcpy(usbuf.password, "deleteme");
228 "System user account <%s> is no longer in use and will be deleted.",
237 * Attempt to guess the name of the time zone currently in use
238 * on the underlying host system.
240 void guess_time_zone(void) {
244 fp = popen(file_guesstimezone, "r");
246 if (fgets(buf, sizeof buf, fp) && (strlen(buf) > 2)) {
247 buf[strlen(buf)-1] = 0;
248 safestrncpy(config.c_default_cal_zone, buf, sizeof config.c_default_cal_zone);
249 syslog(LOG_INFO, "Configuring timezone: %s", config.c_default_cal_zone);
257 * Perform any upgrades that can be done automatically based on our knowledge of the previous
258 * version of Citadel server that was running here.
260 * Note that if the previous version was 0 then this is a new installation running for the first time.
262 void update_config(void) {
265 if (CitControl.MM_hosted_upgrade_level < 606) {
266 config.c_rfc822_strict_from = 0;
269 if (CitControl.MM_hosted_upgrade_level < 609) {
270 config.c_purge_hour = 3;
273 if (CitControl.MM_hosted_upgrade_level < 615) {
274 config.c_ldap_port = 389;
277 if (CitControl.MM_hosted_upgrade_level < 623) {
278 strcpy(config.c_ip_addr, "*");
281 if (CitControl.MM_hosted_upgrade_level < 650) {
282 config.c_enable_fulltext = 1;
285 if (CitControl.MM_hosted_upgrade_level < 652) {
286 config.c_auto_cull = 1;
289 if (CitControl.MM_hosted_upgrade_level < 725) {
290 config.c_xmpp_c2s_port = 5222;
291 config.c_xmpp_s2s_port = 5269;
294 if (CitControl.MM_hosted_upgrade_level < 830) {
295 config.c_nntp_port = 119;
296 config.c_nntps_port = 563;
299 if (IsEmptyStr(config.c_default_cal_zone)) {
309 * Based on the server version number reported by the existing database,
310 * run in-place data format upgrades until everything is up to date.
312 void check_server_upgrades(void) {
315 syslog(LOG_INFO, "Existing database version on disk is %d.%02d",
316 (CitControl.MM_hosted_upgrade_level / 100),
317 (CitControl.MM_hosted_upgrade_level % 100)
320 if (CitControl.MM_hosted_upgrade_level < REV_LEVEL) {
322 "Server hosted updates need to be processed at this time. Please wait..."
331 if ((CitControl.MM_hosted_upgrade_level > 000) && (CitControl.MM_hosted_upgrade_level < 555)) {
332 syslog(LOG_EMERG, "This database is too old to be upgraded. Citadel server will exit.");
335 if ((CitControl.MM_hosted_upgrade_level > 000) && (CitControl.MM_hosted_upgrade_level < 591)) {
336 bump_mailbox_generation_numbers();
338 if ((CitControl.MM_hosted_upgrade_level > 000) && (CitControl.MM_hosted_upgrade_level < 608)) {
339 convert_ctdluid_to_minusone();
341 if ((CitControl.MM_hosted_upgrade_level > 000) && (CitControl.MM_hosted_upgrade_level < 659)) {
342 rebuild_euid_index();
344 if (CitControl.MM_hosted_upgrade_level < 735) {
347 if (CitControl.MM_hosted_upgrade_level < 736) {
348 rebuild_usersbynumber();
350 if (CitControl.MM_hosted_upgrade_level < 790) {
351 remove_thread_users();
353 if (CitControl.MM_hosted_upgrade_level < 810) {
354 struct ctdlroom QRoom;
355 if (!CtdlGetRoom(&QRoom, SMTP_SPOOLOUT_ROOM)) {
356 QRoom.QRdefaultview = VIEW_QUEUE;
359 if (!CtdlGetRoom(&QRoom, FNBL_QUEUE_ROOM)) {
360 QRoom.QRdefaultview = VIEW_QUEUE;
365 CitControl.MM_hosted_upgrade_level = REV_LEVEL;
368 * Negative values for maxsessions are not allowed.
370 if (config.c_maxsessions < 0) {
371 config.c_maxsessions = 0;
374 /* We need a system default message expiry policy, because this is
375 * the top level and there's no 'higher' policy to fall back on.
376 * By default, do not expire messages at all.
378 if (config.c_ep.expire_mode == 0) {
379 config.c_ep.expire_mode = EXPIRE_MANUAL;
380 config.c_ep.expire_value = 0;
387 CTDL_MODULE_UPGRADE(upgrade)
389 check_server_upgrades();
391 /* return our module id for the Log */