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