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