* synchronize strings with debian.org strings (where available and appropriate) so...
[citadel.git] / citadel / utils / setup.c
1 /*
2  * Citadel setup utility
3  */
4
5 #define SHOW_ME_VAPPEND_PRINTF
6 #include "ctdl_module.h"
7 #include <stdlib.h>
8 #include <unistd.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include <ctype.h>
12 #include <fcntl.h>
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <sys/utsname.h>
16 #include <sys/wait.h>
17 #include <signal.h>
18 #include <netdb.h>
19 #include <errno.h>
20 #include <limits.h>
21 #include <pwd.h>
22 #include <time.h>
23 #include <libcitadel.h>
24 #include "citadel.h"
25 #include "axdefs.h"
26 #include "sysdep.h"
27 #include "config.h"
28 #include "citadel_dirs.h"
29 #if HAVE_BACKTRACE
30 #include <execinfo.h>
31 #endif
32
33 #ifdef ENABLE_NLS
34 #ifdef HAVE_XLOCALE_H
35 #include <xlocale.h>
36 #endif
37 #include <libintl.h>
38 #include <locale.h>
39 #define _(string)       gettext(string)
40 #else
41 #define _(string)       (string)
42 #endif
43
44
45 #define MAXSETUP 11     /* How many setup questions to ask */
46
47 #define UI_TEXT         0       /* Default setup type -- text only */
48 #define UI_DIALOG       2       /* Use the 'dialog' program */
49 #define UI_SILENT       3       /* Silent running, for use in scripts */
50
51 #define SERVICE_NAME    "citadel"
52 #define PROTO_NAME      "tcp"
53 #define NSSCONF         "/etc/nsswitch.conf"
54
55
56 typedef enum _SetupStep {
57         eCitadelHomeDir = 0,
58         eSysAdminName = 1,
59         eSysAdminPW = 2,
60         eUID = 3,
61         eIP_ADDR = 4,
62         eCTDL_Port = 5,
63         eAuthType = 6,
64         eLDAP_Host = 7,
65         eLDAP_Port = 8,
66         eLDAP_Base_DN = 9,
67         eLDAP_Bind_DN = 10,
68         eLDAP_Bind_PW = 11,
69         eMaxQuestions = 12
70 } eSteupStep;
71
72 ///"CREATE_XINETD_ENTRY";
73 /* Environment variables, don't translate! */
74 const char *EnvNames [eMaxQuestions] = {
75         "HOME_DIRECTORY",
76         "SYSADMIN_NAME",
77         "SYSADMIN_PW",
78         "CITADEL_UID",
79         "IP_ADDR",
80         "CITADEL_PORT",
81         "ENABLE_UNIX_AUTH",
82         "LDAP_HOST",
83         "LDAP_PORT",
84         "LDAP_BASE_DN",
85         "LDAP_BIND_DN",
86         "LDAP_BIND_PW"
87 };
88
89 int setup_type;
90 int using_web_installer = 0;
91 int enable_home = 1;
92 char admin_pass[SIZ];
93 char admin_cmd[SIZ];
94
95 const char *setup_titles[eMaxQuestions];
96 const char *setup_text[eMaxQuestions];
97
98 /* calculate all our path on a central place */
99 /* where to keep our config */
100         
101
102
103 void SetTitles(void)
104 {
105         int have_run_dir;
106 #ifndef HAVE_RUN_DIR
107         have_run_dir = 1;
108 #else
109         have_run_dir = 0;
110 #endif
111         setup_titles[eCitadelHomeDir] = _("Citadel Home Directory");
112         if (have_run_dir)
113                 setup_text[eCitadelHomeDir] = _(
114 "Enter the full pathname of the directory in which the Citadel\n"
115 "installation you are creating or updating resides.  If you\n"
116 "specify a directory other than the default, you will need to\n"
117 "specify the -h flag to the server when you start it up.\n");
118         else
119                 setup_text[eCitadelHomeDir] = _(
120 "Enter the subdirectory name for an alternate installation of "
121 "Citadel. To do a default installation just leave it blank."
122 "If you specify a directory other than the default, you will need to\n"
123 "specify the -h flag to the server when you start it up.\n"
124 "note that it may not have a leading /");
125
126
127         setup_titles[eSysAdminName] = _("Citadel administrator username:");
128         setup_text[eSysAdminName] = _(
129 "Please enter the name of the Citadel user account that should be granted "
130 "administrative privileges once created. If using internal authentication "
131 "this user account will be created if it does not exist. For external "
132 "authentication this user account has to exist.");
133
134
135         setup_titles[eSysAdminPW] = _("Administrator password:");
136         setup_text[eSysAdminPW] = _(
137 "Enter a password for the system administrator. When setup\n"
138 "completes it will attempt to create the administrator user\n"
139 "and set the password specified here.\n");
140
141         setup_titles[eUID] = _("Citadel User ID:");
142         setup_text[eUID] = _(
143 "Citadel needs to run under its own user ID.  This would\n"
144 "typically be called \"citadel\", but if you are running Citadel\n"
145 "as a public BBS, you might also call it \"bbs\" or \"guest\".\n"
146 "The server will run under this user ID.  Please specify that\n"
147 "user ID here.  You may specify either a user name or a numeric\n"
148 "UID.\n");
149
150         setup_titles[eIP_ADDR] = _("Listening address for the Citadel server:");
151         setup_text[eIP_ADDR] = _(
152 "Please specify the IP address which the server should be listening to. "
153 "You can name a specific IPv4 or IPv6 address, or you can specify\n"
154 "'*' for 'any address', '::' for 'any IPv6 address', or '0.0.0.0'\n"
155 "for 'any IPv4 address'. If you leave this blank, Citadel will\n"
156 "listen on all addresses. "
157 "This can usually be left to the default unless multiple instances of Citadel "
158 "are running on the same computer.");
159
160         setup_titles[eCTDL_Port] = _("Server port number:");
161         setup_text[eCTDL_Port] = _(
162 "Specify the TCP port number on which your server will run.\n"
163 "Normally, this will be port 504, which is the official port\n"
164 "assigned by the IANA for Citadel servers.  You will only need\n"
165 "to specify a different port number if you run multiple instances\n"
166 "of Citadel on the same computer and there is something else\n"
167 "already using port 504.\n");
168
169         setup_titles[eAuthType] = _("Authentication method to use:");
170         setup_text[eAuthType] = _(
171 "Please choose the user authentication mode. By default Citadel will use its "
172 "own internal user accounts database. If you choose Host, Citadel users will "
173 "have accounts on the host system, authenticated via /etc/passwd or a PAM "
174 "source. LDAP chooses an RFC 2307 compliant directory server, the last option "
175 "chooses the nonstandard MS Active Directory LDAP scheme."
176 "\n"
177 "Do not change this option unless you are sure it is required, since changing "
178 "back requires a full reinstall of Citadel."
179 "\n"
180 " 0. Self contained authentication\n"
181 " 1. Host system integrated authentication\n"
182 " 2. External LDAP - RFC 2307 compliant directory\n"
183 " 3. External LDAP - nonstandard MS Active Directory\n"
184 "\n"
185 "For help: http://www.citadel.org/doku.php/faq:installation:authmodes\n"
186 "\n"
187 "ANSWER \"0\" UNLESS YOU COMPLETELY UNDERSTAND THIS OPTION.\n");
188
189         setup_titles[eLDAP_Host] = _("LDAP host:");
190         setup_text[eLDAP_Host] = _(
191 "Please enter the host name or IP address of your LDAP server.\n");
192
193         setup_titles[eLDAP_Port] = _("LDAP port number:");
194         setup_text[eLDAP_Port] = _(
195 "Please enter the port number of the LDAP service (usually 389).\n");
196
197         setup_titles[eLDAP_Base_DN] = _("LDAP base DN:");
198         setup_text[eLDAP_Base_DN] = _(
199 "Please enter the Base DN to search for authentication\n"
200 "(for example: dc=example,dc=com)\n");
201
202         setup_titles[eLDAP_Bind_DN] = _("LDAP bind DN:");
203         setup_text[eLDAP_Bind_DN] = _(
204 "Please enter the DN of an account to use for binding to the LDAP server for "
205 "performing queries. The account does not require any other privileges. If "
206 "your LDAP server allows anonymous queries, you can leave this blank."
207 "Please enter the DN of an account to use for binding to the LDAP server\n"
208 "for performing queries.  The account does not require any other\n"
209 "privileges.  If your LDAP server allows anonymous queries, you can\n"
210 "leave this blank.\n");
211
212         setup_titles[eLDAP_Bind_PW] = _("LDAP bind password:");
213         setup_text[eLDAP_Bind_PW] = _(
214 "If you entered a Bind DN in the previous question, you must now enter\n"
215 "the password associated with that account.  Otherwise, you can leave this\n"
216 "blank.\n");
217 }
218
219 /*
220  * print the actual stack frame.
221  */
222 void cit_backtrace(void)
223 {
224 #ifdef HAVE_BACKTRACE
225         void *stack_frames[50];
226         size_t size, i;
227         char **strings;
228
229         size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
230         strings = backtrace_symbols(stack_frames, size);
231         for (i = 0; i < size; i++) {
232                 if (strings != NULL)
233                         fprintf(stderr, "%s\n", strings[i]);
234                 else
235                         fprintf(stderr, "%p\n", stack_frames[i]);
236         }
237         free(strings);
238 #endif
239 }
240
241 struct config config;
242
243
244 struct config config;
245 int direction;
246
247
248 void cleanup(int exitcode)
249 {
250 //      printf("Exitcode: %d\n", exitcode);
251 //      cit_backtrace();
252         exit(exitcode);
253 }
254
255
256
257 void title(const char *text)
258 {
259         if (setup_type == UI_TEXT) {
260                 printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<%s>\n", text);
261         }
262 }
263
264
265
266 int yesno(const char *question, int default_value)
267 {
268         int i = 0;
269         int answer = 0;
270         char buf[SIZ];
271
272         switch (setup_type) {
273
274         case UI_TEXT:
275                 do {
276                         printf("%s\nYes/No [%s] --> ",
277                                 question,
278                                 ( default_value ? "Yes" : "No" )
279                         );
280                         if (fgets(buf, sizeof buf, stdin))
281                         {
282                                 answer = tolower(buf[0]);
283                                 if ((buf[0]==0) || (buf[0]==13) || (buf[0]==10))
284                                         answer = default_value;
285                                 else if (answer == 'y')
286                                         answer = 1;
287                                 else if (answer == 'n')
288                                         answer = 0;
289                         }
290                 } while ((answer < 0) || (answer > 1));
291                 break;
292
293         case UI_DIALOG:
294                 sprintf(buf, "exec %s %s --yesno '%s' 15 75",
295                         getenv("CTDL_DIALOG"),
296                         ( default_value ? "" : "--defaultno" ),
297                         question);
298                 i = system(buf);
299                 if (i == 0) {
300                         answer = 1;
301                 }
302                 else {
303                         answer = 0;
304                 }
305                 break;
306         case UI_SILENT:
307                 break;
308
309         }
310         return (answer);
311 }
312
313
314 void important_message(const char *title, const char *msgtext)
315 {
316         char buf[SIZ];
317         int rv;
318
319         switch (setup_type) {
320
321         case UI_TEXT:
322                 printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
323                 printf("       %s \n\n%s\n\n", title, msgtext);
324                 printf("Press return to continue...");
325                 if (fgets(buf, sizeof buf, stdin));
326                 break;
327
328         case UI_DIALOG:
329                 sprintf(buf, "exec %s --msgbox '%s' 19 72",
330                         getenv("CTDL_DIALOG"),
331                         msgtext);
332                 rv = system(buf);
333                 break;
334         case UI_SILENT:
335                 fprintf(stderr, "%s\n", msgtext);
336                 break;
337         }
338 }
339
340 void important_msgnum(int msgnum)
341 {
342         important_message("Important Message", setup_text[msgnum]);
343 }
344
345 void display_error(char *error_message)
346 {
347         important_message("Error", error_message);
348 }
349
350 void progress(char *text, long int curr, long int cmax)
351 {
352         static long dots_printed = 0L;
353         long a = 0;
354         static FILE *fp = NULL;
355         char buf[SIZ];
356
357         switch (setup_type) {
358
359         case UI_TEXT:
360                 if (curr == 0) {
361                         printf("%s\n", text);
362                         printf("....................................................");
363                         printf("..........................\r");
364                         fflush(stdout);
365                         dots_printed = 0;
366                 } else if (curr == cmax) {
367                         printf("\r%79s\n", "");
368                 } else {
369                         a = (curr * 100) / cmax;
370                         a = a * 78;
371                         a = a / 100;
372                         while (dots_printed < a) {
373                                 printf("*");
374                                 ++dots_printed;
375                                 fflush(stdout);
376                         }
377                 }
378                 break;
379
380         case UI_DIALOG:
381                 if (curr == 0) {
382                         sprintf(buf, "exec %s --gauge '%s' 7 72 0",
383                                 getenv("CTDL_DIALOG"),
384                                 text);
385                         fp = popen(buf, "w");
386                         if (fp != NULL) {
387                                 fprintf(fp, "0\n");
388                                 fflush(fp);
389                         }
390                 } 
391                 else if (curr == cmax) {
392                         if (fp != NULL) {
393                                 fprintf(fp, "100\n");
394                                 pclose(fp);
395                                 fp = NULL;
396                         }
397                 }
398                 else {
399                         a = (curr * 100) / cmax;
400                         if (fp != NULL) {
401                                 fprintf(fp, "%ld\n", a);
402                                 fflush(fp);
403                         }
404                 }
405                 break;
406         case UI_SILENT:
407                 break;
408
409         }
410 }
411
412
413
414 /*
415  * check_services_entry()  -- Make sure "citadel" is in /etc/services
416  *
417  */
418 void check_services_entry(void)
419 {
420         int i;
421         FILE *sfp;
422         char errmsg[256];
423
424         if (getservbyname(SERVICE_NAME, PROTO_NAME) == NULL) {
425                 for (i=0; i<=2; ++i) {
426                         progress("Adding service entry...", i, 2);
427                         if (i == 0) {
428                                 sfp = fopen("/etc/services", "a");
429                                 if (sfp == NULL) {
430                                         sprintf(errmsg, "Cannot open /etc/services: %s", strerror(errno));
431                                         display_error(errmsg);
432                                 } else {
433                                         fprintf(sfp, "%s                504/tcp\n", SERVICE_NAME);
434                                         fclose(sfp);
435                                 }
436                         }
437                 }
438         }
439 }
440
441
442
443
444 /*
445  * delete_inittab_entry()  -- Remove obsolete /etc/inittab entry for Citadel
446  */
447 void delete_inittab_entry(void)
448 {
449         FILE *infp;
450         FILE *outfp;
451         char looking_for[256];
452         char buf[1024];
453         char outfilename[32];
454         int changes_made = 0;
455         int rv;
456
457         /* Determine the fully qualified path name of citserver */
458         snprintf(looking_for, 
459                  sizeof looking_for,
460                  "%s/citserver", 
461                  ctdl_sbin_dir
462                 );
463
464         /* Now tweak /etc/inittab */
465         infp = fopen("/etc/inittab", "r");
466         if (infp == NULL) {
467
468                 /* If /etc/inittab does not exist, return quietly.
469                  * Not all host platforms have it.
470                  */
471                 if (errno == ENOENT) {
472                         return;
473                 }
474
475                 /* Other errors might mean something really did go wrong.
476                  */
477                 sprintf(buf, "Cannot open /etc/inittab: %s", strerror(errno));
478                 display_error(buf);
479                 return;
480         }
481
482         strcpy(outfilename, "/tmp/ctdlsetup.XXXXXX");
483         outfp = fdopen(mkstemp(outfilename), "w+");
484         if (outfp == NULL) {
485                 sprintf(buf, "Cannot open %s: %s", outfilename, strerror(errno));
486                 display_error(buf);
487                 fclose(infp);
488                 return;
489         }
490
491         while (fgets(buf, sizeof buf, infp) != NULL) {
492                 if (strstr(buf, looking_for) != NULL) {
493                         rv = fwrite("#", 1, 1, outfp);
494                         ++changes_made;
495                 }
496                 rv = fwrite(buf, strlen(buf), 1, outfp);
497         }
498
499         fclose(infp);
500         fclose(outfp);
501
502         if (changes_made) {
503                 sprintf(buf, "/bin/mv -f %s /etc/inittab 2>/dev/null", outfilename);
504                 rv = system(buf);
505                 rv = system("/sbin/init q 2>/dev/null");
506         }
507         else {
508                 unlink(outfilename);
509         }
510 }
511
512
513 /*
514  * install_init_scripts()  -- Try to configure to start Citadel at boot
515  */
516 void install_init_scripts(void)
517 {
518         struct stat etcinitd;
519         FILE *fp;
520         char *initfile = "/etc/init.d/citadel";
521         char command[SIZ];
522         int rv;
523
524         if ((stat("/etc/init.d/", &etcinitd) == -1) && 
525             (errno == ENOENT))
526         {
527                 if ((stat("/etc/rc.d/init.d/", &etcinitd) == -1) &&
528                     (errno == ENOENT))
529                         initfile = CTDLDIR"/citadel.init";
530                 else
531                         initfile = "/etc/rc.d/init.d/citadel";
532         }
533
534         fp = fopen(initfile, "r");
535         if (fp != NULL) {
536                 if (yesno("Citadel already appears to be configured to start at boot.\n"
537                           "Would you like to keep your boot configuration as is?\n", 1) == 1) {
538                         return;
539                 }
540                 fclose(fp);
541                 
542         }
543
544         if (yesno("Would you like to automatically start Citadel at boot?\n", 1) == 0) {
545                 return;
546         }
547
548         fp = fopen(initfile, "w");
549         if (fp == NULL) {
550                 display_error("Cannot create /etc/init.d/citadel");
551                 return;
552         }
553
554         fprintf(fp,     "#!/bin/sh\n"
555                 "#\n"
556                 "# Init file for Citadel\n"
557                 "#\n"
558                 "# chkconfig: - 79 30\n"
559                 "# description: Citadel service\n"
560                 "# processname: citserver\n"
561                 "# pidfile: %s/citadel.pid\n\n"
562                 "# uncomment this to create coredumps as described in\n"
563                 "# http://www.citadel.org/doku.php/faq:mastering_your_os:gdb#how.do.i.make.my.system.produce.core-files\n"
564                 "# ulimit -c unlimited\n"
565                 "\n"
566                 "CITADEL_DIR=%s\n"
567                 ,
568                 ctdl_run_dir,
569                 ctdl_sbin_dir
570                 );
571         fprintf(fp,     "\n"
572                 "test -d /var/run || exit 0\n"
573                 "\n"
574                 "case \"$1\" in\n"
575                 "\n"
576                 "start)         echo -n \"Starting Citadel... \"\n"
577                 "               if $CITADEL_DIR/citserver -lmail -d\n"
578                 "               then\n"
579                 "                       echo \"ok\"\n"
580                 "               else\n"
581                 "                       echo \"failed\"\n"
582                 "               fi\n");
583         fprintf(fp,     "               ;;\n"
584                 "stop)          echo -n \"Stopping Citadel... \"\n"
585                 "               if $CITADEL_DIR/sendcommand DOWN >/dev/null 2>&1 ; then\n"
586                 "                       echo \"ok\"\n"
587                 "               else\n"
588                 "                       echo \"failed\"\n"
589                 "               fi\n"
590                 "               rm -f %s/citadel.pid 2>/dev/null\n"
591                 ,
592                 ctdl_run_dir
593                 );
594         fprintf(fp,     "               ;;\n"
595                 "restart)       if $CITADEL_DIR/sendcommand DOWN 1 >/dev/null 2>&1 ; then\n"
596                 "                       echo \"ok\"\n"
597                 "               else\n"
598                 "                       echo \"failed\"\n"
599                 "               fi\n"
600                 "               ;;\n"
601                 "*)             echo \"Usage: $0 {start|stop|restart}\"\n"
602                 "               exit 1\n"
603                 "               ;;\n"
604                 "esac\n"
605                 );
606
607         fclose(fp);
608         chmod(initfile, 0755);
609
610         /* Set up the run levels. */
611         rv = system("/bin/rm -f /etc/rc?.d/[SK]??citadel 2>/dev/null");
612         snprintf(command, sizeof(command), "for x in 2 3 4 5 ; do [ -d /etc/rc$x.d ] && ln -s %s /etc/rc$x.d/S79citadel ; done 2>/dev/null", initfile);
613         rv = system(command);
614         snprintf(command, sizeof(command),"for x in 0 6 S; do [ -d /etc/rc$x.d ] && ln -s %s /etc/rc$x.d/K30citadel ; done 2>/dev/null", initfile);
615         rv = system(command);
616
617 }
618
619
620
621 /*
622  * On systems which use xinetd, see if we can offer to install Citadel as
623  * the default telnet target.
624  */
625 void check_xinetd_entry(void) {
626         char *filename = "/etc/xinetd.d/telnet";
627         FILE *fp;
628         char buf[SIZ];
629         int already_citadel = 0;
630         int rv;
631
632         fp = fopen(filename, "r+");
633         if (fp == NULL) return;         /* Not there.  Oh well... */
634
635         while (fgets(buf, sizeof buf, fp) != NULL) {
636                 if (strstr(buf, "/citadel") != NULL) already_citadel = 1;
637         }
638         fclose(fp);
639         if (already_citadel) return;    /* Already set up this way. */
640
641         /* Otherwise, prompt the user to create an entry. */
642         if (getenv("CREATE_XINETD_ENTRY") != NULL) {
643                 if (strcasecmp(getenv("CREATE_XINETD_ENTRY"), "yes")) {
644                         return;
645                 }
646         }
647         else {
648                 snprintf(buf, sizeof buf,
649                          "Setup can configure the \"xinetd\" service to automatically\n"
650                          "connect incoming telnet sessions to Citadel, bypassing the\n"
651                          "host system login: prompt.  Would you like to do this?\n"
652                         );
653                 if (yesno(buf, 1) == 0) {
654                         return;
655                 }
656         }
657
658         fp = fopen(filename, "w");
659         fprintf(fp,
660                 "# description: telnet service for Citadel users\n"
661                 "service telnet\n"
662                 "{\n"
663                 "       disable = no\n"
664                 "       flags           = REUSE\n"
665                 "       socket_type     = stream\n"
666                 "       wait            = no\n"
667                 "       user            = root\n"
668                 "       server          = /usr/sbin/in.telnetd\n"
669                 "       server_args     = -h -L %s/citadel\n"
670                 "       log_on_failure  += USERID\n"
671                 "}\n",
672                 ctdl_bin_dir);
673         fclose(fp);
674
675         /* Now try to restart the service */
676         rv = system("/etc/init.d/xinetd restart >/dev/null 2>&1");
677 }
678
679
680
681 /*
682  * Offer to disable other MTA's
683  */
684 void disable_other_mta(const char *mta) {
685         char buf[SIZ];
686         FILE *fp;
687         int lines = 0;
688         int rv;
689
690         sprintf(buf, "/bin/ls -l /etc/rc*.d/S*%s 2>/dev/null; "
691                 "/bin/ls -l /etc/rc.d/rc*.d/S*%s 2>/dev/null",
692                 mta, mta);
693         fp = popen(buf, "r");
694         if (fp == NULL) return;
695
696         while (fgets(buf, sizeof buf, fp) != NULL) {
697                 ++lines;
698         }
699         fclose(fp);
700         if (lines == 0) return;         /* Nothing to do. */
701
702
703         /* Offer to replace other MTA with the vastly superior Citadel :)  */
704
705         snprintf(buf, sizeof buf,
706                  "You appear to have the \"%s\" email program\n"
707                  "running on your system.  If you want Citadel mail\n"
708                  "connected with %s, you will have to manually integrate\n"
709                  "them.  It is preferable to disable %s, and use Citadel's\n"
710                  "SMTP, POP3, and IMAP services.\n\n"
711                  "May we disable %s so that Citadel has access to ports\n"
712                  "25, 110, and 143?\n",
713                  mta, mta, mta, mta
714                 );
715         if (yesno(buf, 1) == 0) {
716                 return;
717         }
718         
719
720         sprintf(buf, "for x in /etc/rc*.d/S*%s; do mv $x `echo $x |sed s/S/K/g`; done >/dev/null 2>&1", mta);
721         rv = system(buf);
722         sprintf(buf, "/etc/init.d/%s stop >/dev/null 2>&1", mta);
723         rv = system(buf);
724 }
725
726 const char *other_mtas[] = {
727         "courier-authdaemon",
728         "courier-imap",
729         "courier-imap-ssl",
730         "courier-pop",
731         "courier-pop3",
732         "courier-pop3d",
733         "cyrmaster",
734         "cyrus",
735         "dovecot",
736         "exim",
737         "exim4",
738         "imapd",
739         "mta",
740         "pop3d",
741         "popd",
742         "postfix",
743         "qmail",
744         "saslauthd",
745         "sendmail",
746         "vmailmgrd",
747         ""
748 };
749
750 void disable_other_mtas(void)
751 {
752         int i = 0;
753         if ((getenv("ACT_AS_MTA") == NULL) || 
754             (getenv("ACT_AS_MTA") &&
755              strcasecmp(getenv("ACT_AS_MTA"), "yes") == 0)) {
756                 /* Offer to disable other MTA's on the system. */
757                 while (!IsEmptyStr(other_mtas[i]))
758                 {
759                         disable_other_mta(other_mtas[i]);
760                         i++;
761                 }
762         }
763 }
764
765 /* 
766  * Check to see if our server really works.  Returns 0 on success.
767  */
768 int test_server(char *relhomestr, int relhome) {
769         char cmd[256];
770         char cookie[256];
771         FILE *fp;
772         char buf[4096];
773         int found_it = 0;
774
775         /* Generate a silly little cookie.  We're going to write it out
776          * to the server and try to get it back.  The cookie does not
777          * have to be secret ... just unique.
778          */
779         sprintf(cookie, "--test--%d--", getpid());
780
781         if (relhome)
782                 sprintf(cmd, "%s/sendcommand -h%s ECHO %s 2>&1",
783                         ctdl_sbin_dir,
784                         relhomestr,
785                         cookie);
786         else
787                 sprintf(cmd, "%s/sendcommand ECHO %s 2>&1",
788                         ctdl_sbin_dir,
789                         cookie);
790
791         fp = popen(cmd, "r");
792         if (fp == NULL) return(errno);
793
794         while (fgets(buf, sizeof buf, fp) != NULL) {
795                 if ( (buf[0]=='2')
796                      && (strstr(buf, cookie) != NULL) ) {
797                         ++found_it;
798                 }
799         }
800         pclose(fp);
801
802         if (found_it) {
803                 return(0);
804         }
805         return(-1);
806 }
807
808 void strprompt(const char *prompt_title, const char *prompt_text, char *Target, char *DefValue)
809 {
810         char buf[SIZ] = "";
811         char setupmsg[SIZ];
812         char dialog_result[PATH_MAX];
813         FILE *fp = NULL;
814         int rv;
815
816         strcpy(setupmsg, "");
817
818         switch (setup_type) {
819         case UI_TEXT:
820                 title(prompt_title);
821                 printf("\n%s\n", prompt_text);
822                 printf("This is currently set to:\n%s\n", Target);
823                 printf("Enter new value or press return to leave unchanged:\n");
824                 if (fgets(buf, sizeof buf, stdin)){
825                         buf[strlen(buf) - 1] = 0;
826                 }
827                 if (!IsEmptyStr(buf))
828                         strcpy(Target, buf);
829                 break;
830
831         case UI_DIALOG:
832                 CtdlMakeTempFileName(dialog_result, sizeof dialog_result);
833                 sprintf(buf, "exec %s --inputbox '%s' 19 72 '%s' 2>%s",
834                         getenv("CTDL_DIALOG"),
835                         prompt_text,
836                         Target,
837                         dialog_result);
838                 rv = system(buf);
839                 fp = fopen(dialog_result, "r");
840                 if (fp != NULL) {
841                         if (fgets(Target, sizeof buf, fp)) {
842                                 if (Target[strlen(Target)-1] == 10) {
843                                         Target[strlen(Target)-1] = 0;
844                                 }
845                         }
846                         fclose(fp);
847                         unlink(dialog_result);
848                 }
849                 break;
850         case UI_SILENT:
851                 strcpy(Target, DefValue);
852                 break;
853         }
854 }
855
856 void set_bool_val(int msgpos, int *ip, char *DefValue) 
857 {
858         title(setup_titles[msgpos]);
859         *ip = yesno(setup_text[msgpos], *ip);
860 }
861
862 void set_str_val(int msgpos, char *Target, char *DefValue) 
863 {
864         strprompt(setup_titles[msgpos], 
865                   setup_text[msgpos], 
866                   Target, 
867                   DefValue);
868 }
869
870 void set_int_val(int msgpos, int *ip, char *DefValue)
871 {
872         char buf[16];
873         snprintf(buf, sizeof buf, "%d", (int) *ip);
874         set_str_val(msgpos, buf, DefValue);
875         *ip = atoi(buf);
876 }
877
878
879 void set_char_val(int msgpos, char *ip, char *DefValue)
880 {
881         char buf[16];
882         snprintf(buf, sizeof buf, "%d", (int) *ip);
883         set_str_val(msgpos, buf, DefValue);
884         *ip = (char) atoi(buf);
885 }
886
887
888 void set_long_val(int msgpos, long int *ip, char *DefValue)
889 {
890         char buf[16];
891         snprintf(buf, sizeof buf, "%ld", *ip);
892         set_str_val(msgpos, buf, DefValue);
893         *ip = atol(buf);
894 }
895
896
897 void edit_value(int curr)
898 {
899         int i;
900         struct passwd *pw;
901         char ctdluidname[256];
902         char *Value = NULL;
903
904         if (setup_type == UI_SILENT)
905         {
906                 Value = getenv(EnvNames[curr]);
907         }
908         if (Value == NULL)
909                 Value = "";
910
911
912         switch (curr) {
913
914         case eSysAdminName:
915                 set_str_val(curr, config.c_sysadm, Value);
916                 break;
917
918         case eSysAdminPW:
919                 set_str_val(curr, admin_pass, Value);
920                 break;
921         
922         case eUID:
923                 if (setup_type == UI_SILENT)
924                 {               
925                         if (Value) {
926                                 config.c_ctdluid = atoi(Value);
927                         }                                       
928                 }
929                 else
930                 {
931 #ifdef __CYGWIN__
932                         config.c_ctdluid = 0;   /* XXX Windows hack, prob. insecure */
933 #else
934                         i = config.c_ctdluid;
935                         pw = getpwuid(i);
936                         if (pw == NULL) {
937                                 set_int_val(curr, &i, Value);
938                                 config.c_ctdluid = i;
939                         }
940                         else {
941                                 strcpy(ctdluidname, pw->pw_name);
942                                 set_str_val(curr, ctdluidname, Value);
943                                 pw = getpwnam(ctdluidname);
944                                 if (pw != NULL) {
945                                         config.c_ctdluid = pw->pw_uid;
946                                 }
947                                 else if (atoi(ctdluidname) > 0) {
948                                         config.c_ctdluid = atoi(ctdluidname);
949                                 }
950                         }
951 #endif
952                 }
953                 break;
954
955         case eIP_ADDR:
956                 set_str_val(curr, config.c_ip_addr, Value);
957                 break;
958
959         case eCTDL_Port:
960                 set_int_val(curr, &config.c_port_number, Value);
961                 break;
962
963         case eAuthType:
964                 if (setup_type == UI_SILENT)
965                 {
966                         const char *auth;
967                         config.c_auth_mode = AUTHMODE_NATIVE;
968                         auth = Value;
969                         if (auth != NULL)
970                         {
971                                 if ((strcasecmp(auth, "yes") == 0) ||
972                                     (strcasecmp(auth, "host") == 0))
973                                 {
974                                         config.c_auth_mode = AUTHMODE_HOST;
975                                 }
976                                 else if (strcasecmp(auth, "ldap") == 0){
977                                         config.c_auth_mode = AUTHMODE_LDAP;
978                                 }
979                                 else if ((strcasecmp(auth, "ldap_ad") == 0) ||
980                                          (strcasecmp(auth, "active directory") == 0)){
981                                         config.c_auth_mode = AUTHMODE_LDAP_AD;
982                                 }
983                         }
984                 }
985                 else {
986                         set_int_val(curr, &config.c_auth_mode, Value);
987                 }
988                 break;
989
990         case eLDAP_Host:
991                 set_str_val(curr, config.c_ldap_host, Value);
992                 break;
993
994         case eLDAP_Port:
995                 if (config.c_ldap_port == 0) {
996                         config.c_ldap_port = 389;
997                 }
998                 set_int_val(curr, &config.c_ldap_port, Value);
999                 break;
1000
1001         case eLDAP_Base_DN:
1002                 set_str_val(curr, config.c_ldap_base_dn, Value);
1003                 break;
1004
1005         case eLDAP_Bind_DN:
1006                 set_str_val(curr, config.c_ldap_bind_dn, Value);
1007                 break;
1008
1009         case eLDAP_Bind_PW:
1010                 set_str_val(curr, config.c_ldap_bind_pw, Value);
1011                 break;
1012
1013         }
1014 }
1015
1016 /*
1017  * (re-)write the config data to disk
1018  */
1019 void write_config_to_disk(void)
1020 {
1021         FILE *fp;
1022         int fd;
1023         int rv;
1024
1025         if ((fd = creat(file_citadel_config, S_IRUSR | S_IWUSR)) == -1) {
1026                 display_error("setup: cannot open citadel.config");
1027                 cleanup(1);
1028         }
1029         fp = fdopen(fd, "wb");
1030         if (fp == NULL) {
1031                 display_error("setup: cannot open citadel.config");
1032                 cleanup(1);
1033         }
1034         rv = fwrite((char *) &config, sizeof(struct config), 1, fp);
1035         fclose(fp);
1036 }
1037
1038
1039
1040
1041 /*
1042  * Figure out what type of user interface we're going to use
1043  */
1044 int discover_ui(void)
1045 {
1046
1047         /* Use "dialog" if we have it */
1048         if (getenv("CTDL_DIALOG") != NULL) {
1049                 return UI_DIALOG;
1050         }
1051                 
1052         return UI_TEXT;
1053 }
1054
1055
1056
1057 void migrate_old_installs(void)
1058 {
1059         int rv;
1060         rv = system("exec /bin/rm -fr ./rooms ./chatpipes ./expressmsgs ./sessions 2>/dev/null");
1061         unlink("citadel.log");
1062         unlink("weekly");
1063 }
1064
1065
1066 /*
1067  * Strip "db" entries out of /etc/nsswitch.conf
1068  */
1069 void fixnss(void) {
1070         FILE *fp_read;
1071         int fd_write;
1072         char buf[256];
1073         char buf_nc[256];
1074         char question[512];
1075         int i;
1076         int changed = 0;
1077         int file_changed = 0;
1078         char new_filename[64];
1079         int rv;
1080
1081         fp_read = fopen(NSSCONF, "r");
1082         if (fp_read == NULL) {
1083                 return;
1084         }
1085
1086         strcpy(new_filename, "/tmp/ctdl_fixnss_XXXXXX");
1087         fd_write = mkstemp(new_filename);
1088         if (fd_write < 0) {
1089                 fclose(fp_read);
1090                 return;
1091         }
1092
1093         while (fgets(buf, sizeof buf, fp_read) != NULL) {
1094                 changed = 0;
1095                 strcpy(buf_nc, buf);
1096                 for (i=0; i<strlen(buf_nc); ++i) {
1097                         if (buf_nc[i] == '#') {
1098                                 buf_nc[i] = 0;
1099                         }
1100                 }
1101                 for (i=0; i<strlen(buf_nc); ++i) {
1102                         if (!strncasecmp(&buf_nc[i], "db", 2)) {
1103                                 if (i > 0) {
1104                                         if ((isspace(buf_nc[i+2])) || (buf_nc[i+2]==0)) {
1105                                                 changed = 1;
1106                                                 file_changed = 1;
1107                                                 strcpy(&buf_nc[i], &buf_nc[i+2]);
1108                                                 strcpy(&buf[i], &buf[i+2]);
1109                                                 if (buf[i]==32) {
1110                                                         strcpy(&buf_nc[i], &buf_nc[i+1]);
1111                                                         strcpy(&buf[i], &buf[i+1]);
1112                                                 }
1113                                         }
1114                                 }
1115                         }
1116                 }
1117                 if (write(fd_write, buf, strlen(buf)) != strlen(buf)) {
1118                         fclose(fp_read);
1119                         close(fd_write);
1120                         unlink(new_filename);
1121                         return;
1122                 }
1123         }
1124
1125         fclose(fp_read);
1126         
1127         if (!file_changed) {
1128                 unlink(new_filename);
1129                 return;
1130         }
1131
1132         snprintf(question, sizeof question,
1133                 "\n"
1134                 "/etc/nsswitch.conf is configured to use the 'db' module for\n"
1135                 "one or more services.  This is not necessary on most systems,\n"
1136                 "and it is known to crash the Citadel server when delivering\n"
1137                 "mail to the Internet.\n"
1138                 "\n"
1139                 "Do you want this module to be automatically disabled?\n"
1140                 "\n"
1141         );
1142
1143         if (yesno(question, 1)) {
1144                 sprintf(buf, "/bin/mv -f %s %s", new_filename, NSSCONF);
1145                 rv = system(buf);
1146                 chmod(NSSCONF, 0644);
1147         }
1148         unlink(new_filename);
1149 }
1150
1151 void check_init_script (char *relhome)
1152 {
1153         int rv;
1154         FILE *fp;
1155
1156         /* 
1157          * If we're running on SysV, install init scripts.
1158          */
1159         if (!access("/var/run", W_OK)) {
1160
1161                 if (getenv("NO_INIT_SCRIPTS") == NULL) {
1162                         install_init_scripts();
1163                 }
1164
1165                 if (!access("/etc/init.d/citadel", X_OK)) {
1166                         rv = system("/etc/init.d/citadel start");
1167                         sleep(3);
1168                 }
1169
1170                 if (test_server(relhome, enable_home) == 0) {
1171                         char buf[SIZ];
1172                         int found_it = 0;
1173
1174                         if (config.c_auth_mode == AUTHMODE_NATIVE) {
1175                                 snprintf (admin_cmd, sizeof(admin_cmd), "%s/sendcommand \"CREU %s|%s\" 2>&1", 
1176                                         ctdl_sbin_dir, config.c_sysadm, admin_pass);
1177                                 fp = popen(admin_cmd, "r");
1178                                 if (fp != NULL) {
1179                                         while (fgets(buf, sizeof buf, fp) != NULL) 
1180                                         {
1181                                                 if ((atol(buf) == 574) || (atol(buf) == 200))
1182                                                         ++found_it;
1183                                         }
1184                                         pclose(fp);
1185                                 }
1186                         
1187                                 if (found_it == 0) {
1188                                         important_message("Error","Setup failed to create your admin user");
1189                                 }
1190                         }
1191
1192                         if (setup_type != UI_SILENT)
1193                                 important_message("Setup finished",
1194                                                   "Setup of the Citadel server is complete.\n"
1195                                                   "If you will be using WebCit, please run its\n"
1196                                                   "setup program now; otherwise, run './citadel'\n"
1197                                                   "to log in.\n");
1198                 }
1199                 else {
1200                         important_message("Setup failed",
1201                                 "Setup is finished, but the Citadel server failed to start.\n"
1202                                 "Go back and check your configuration.\n"
1203                         );
1204                 }
1205
1206         }
1207
1208         else {
1209                 important_message("Setup finished",
1210                         "Setup is finished.  You may now start the server.");
1211         }
1212 }
1213
1214 void set_default_values(void)
1215 {
1216         struct passwd *pw;
1217         struct utsname my_utsname;
1218         struct hostent *he;
1219
1220         /* Determine our host name, in case we need to use it as a default */
1221         uname(&my_utsname);
1222
1223         /* set some sample/default values in place of blanks... */
1224         if (IsEmptyStr(config.c_nodename))
1225                 safestrncpy(config.c_nodename, my_utsname.nodename,
1226                             sizeof config.c_nodename);
1227         strtok(config.c_nodename, ".");
1228         if (IsEmptyStr(config.c_fqdn) ) {
1229                 if ((he = gethostbyname(my_utsname.nodename)) != NULL) {
1230                         safestrncpy(config.c_fqdn, he->h_name, sizeof config.c_fqdn);
1231                 } else {
1232                         safestrncpy(config.c_fqdn, my_utsname.nodename, sizeof config.c_fqdn);
1233                 }
1234         }
1235         if (IsEmptyStr(config.c_humannode)) {
1236                 strcpy(config.c_humannode, "My System");
1237         }
1238         if (IsEmptyStr(config.c_phonenum)) {
1239                 strcpy(config.c_phonenum, "US 800 555 1212");
1240         }
1241         if (config.c_initax == 0) {
1242                 config.c_initax = 4;
1243         }
1244         if (IsEmptyStr(config.c_moreprompt)) strcpy(config.c_moreprompt, "<more>");
1245         if (IsEmptyStr(config.c_twitroom)) strcpy(config.c_twitroom, "Trashcan");
1246         if (IsEmptyStr(config.c_baseroom)) strcpy(config.c_baseroom, BASEROOM);
1247         if (IsEmptyStr(config.c_aideroom)) strcpy(config.c_aideroom, "Aide");
1248         if (config.c_port_number == 0) {
1249                 config.c_port_number = 504;
1250         }
1251         if (config.c_sleeping == 0) {
1252                 config.c_sleeping = 900;
1253         }
1254         if (config.c_ctdluid == 0) {
1255                 pw = getpwnam("citadel");
1256                 if (pw != NULL) {
1257                         config.c_ctdluid = pw->pw_uid;
1258                 }
1259         }
1260         if (config.c_ctdluid == 0) {
1261                 pw = getpwnam("bbs");
1262                 if (pw != NULL) {
1263                         config.c_ctdluid = pw->pw_uid;
1264                 }
1265         }
1266         if (config.c_ctdluid == 0) {
1267                 pw = getpwnam("guest");
1268                 if (pw != NULL) {
1269                         config.c_ctdluid = pw->pw_uid;
1270                 }
1271         }
1272         if (config.c_createax == 0) {
1273                 config.c_createax = 3;
1274         }
1275         /*
1276          * Negative values for maxsessions are not allowed.
1277          */
1278         if (config.c_maxsessions < 0) {
1279                 config.c_maxsessions = 0;
1280         }
1281         /* We need a system default message expiry policy, because this is
1282          * the top level and there's no 'higher' policy to fall back on.
1283          * By default, do not expire messages at all.
1284          */
1285         if (config.c_ep.expire_mode == 0) {
1286                 config.c_ep.expire_mode = EXPIRE_MANUAL;
1287                 config.c_ep.expire_value = 0;
1288         }
1289
1290         /*
1291          * Default port numbers for various services
1292          */
1293         if (config.c_smtp_port == 0) config.c_smtp_port = 25;
1294         if (config.c_pop3_port == 0) config.c_pop3_port = 110;
1295         if (config.c_imap_port == 0) config.c_imap_port = 143;
1296         if (config.c_msa_port == 0) config.c_msa_port = 587;
1297         if (config.c_smtps_port == 0) config.c_smtps_port = 465;
1298         if (config.c_pop3s_port == 0) config.c_pop3s_port = 995;
1299         if (config.c_imaps_port == 0) config.c_imaps_port = 993;
1300         if (config.c_pftcpdict_port == 0) config.c_pftcpdict_port = -1;
1301         if (config.c_managesieve_port == 0) config.c_managesieve_port = 2020;
1302         if (config.c_xmpp_c2s_port == 0) config.c_xmpp_c2s_port = 5222;
1303         if (config.c_xmpp_s2s_port == 0) config.c_xmpp_s2s_port = 5269;
1304 }
1305
1306
1307 void get_config (void)
1308 {
1309         int a;
1310         int rv;
1311         FILE *fp;
1312
1313         /*
1314          * What we're going to try to do here is append a whole bunch of
1315          * nulls to the citadel.config file, so we can keep the old config
1316          * values if they exist, but if the file is missing or from an
1317          * earlier version with a shorter config structure, when setup tries
1318          * to read the old config parameters, they'll all come up zero.
1319          * The length of the config file will be set to what it's supposed
1320          * to be when we rewrite it, because we replace the old file with a
1321          * completely new copy.
1322          */
1323         if ((a = open(file_citadel_config, O_WRONLY | O_CREAT | O_APPEND,
1324                       S_IRUSR | S_IWUSR)) == -1) {
1325                 display_error("setup: cannot append citadel.config");
1326                 cleanup(errno);
1327         }
1328         fp = fdopen(a, "ab");
1329         if (fp == NULL) {
1330                 display_error("setup: cannot append citadel.config");
1331                 cleanup(errno);
1332         }
1333         for (a = 0; a < sizeof(struct config); ++a) {
1334                 putc(0, fp);
1335         }
1336         fclose(fp);
1337
1338         /* now we re-open it, and read the old or blank configuration */
1339         fp = fopen(file_citadel_config, "rb");
1340         if (fp == NULL) {
1341                 display_error("setup: cannot open citadel.config");
1342                 cleanup(errno);
1343         }
1344         rv = fread((char *) &config, sizeof(struct config), 1, fp);
1345         fclose(fp);
1346
1347 }
1348
1349 int main(int argc, char *argv[])
1350 {
1351         int a;
1352         int curr; 
1353         char aaa[128];
1354         int old_setup_level = 0;
1355         int info_only = 0;
1356         int relh=0;
1357         int home=0;
1358         char relhome[PATH_MAX]="";
1359         char ctdldir[PATH_MAX]=CTDLDIR;
1360         int rv;
1361         struct passwd *pw;
1362         gid_t gid;
1363         
1364         /* set an invalid setup type */
1365         setup_type = (-1);
1366
1367         /* Check to see if we're running the web installer */
1368         if (getenv("CITADEL_INSTALLER") != NULL) {
1369                 using_web_installer = 1;
1370         }
1371
1372         /* parse command line args */
1373         for (a = 0; a < argc; ++a) {
1374                 if (!strncmp(argv[a], "-u", 2)) {
1375                         strcpy(aaa, argv[a]);
1376                         strcpy(aaa, &aaa[2]);
1377                         setup_type = atoi(aaa);
1378                 }
1379                 else if (!strcmp(argv[a], "-i")) {
1380                         info_only = 1;
1381                 }
1382                 else if (!strcmp(argv[a], "-q")) {
1383                         setup_type = UI_SILENT;
1384                 }
1385                 else if (!strncmp(argv[a], "-h", 2)) {
1386                         relh=argv[a][2]!='/';
1387                         if (!relh) {
1388                                 safestrncpy(ctdl_home_directory, &argv[a][2], sizeof ctdl_home_directory);
1389                         } else {
1390                                 safestrncpy(relhome, &argv[a][2], sizeof relhome);
1391                         }
1392                         home = 1;
1393                 }
1394
1395         }
1396
1397         calc_dirs_n_files(relh, home, relhome, ctdldir, 0);
1398         SetTitles();
1399
1400         /* If a setup type was not specified, try to determine automatically
1401          * the best one to use out of all available types.
1402          */
1403         if (setup_type < 0) {
1404                 setup_type = discover_ui();
1405         }
1406         if (info_only == 1) {
1407                 important_message("Citadel Setup", CITADEL);
1408                 cleanup(0);
1409         }
1410
1411         enable_home = ( relh | home );
1412
1413         if (chdir(ctdl_run_dir) != 0) {
1414                 char errmsg[SIZ];
1415                 sprintf(errmsg, "The directory you specified does not exist: [%s]\n", ctdl_run_dir);
1416                 
1417                 important_message("Citadel Setup", errmsg);
1418                 cleanup(errno);
1419         }
1420
1421
1422         /* Try to stop Citadel if we can */
1423         if (!access("/etc/init.d/citadel", X_OK)) {
1424                 rv = system("/etc/init.d/citadel stop");
1425         }
1426
1427         /* Make sure Citadel is not running. */
1428         if (test_server(relhome, enable_home) == 0) {
1429                 important_message("Citadel Setup",
1430                         "The Citadel service is still running.\n"
1431                         "Please stop the service manually and run "
1432                         "setup again.");
1433                 cleanup(1);
1434         }
1435
1436         /* Now begin. */
1437         switch (setup_type) {
1438
1439         case UI_TEXT:
1440                 printf("\n\n\n"
1441                         "              *** Citadel setup program ***\n\n");
1442                 break;
1443
1444         }
1445
1446         get_config ();
1447
1448         set_default_values();
1449
1450         /* Go through a series of dialogs prompting for config info */
1451         for (curr = 1; curr <= MAXSETUP; ++curr) {
1452                 edit_value(curr);
1453                 if ((curr == 6) && (config.c_auth_mode != AUTHMODE_LDAP) && (config.c_auth_mode != AUTHMODE_LDAP_AD)) {
1454                         curr += 5;      /* skip LDAP questions if we're not authenticating against LDAP */
1455                 }
1456         }
1457
1458         /***** begin version update section *****/
1459
1460         old_setup_level = config.c_setup_level;
1461
1462         if (old_setup_level == 0) {
1463                 goto NEW_INST;
1464         }
1465
1466         if (old_setup_level < 555) {
1467                 important_message(
1468                         "Citadel Setup",
1469                         "This Citadel installation is too old to be upgraded."
1470                 );
1471                 cleanup(1);
1472         }
1473         write_config_to_disk();
1474
1475         old_setup_level = config.c_setup_level;
1476
1477         /***** end of version update section *****/
1478
1479 NEW_INST:
1480         config.c_setup_level = REV_LEVEL;
1481
1482         if ((pw = getpwuid(config.c_ctdluid)) == NULL) {
1483                 gid = getgid();
1484         } else {
1485                 gid = pw->pw_gid;
1486         }
1487
1488         create_run_directories(config.c_ctdluid, gid);
1489
1490         write_config_to_disk();
1491
1492         migrate_old_installs(); /* Delete files and directories used by older Citadel versions */
1493
1494         if (    ((setup_type == UI_SILENT)
1495                 && (getenv("ALTER_ETC_SERVICES")!=NULL))
1496                 || (setup_type != UI_SILENT)
1497         ) {
1498                 check_services_entry(); /* Check /etc/services */
1499         }
1500
1501 #ifndef __CYGWIN__
1502         delete_inittab_entry(); /* Remove obsolete /etc/inittab entry */
1503         check_xinetd_entry();   /* Check /etc/xinetd.d/telnet */
1504         disable_other_mtas();   /* Offer to disable other MTAs */
1505         fixnss();               /* Check for the 'db' nss and offer to disable it */
1506 #endif
1507
1508         progress("Setting file permissions", 1, 3);
1509         rv = chown(file_citadel_config, config.c_ctdluid, gid);
1510         progress("Setting file permissions", 2, 3);
1511         rv = chmod(file_citadel_config, S_IRUSR | S_IWUSR);
1512         progress("Setting file permissions", 3, 3);
1513
1514         check_init_script(relhome);
1515         cleanup(0);
1516         return 0;
1517 }
1518
1519