2 * Transparently handle the upgrading of server data formats.
4 * Copyright (c) 1987-2012 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>
24 #include <sys/utsname.h>
26 #if TIME_WITH_SYS_TIME
27 # include <sys/time.h>
31 # include <sys/time.h>
40 #include <libcitadel.h>
43 #include "citserver.h"
50 #include "serv_upgrade.h"
51 #include "euidindex.h"
52 #include "ctdl_module.h"
56 * Fix up the name for Citadel user 0 and try to remove any extra users with number 0
58 void fix_sys_user_name(void)
60 struct ctdluser usbuf;
61 char usernamekey[USERNAME_SIZE];
63 /** If we have a user called Citadel rename them to SYS_Citadel */
64 if (CtdlGetUser(&usbuf, "Citadel") == 0)
66 rename_user("Citadel", "SYS_Citadel");
69 while (CtdlGetUserByNumber(&usbuf, 0) == 0)
71 /* delete user with number 0 and no name */
72 if (IsEmptyStr(usbuf.fullname)) {
73 cdb_delete(CDB_USERS, "", 0);
76 /* temporarily set this user to -1 */
82 /* Make sure user SYS_* is user 0 */
83 while (CtdlGetUserByNumber(&usbuf, -1) == 0)
85 if (strncmp(usbuf.fullname, "SYS_", 4))
86 { /* Delete any user 0 that doesn't start with SYS_ */
87 makeuserkey(usernamekey, usbuf.fullname, cutuserkey(usbuf.fullname));
88 cdb_delete(CDB_USERS, usernamekey, strlen(usernamekey));
99 * Back end processing function for cmd_bmbx
101 void cmd_bmbx_backend(struct ctdlroom *qrbuf, void *data) {
102 static struct RoomProcList *rplist = NULL;
103 struct RoomProcList *ptr;
106 /* Lazy programming here. Call this function as a CtdlForEachRoom backend
107 * in order to queue up the room names, or call it with a null room
108 * to make it do the processing.
111 ptr = (struct RoomProcList *) malloc(sizeof (struct RoomProcList));
112 if (ptr == NULL) return;
114 safestrncpy(ptr->name, qrbuf->QRname, sizeof ptr->name);
120 while (rplist != NULL) {
122 if (CtdlGetRoomLock(&qr, rplist->name) == 0) {
123 syslog(LOG_DEBUG, "Processing <%s>...", rplist->name);
124 if ( (qr.QRflags & QR_MAILBOX) == 0) {
125 syslog(LOG_DEBUG, " -- not a mailbox");
129 qr.QRgen = time(NULL);
130 syslog(LOG_DEBUG, " -- fixed!");
132 CtdlPutRoomLock(&qr);
136 rplist = rplist->next;
142 * quick fix to bump mailbox generation numbers
144 void bump_mailbox_generation_numbers(void) {
145 syslog(LOG_WARNING, "Applying security fix to mailbox rooms");
146 CtdlForEachRoom(cmd_bmbx_backend, NULL);
147 cmd_bmbx_backend(NULL, NULL);
153 * Back end processing function for convert_ctdluid_to_minusone()
155 void cbtm_backend(struct ctdluser *usbuf, void *data) {
156 static struct UserProcList *uplist = NULL;
157 struct UserProcList *ptr;
160 /* Lazy programming here. Call this function as a ForEachUser backend
161 * in order to queue up the room names, or call it with a null user
162 * to make it do the processing.
165 ptr = (struct UserProcList *)
166 malloc(sizeof (struct UserProcList));
167 if (ptr == NULL) return;
169 safestrncpy(ptr->user, usbuf->fullname, sizeof ptr->user);
175 while (uplist != NULL) {
177 if (CtdlGetUserLock(&us, uplist->user) == 0) {
178 syslog(LOG_DEBUG, "Processing <%s>...", uplist->user);
179 if (us.uid == CTDLUID) {
182 CtdlPutUserLock(&us);
186 uplist = uplist->next;
192 * quick fix to change all CTDLUID users to (-1)
194 void convert_ctdluid_to_minusone(void) {
195 syslog(LOG_WARNING, "Applying uid changes");
196 ForEachUser(cbtm_backend, NULL);
197 cbtm_backend(NULL, NULL);
204 * These accounts may have been created by code that ran between mid 2008 and early 2011.
205 * If present they are no longer in use and may be deleted.
207 void remove_thread_users(void) {
208 char *deleteusers[] = {
217 "SYS_select_on_master",
222 struct ctdluser usbuf;
223 for (i=0; i<(sizeof(deleteusers)/sizeof(char *)); ++i) {
224 if (CtdlGetUser(&usbuf, deleteusers[i]) == 0) {
226 strcpy(usbuf.password, "deleteme");
229 "System user account <%s> is no longer in use and will be deleted.",
238 * Attempt to guess the name of the time zone currently in use
239 * on the underlying host system.
241 void guess_time_zone(void) {
245 fp = popen(file_guesstimezone, "r");
247 if (fgets(buf, sizeof buf, fp) && (strlen(buf) > 2)) {
248 buf[strlen(buf)-1] = 0;
249 safestrncpy(config.c_default_cal_zone, buf, sizeof config.c_default_cal_zone);
250 syslog(LOG_INFO, "Configuring timezone: %s", config.c_default_cal_zone);
258 * Put some sane default values into our configuration. Some will be overridden when we run setup.
260 void brand_new_installation_set_defaults(void) {
263 struct utsname my_utsname;
266 /* Determine our host name, in case we need to use it as a default */
269 /* set some sample/default values in place of blanks... */
270 char c_nodename[256];
271 safestrncpy(c_nodename, my_utsname.nodename, sizeof c_nodename);
272 strtok(config.c_nodename, ".");
273 if (IsEmptyStr(config.c_fqdn) ) {
274 if ((he = gethostbyname(my_utsname.nodename)) != NULL) {
275 safestrncpy(config.c_fqdn, he->h_name, sizeof config.c_fqdn);
278 safestrncpy(config.c_fqdn, my_utsname.nodename, sizeof config.c_fqdn);
282 safestrncpy(config.c_humannode, "Citadel Server", sizeof config.c_humannode);
283 safestrncpy(config.c_phonenum, "US 800 555 1212", sizeof config.c_phonenum);
285 safestrncpy(config.c_moreprompt, "<more>", sizeof config.c_moreprompt);
286 safestrncpy(config.c_twitroom, "Trashcan", sizeof config.c_twitroom);
287 safestrncpy(config.c_baseroom, BASEROOM, sizeof config.c_baseroom);
288 safestrncpy(config.c_aideroom, "Aide", sizeof config.c_aideroom);
289 config.c_port_number = 504;
290 config.c_sleeping = 900;
291 config.c_instant_expunge = 1;
293 if (config.c_ctdluid == 0) {
294 pw = getpwnam("citadel");
296 config.c_ctdluid = pw->pw_uid;
299 if (config.c_ctdluid == 0) {
300 pw = getpwnam("bbs");
302 config.c_ctdluid = pw->pw_uid;
305 if (config.c_ctdluid == 0) {
306 pw = getpwnam("guest");
308 config.c_ctdluid = pw->pw_uid;
311 if (config.c_createax == 0) {
312 config.c_createax = 3;
316 * Default port numbers for various services
318 config.c_smtp_port = 25;
319 config.c_pop3_port = 110;
320 config.c_imap_port = 143;
321 config.c_msa_port = 587;
322 config.c_smtps_port = 465;
323 config.c_pop3s_port = 995;
324 config.c_imaps_port = 993;
325 config.c_pftcpdict_port = -1 ;
326 config.c_managesieve_port = 2020;
327 config.c_xmpp_c2s_port = 5222;
328 config.c_xmpp_s2s_port = 5269;
334 * Perform any upgrades that can be done automatically based on our knowledge of the previous
335 * version of Citadel server that was running here.
337 * Note that if the previous version was 0 then this is a new installation running for the first time.
339 void update_config(void) {
342 if (CitControl.version == 0) {
343 brand_new_installation_set_defaults();
346 if (CitControl.version < 606) {
347 config.c_rfc822_strict_from = 0;
350 if (CitControl.version < 609) {
351 config.c_purge_hour = 3;
354 if (CitControl.version < 615) {
355 config.c_ldap_port = 389;
358 if (CitControl.version < 623) {
359 strcpy(config.c_ip_addr, "*");
362 if (CitControl.version < 650) {
363 config.c_enable_fulltext = 1;
366 if (CitControl.version < 652) {
367 config.c_auto_cull = 1;
370 if (CitControl.version < 725) {
371 config.c_xmpp_c2s_port = 5222;
372 config.c_xmpp_s2s_port = 5269;
375 if (IsEmptyStr(config.c_default_cal_zone)) {
385 * Based on the server version number reported by the existing database,
386 * run in-place data format upgrades until everything is up to date.
388 void check_server_upgrades(void) {
391 syslog(LOG_INFO, "Existing database version on disk is %d.%02d",
392 (CitControl.version / 100),
393 (CitControl.version % 100)
396 if (CitControl.version < REV_LEVEL) {
398 "Server hosted updates need to be processed at this time. Please wait..."
407 if ((CitControl.version > 000) && (CitControl.version < 555)) {
408 syslog(LOG_EMERG, "This database is too old to be upgraded. Citadel server will exit.");
411 if ((CitControl.version > 000) && (CitControl.version < 591)) {
412 bump_mailbox_generation_numbers();
414 if ((CitControl.version > 000) && (CitControl.version < 608)) {
415 convert_ctdluid_to_minusone();
417 if ((CitControl.version > 000) && (CitControl.version < 659)) {
418 rebuild_euid_index();
420 if (CitControl.version < 735) {
423 if (CitControl.version < 736) {
424 rebuild_usersbynumber();
426 if (CitControl.version < 790) {
427 remove_thread_users();
429 CitControl.version = REV_LEVEL;
432 * Negative values for maxsessions are not allowed.
434 if (config.c_maxsessions < 0) {
435 config.c_maxsessions = 0;
438 /* We need a system default message expiry policy, because this is
439 * the top level and there's no 'higher' policy to fall back on.
440 * By default, do not expire messages at all.
442 if (config.c_ep.expire_mode == 0) {
443 config.c_ep.expire_mode = EXPIRE_MANUAL;
444 config.c_ep.expire_value = 0;
451 CTDL_MODULE_UPGRADE(upgrade)
453 check_server_upgrades();
455 /* return our module id for the Log */