4 * Citadel setup utility
14 #include <sys/types.h>
16 #include <sys/utsname.h>
36 #define MAXSETUP 4 /* How many setup questions to ask */
38 #define UI_TEXT 0 /* Default setup type -- text only */
39 #define UI_DIALOG 2 /* Use the 'dialog' program */
40 #define UI_SILENT 3 /* Silent running, for use in scripts */
41 #define UI_NEWT 4 /* Use the "newt" window library */
43 #define SERVICE_NAME "citadel"
44 #define PROTO_NAME "tcp"
47 char setup_directory[SIZ];
48 char citserver_init_entry[SIZ];
49 int using_web_installer = 0;
53 void contemplate_ldap(void);
56 char *setup_titles[] =
58 "Citadel Home Directory",
59 "System Administrator",
68 char ctdl_home_directory[PATH_MAX] = "";
69 char ctdl_bio_dir[PATH_MAX]="bio";
70 char ctdl_bb_dir[PATH_MAX]="bitbucket";
71 char ctdl_data_dir[PATH_MAX]="data";
72 char ctdl_file_dir[PATH_MAX]="files";
73 char ctdl_hlp_dir[PATH_MAX]="help";
74 char ctdl_image_dir[PATH_MAX]="images";
75 char ctdl_info_dir[PATH_MAX]="info";
76 char ctdl_key_dir[PATH_MAX]="keys";
77 char ctdl_message_dir[PATH_MAX]="messages";
78 char ctdl_usrpic_dir[PATH_MAX]="userpics";
79 char ctdl_etc_dir[PATH_MAX]="";
80 char ctdl_run_dir[PATH_MAX]="";
81 char ctdl_spool_dir[PATH_MAX]="network";
82 char ctdl_netout_dir[PATH_MAX]="network/spoolout";
83 char ctdl_netin_dir[PATH_MAX]="network/spoolin";
86 char citadel_rc_file[PATH_MAX]="";
88 /* calculate all our path on a central place */
89 /* where to keep our config */
91 #define COMPUTE_DIRECTORY(SUBDIR) memcpy(dirbuffer,SUBDIR, sizeof dirbuffer);\
92 snprintf(SUBDIR,sizeof SUBDIR, "%s%s%s%s%s%s%s", \
93 (home&!relh)?ctdl_home_directory:basedir, \
94 ((basedir!=ctdldir)&(home&!relh))?basedir:"/", \
95 ((basedir!=ctdldir)&(home&!relh))?"/":"", \
97 (relhome[0]!='\0')?"/":"",\
99 (dirbuffer[0]!='\0')?"/":"");
102 char *setup_text[] = {
104 "Enter the full pathname of the directory in which the Citadel\n"
105 "installation you are creating or updating resides. If you\n"
106 "specify a directory other than the default, you will need to\n"
107 "specify the -h flag to the server when you start it up.\n",
109 "Enter the subdirectoryname for an alternating installation of "
110 "Citadel. To do a default installation just leave it blank."
111 "If you specify a directory other than the default, you will need to\n"
112 "specify the -h flag to the server when you start it up.\n"
113 "note that it may not have a leading /",
116 "Enter the name of the system administrator (which is probably\n"
117 "you). When an account is created with this name, it will\n"
118 "automatically be given administrator-level access.\n",
120 "Citadel needs to run under its own user ID. This would\n"
121 "typically be called \"citadel\", but if you are running Citadel\n"
122 "as a public BBS, you might also call it \"bbs\" or \"guest\".\n"
123 "The server will run under this user ID. Please specify that\n"
124 "user ID here. You may specify either a user name or a numeric\n"
127 "Specify the IP address on which your server will run. If you\n"
128 "leave this blank, or if you specify 0.0.0.0, Citadel will listen\n"
129 "on all addresses. You can usually skip this unless you are\n"
130 "running multiple instances of Citadel on the same computer.\n",
132 "Specify the TCP port number on which your server will run.\n"
133 "Normally, this will be port 504, which is the official port\n"
134 "assigned by the IANA for Citadel servers. You will only need\n"
135 "to specify a different port number if you run multiple instances\n"
136 "of Citadel on the same computer and there is something else\n"
137 "already using port 504.\n",
141 struct config config;
145 * Set an entry in inittab to the desired state
147 void set_init_entry(char *which_entry, char *new_state) {
148 char *inittab = NULL;
156 if (which_entry == NULL) return;
157 if (strlen(which_entry) == 0) return;
159 inittab = strdup("");
160 if (inittab == NULL) return;
162 fp = fopen("/etc/inittab", "r");
163 if (fp == NULL) return;
165 while(fgets(buf, sizeof buf, fp) != NULL) {
167 if (num_tokens(buf, ':') == 4) {
168 extract_token(entry, buf, 0, ':', sizeof entry);
169 extract_token(levels, buf, 1, ':', sizeof levels);
170 extract_token(state, buf, 2, ':', sizeof state);
171 extract_token(prog, buf, 3, ':', sizeof prog); /* includes 0x0a LF */
173 if (!strcmp(entry, which_entry)) {
174 strcpy(state, new_state);
175 sprintf(buf, "%s:%s:%s:%s",
176 entry, levels, state, prog);
180 inittab = realloc(inittab, strlen(inittab) + strlen(buf) + 2);
181 if (inittab == NULL) {
186 strcat(inittab, buf);
189 fp = fopen("/etc/inittab", "w");
191 fwrite(inittab, strlen(inittab), 1, fp);
193 kill(1, SIGHUP); /* Tell init to re-read /etc/inittab */
200 * Locate the name of an inittab entry for a specific program
202 void locate_init_entry(char *init_entry, char *looking_for) {
210 strcpy(init_entry, "");
212 /* Pound through /etc/inittab line by line. Set have_entry to 1 if
213 * an entry is found which we believe starts the specified program.
215 infp = fopen("/etc/inittab", "r");
219 while (fgets(buf, sizeof buf, infp) != NULL) {
220 buf[strlen(buf) - 1] = 0;
221 extract_token(entry, buf, 0, ':', sizeof entry);
222 extract_token(prog, buf, 3, ':', sizeof prog);
223 if (!strncasecmp(prog, looking_for,
224 strlen(looking_for))) {
226 strcpy(init_entry, entry);
236 * Shut down the Citadel service if necessary, during setup.
238 void shutdown_citserver(void) {
239 char looking_for[SIZ];
241 snprintf(looking_for,
250 locate_init_entry(citserver_init_entry, looking_for);
251 if (strlen(citserver_init_entry) > 0) {
252 set_init_entry(citserver_init_entry, "off");
258 * Start the Citadel service.
260 void start_citserver(void) {
261 if (strlen(citserver_init_entry) > 0) {
262 set_init_entry(citserver_init_entry, "respawn");
268 void cleanup(int exitcode)
280 void title(char *text)
282 if (setup_type == UI_TEXT) {
283 printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<%s>\n", text);
289 int yesno(char *question)
292 newtComponent form = NULL;
293 newtComponent yesbutton = NULL;
294 newtComponent nobutton = NULL;
295 int prompt_window_height = 0;
301 switch (setup_type) {
305 printf("%s\nYes/No --> ", question);
306 fgets(buf, sizeof buf, stdin);
307 answer = tolower(buf[0]);
310 else if (answer == 'n')
312 } while ((answer < 0) || (answer > 1));
316 sprintf(buf, "exec %s --yesno '%s' 10 72",
317 getenv("CTDL_DIALOG"),
330 prompt_window_height = num_tokens(question, '\n') + 5;
331 newtCenteredWindow(76, prompt_window_height, "Question");
332 form = newtForm(NULL, NULL, 0);
333 for (i=0; i<num_tokens(question, '\n'); ++i) {
334 extract_token(buf, question, i, '\n', sizeof buf);
335 newtFormAddComponent(form, newtLabel(1, 1+i, buf));
337 yesbutton = newtButton(10, (prompt_window_height - 4), "Yes");
338 nobutton = newtButton(60, (prompt_window_height - 4), "No");
339 newtFormAddComponent(form, yesbutton);
340 newtFormAddComponent(form, nobutton);
341 if (newtRunForm(form) == yesbutton) {
348 newtFormDestroy(form);
358 void important_message(char *title, char *msgtext)
361 newtComponent form = NULL;
366 switch (setup_type) {
369 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");
370 printf(" %s \n\n%s\n\n", title, msgtext);
371 printf("Press return to continue...");
372 fgets(buf, sizeof buf, stdin);
376 sprintf(buf, "exec %s --msgbox '%s' 19 72",
377 getenv("CTDL_DIALOG"),
384 newtCenteredWindow(76, 10, title);
385 form = newtForm(NULL, NULL, 0);
386 for (i=0; i<num_tokens(msgtext, '\n'); ++i) {
387 extract_token(buf, msgtext, i, '\n', sizeof buf);
388 newtFormAddComponent(form, newtLabel(1, 1+i, buf));
390 newtFormAddComponent(form, newtButton(35, 5, "OK"));
393 newtFormDestroy(form);
400 void important_msgnum(int msgnum)
402 important_message("Important Message", setup_text[msgnum]);
405 void display_error(char *error_message)
407 important_message("Error", error_message);
410 void progress(char *text, long int curr, long int cmax)
414 /* These variables are static because progress() gets called
415 * multiple times during the course of whatever operation is
416 * being performed. This makes setup non-threadsafe, but who
419 static newtComponent form = NULL;
420 static newtComponent scale = NULL;
422 static long dots_printed = 0L;
424 static FILE *fp = NULL;
427 switch (setup_type) {
431 printf("%s\n", text);
432 printf("..........................");
433 printf("..........................");
434 printf("..........................\r");
437 } else if (curr == cmax) {
438 printf("\r%79s\n", "");
440 a = (curr * 100) / cmax;
443 while (dots_printed < a) {
453 sprintf(buf, "exec %s --gauge '%s' 7 72 0",
454 getenv("CTDL_DIALOG"),
456 fp = popen(buf, "w");
462 else if (curr == cmax) {
464 fprintf(fp, "100\n");
470 a = (curr * 100) / cmax;
472 fprintf(fp, "%ld\n", a);
481 newtCenteredWindow(76, 8, text);
482 form = newtForm(NULL, NULL, 0);
483 scale = newtScale(1, 3, 74, cmax);
484 newtFormAddComponent(form, scale);
488 if ((curr > 0) && (curr <= cmax)) {
489 newtScaleSet(scale, curr);
493 newtFormDestroy(form);
506 * check_services_entry() -- Make sure "citadel" is in /etc/services
509 void check_services_entry(void)
514 if (getservbyname(SERVICE_NAME, PROTO_NAME) == NULL) {
515 for (i=0; i<=3; ++i) {
516 progress("Adding service entry...", i, 3);
518 sfp = fopen("/etc/services", "a");
520 display_error(strerror(errno));
522 fprintf(sfp, "%s 504/tcp\n",
534 * Generate a unique entry name for a new inittab entry
536 void generate_entry_name(char *entryname) {
539 snprintf(entryname, sizeof entryname, "c0");
542 if (entryname[1] > '9') {
545 if (entryname[0] > 'z') {
547 "Can't generate a unique entry name");
551 snprintf(buf, sizeof buf,
552 "grep %s: /etc/inittab >/dev/null 2>&1", entryname);
553 } while (system(buf) == 0);
559 * check_inittab_entry() -- Make sure "citadel" is in /etc/inittab
562 void check_inittab_entry(void)
565 char looking_for[SIZ];
569 /* Determine the fully qualified path name of citserver */
570 snprintf(looking_for,
579 locate_init_entry(citserver_init_entry, looking_for);
581 /* If there's already an entry, then we have nothing left to do. */
582 if (strlen(citserver_init_entry) > 0) {
586 /* Otherwise, prompt the user to create an entry. */
587 if (getenv("CREATE_INITTAB_ENTRY") != NULL) {
588 if (strcasecmp(getenv("CREATE_INITTAB_ENTRY"), "yes")) {
593 snprintf(question, sizeof question,
594 "Do you want this computer configured to start the Citadel\n"
595 "service automatically? (If you answer yes, an entry in\n"
596 "/etc/inittab pointing to %s will be added.)\n",
598 if (yesno(question) == 0) {
603 /* Generate a unique entry name for /etc/inittab */
604 generate_entry_name(entryname);
606 /* Now write it out to /etc/inittab */
607 infp = fopen("/etc/inittab", "a");
609 display_error(strerror(errno));
611 fprintf(infp, "# Start the Citadel server...\n");
612 fprintf(infp, "%s:2345:respawn:%s %s%s -x3 -llocal4\n",
615 (enable_home)?"-h":"",
616 (enable_home)?setup_directory:"");
618 strcpy(citserver_init_entry, entryname);
624 * On systems which use xinetd, see if we can offer to install Citadel as
625 * the default telnet target.
627 void check_xinetd_entry(void) {
628 char *filename = "/etc/xinetd.d/telnet";
631 int already_citadel = 0;
633 fp = fopen(filename, "r+");
634 if (fp == NULL) return; /* Not there. Oh well... */
636 while (fgets(buf, sizeof buf, fp) != NULL) {
637 if (strstr(buf, setup_directory) != NULL) already_citadel = 1;
640 if (already_citadel) return; /* Already set up this way. */
642 /* Otherwise, prompt the user to create an entry. */
643 if (getenv("CREATE_XINETD_ENTRY") != NULL) {
644 if (strcasecmp(getenv("CREATE_XINETD_ENTRY"), "yes")) {
649 snprintf(buf, sizeof buf,
650 "Setup can configure the \"xinetd\" service to automatically\n"
651 "connect incoming telnet sessions to Citadel, bypassing the\n"
652 "host system login: prompt. Would you like to do this?\n"
654 if (yesno(buf) == 0) {
659 fp = fopen(filename, "w");
661 "# description: telnet service for Citadel users\n"
666 " socket_type = stream\n"
669 " server = /usr/sbin/in.telnetd\n"
670 " server_args = -h -L %s/citadel\n"
671 " log_on_failure += USERID\n"
681 /* Now try to restart the service */
682 system("/etc/init.d/xinetd restart >/dev/null 2>&1");
688 * Offer to disable other MTA's
690 void disable_other_mta(char *mta) {
695 sprintf(buf, "/bin/ls -l /etc/rc*.d/S*%s 2>/dev/null; "
696 "/bin/ls -l /etc/rc.d/rc*.d/S*%s 2>/dev/null",
698 fp = popen(buf, "r");
699 if (fp == NULL) return;
701 while (fgets(buf, sizeof buf, fp) != NULL) {
705 if (lines == 0) return; /* Nothing to do. */
708 /* Offer to replace other MTA with the vastly superior Citadel :) */
710 if (getenv("ACT_AS_MTA")) {
711 if (strcasecmp(getenv("ACT_AS_MTA"), "yes")) {
716 snprintf(buf, sizeof buf,
717 "You appear to have the \"%s\" email program\n"
718 "running on your system. If you want Citadel mail\n"
719 "connected with %s, you will have to manually integrate\n"
720 "them. It is preferable to disable %s, and use Citadel's\n"
721 "SMTP, POP3, and IMAP services.\n\n"
722 "May we disable %s so that Citadel has access to ports\n"
723 "25, 110, and 143?\n",
726 if (yesno(buf) == 0) {
731 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);
733 sprintf(buf, "/etc/init.d/%s stop >/dev/null 2>&1", mta);
741 * Check to see if our server really works. Returns 0 on success.
743 int test_server(void) {
750 /* Generate a silly little cookie. We're going to write it out
751 * to the server and try to get it back. The cookie does not
752 * have to be secret ... just unique.
754 sprintf(cookie, "--test--%d--", getpid());
756 sprintf(cmd, "%s/sendcommand %s%s ECHO %s 2>&1",
762 (enable_home)?"-h":"",
763 (enable_home)?setup_directory:"",
766 fp = popen(cmd, "r");
767 if (fp == NULL) return(errno);
769 while (fgets(buf, sizeof buf, fp) != NULL) {
771 && (strstr(buf, cookie) != NULL) ) {
783 void strprompt(char *prompt_title, char *prompt_text, char *str)
789 int prompt_window_height = 0;
793 char dialog_result[PATH_MAX];
796 strcpy(setupmsg, "");
798 switch (setup_type) {
801 printf("\n%s\n", prompt_text);
802 printf("This is currently set to:\n%s\n", str);
803 printf("Enter new value or press return to leave unchanged:\n");
804 fgets(buf, sizeof buf, stdin);
805 buf[strlen(buf) - 1] = 0;
806 if (strlen(buf) != 0)
811 CtdlMakeTempFileName(dialog_result, sizeof dialog_result);
812 sprintf(buf, "exec %s --inputbox '%s' 19 72 '%s' 2>%s",
813 getenv("CTDL_DIALOG"),
818 fp = fopen(dialog_result, "r");
820 fgets(str, sizeof buf, fp);
821 if (str[strlen(str)-1] == 10) {
822 str[strlen(str)-1] = 0;
825 unlink(dialog_result);
832 prompt_window_height = num_tokens(prompt_text, '\n') + 5 ;
833 newtCenteredWindow(76,
834 prompt_window_height,
836 form = newtForm(NULL, NULL, 0);
837 for (i=0; i<num_tokens(prompt_text, '\n'); ++i) {
838 extract_token(buf, prompt_text, i, '\n', sizeof buf);
839 newtFormAddComponent(form, newtLabel(1, 1+i, buf));
841 newtFormAddComponent(form,
843 (prompt_window_height - 2),
846 (const char **) &result,
847 NEWT_FLAG_RETURNEXIT)
853 newtFormDestroy(form);
859 void set_str_val(int msgpos, char *str) {
860 strprompt(setup_titles[msgpos], setup_text[msgpos], str);
865 void set_int_val(int msgpos, int *ip)
868 snprintf(buf, sizeof buf, "%d", (int) *ip);
869 set_str_val(msgpos, buf);
874 void set_char_val(int msgpos, char *ip)
877 snprintf(buf, sizeof buf, "%d", (int) *ip);
878 set_str_val(msgpos, buf);
879 *ip = (char) atoi(buf);
883 void set_long_val(int msgpos, long int *ip)
886 snprintf(buf, sizeof buf, "%ld", *ip);
887 set_str_val(msgpos, buf);
892 void edit_value(int curr)
896 char ctdluidname[SIZ];
901 if (getenv("SYSADMIN_NAME")) {
902 strcpy(config.c_sysadm, getenv("SYSADMIN_NAME"));
905 set_str_val(curr, config.c_sysadm);
911 config.c_ctdluid = 0; /* XXX Windows hack, prob. insecure */
913 i = config.c_ctdluid;
916 set_int_val(curr, &i);
917 config.c_ctdluid = i;
920 strcpy(ctdluidname, pw->pw_name);
921 set_str_val(curr, ctdluidname);
922 pw = getpwnam(ctdluidname);
924 config.c_ctdluid = pw->pw_uid;
926 else if (atoi(ctdluidname) > 0) {
927 config.c_ctdluid = atoi(ctdluidname);
934 set_str_val(curr, config.c_ip_addr);
938 set_int_val(curr, &config.c_port_number);
946 * (re-)write the config data to disk
948 void write_config_to_disk(void)
959 "/citadel.config", S_IRUSR | S_IWUSR)) == -1) {
960 display_error("setup: cannot open citadel.config");
963 fp = fdopen(fd, "wb");
965 display_error("setup: cannot open citadel.config");
968 fwrite((char *) &config, sizeof(struct config), 1, fp);
976 * Figure out what type of user interface we're going to use
978 int discover_ui(void)
981 /* Use "dialog" if we have it */
982 if (getenv("CTDL_DIALOG") != NULL) {
990 newtDrawRootText(0, 0, "Citadel Setup");
1000 int main(int argc, char *argv[])
1006 int old_setup_level = 0;
1008 struct utsname my_utsname;
1014 const char* basedir;
1015 char dirbuffer[PATH_MAX]="";
1016 char relhome[PATH_MAX]="";
1017 char ctdldir[PATH_MAX]=CTDLDIR;
1019 /* set an invalid setup type */
1022 /* Check to see if we're running the web installer */
1023 if (getenv("CITADEL_INSTALLER") != NULL) {
1024 using_web_installer = 1;
1027 /* parse command line args */
1028 for (a = 0; a < argc; ++a) {
1029 if (!strncmp(argv[a], "-u", 2)) {
1030 strcpy(aaa, argv[a]);
1031 strcpy(aaa, &aaa[2]);
1032 setup_type = atoi(aaa);
1034 if (!strcmp(argv[a], "-i")) {
1037 if (!strcmp(argv[a], "-q")) {
1038 setup_type = UI_SILENT;
1043 /* If a setup type was not specified, try to determine automatically
1044 * the best one to use out of all available types.
1046 if (setup_type < 0) {
1047 setup_type = discover_ui();
1049 if (info_only == 1) {
1050 important_message("Citadel Setup", CITADEL);
1054 /* Get started in a valid setup directory. */
1055 strcpy(setup_directory,
1062 if ( (using_web_installer) && (getenv("CITADEL") != NULL) ) {
1063 strcpy(setup_directory, getenv("CITADEL"));
1066 set_str_val(0, setup_directory);
1069 home=(setup_directory[1]!='\0');
1070 relh=home&(setup_directory[1]!='/');
1071 if (!relh) safestrncpy(ctdl_home_directory, setup_directory,
1072 sizeof ctdl_home_directory);
1074 safestrncpy(relhome, ctdl_home_directory,
1077 #ifndef HAVE_ETC_DIR
1082 COMPUTE_DIRECTORY(ctdl_etc_dir);
1084 #ifndef HAVE_RUN_DIR
1089 COMPUTE_DIRECTORY(ctdl_run_dir);
1091 #ifndef HAVE_DATA_DIR
1096 COMPUTE_DIRECTORY(ctdl_bio_dir);
1097 COMPUTE_DIRECTORY(ctdl_bb_dir);
1098 COMPUTE_DIRECTORY(ctdl_data_dir);
1099 COMPUTE_DIRECTORY(ctdl_file_dir);
1100 COMPUTE_DIRECTORY(ctdl_hlp_dir);
1101 COMPUTE_DIRECTORY(ctdl_image_dir);
1102 COMPUTE_DIRECTORY(ctdl_info_dir);
1103 COMPUTE_DIRECTORY(ctdl_message_dir);
1104 COMPUTE_DIRECTORY(ctdl_usrpic_dir);
1105 #ifndef HAVE_SPOOL_DIR
1110 COMPUTE_DIRECTORY(ctdl_spool_dir);
1111 COMPUTE_DIRECTORY(ctdl_netout_dir);
1112 COMPUTE_DIRECTORY(ctdl_netin_dir);
1115 if ((home) && (chdir(setup_directory) != 0)) {
1116 important_message("Citadel Setup",
1117 "The directory you specified does not exist.");
1121 /* Determine our host name, in case we need to use it as a default */
1124 /* See if we need to shut down the Citadel service. */
1125 for (a=0; a<=3; ++a) {
1126 progress("Shutting down the Citadel service...", a, 3);
1127 if (a == 0) shutdown_citserver();
1131 /* Make sure it's stopped. */
1132 if (test_server() == 0) {
1133 important_message("Citadel Setup",
1134 "The Citadel service is still running.\n"
1135 "Please stop the service manually and run "
1141 switch (setup_type) {
1145 " *** Citadel setup program ***\n\n");
1151 * What we're going to try to do here is append a whole bunch of
1152 * nulls to the citadel.config file, so we can keep the old config
1153 * values if they exist, but if the file is missing or from an
1154 * earlier version with a shorter config structure, when setup tries
1155 * to read the old config parameters, they'll all come up zero.
1156 * The length of the config file will be set to what it's supposed
1157 * to be when we rewrite it, because we replace the old file with a
1158 * completely new copy.
1160 snprintf(citadel_rc_file,
1161 sizeof citadel_rc_file,
1162 "%s/citadel.config",
1165 if ((a = open(citadel_rc_file, O_WRONLY | O_CREAT | O_APPEND,
1166 S_IRUSR | S_IWUSR)) == -1) {
1167 display_error("setup: cannot append citadel.config");
1170 fp = fdopen(a, "ab");
1172 display_error("setup: cannot append citadel.config");
1175 for (a = 0; a < sizeof(struct config); ++a)
1179 /* now we re-open it, and read the old or blank configuration */
1180 fp = fopen(citadel_rc_file, "rb");
1182 display_error("setup: cannot open citadel.config");
1185 fread((char *) &config, sizeof(struct config), 1, fp);
1188 /* set some sample/default values in place of blanks... */
1189 if (strlen(config.c_nodename) == 0)
1190 safestrncpy(config.c_nodename, my_utsname.nodename,
1191 sizeof config.c_nodename);
1192 strtok(config.c_nodename, ".");
1193 if (strlen(config.c_fqdn) == 0) {
1194 if ((he = gethostbyname(my_utsname.nodename)) != NULL)
1195 safestrncpy(config.c_fqdn, he->h_name,
1196 sizeof config.c_fqdn);
1198 safestrncpy(config.c_fqdn, my_utsname.nodename,
1199 sizeof config.c_fqdn);
1201 if (strlen(config.c_humannode) == 0)
1202 strcpy(config.c_humannode, "My System");
1203 if (strlen(config.c_phonenum) == 0)
1204 strcpy(config.c_phonenum, "US 800 555 1212");
1205 if (config.c_initax == 0) {
1206 config.c_initax = 4;
1208 if (strlen(config.c_moreprompt) == 0)
1209 strcpy(config.c_moreprompt, "<more>");
1210 if (strlen(config.c_twitroom) == 0)
1211 strcpy(config.c_twitroom, "Trashcan");
1212 if (strlen(config.c_baseroom) == 0)
1213 strcpy(config.c_baseroom, BASEROOM);
1214 if (strlen(config.c_aideroom) == 0)
1215 strcpy(config.c_aideroom, "Aide");
1216 if (config.c_port_number == 0) {
1217 config.c_port_number = 504;
1219 if (config.c_sleeping == 0) {
1220 config.c_sleeping = 900;
1222 if (config.c_ctdluid == 0) {
1223 pw = getpwnam("citadel");
1225 config.c_ctdluid = pw->pw_uid;
1227 if (config.c_ctdluid == 0) {
1228 pw = getpwnam("bbs");
1230 config.c_ctdluid = pw->pw_uid;
1232 if (config.c_ctdluid == 0) {
1233 pw = getpwnam("guest");
1235 config.c_ctdluid = pw->pw_uid;
1237 if (config.c_createax == 0) {
1238 config.c_createax = 3;
1241 * Negative values for maxsessions are not allowed.
1243 if (config.c_maxsessions < 0) {
1244 config.c_maxsessions = 0;
1246 /* We need a system default message expiry policy, because this is
1247 * the top level and there's no 'higher' policy to fall back on.
1248 * By default, do not expire messages at all.
1250 if (config.c_ep.expire_mode == 0) {
1251 config.c_ep.expire_mode = EXPIRE_MANUAL;
1252 config.c_ep.expire_value = 0;
1256 * Default port numbers for various services
1258 if (config.c_smtp_port == 0) config.c_smtp_port = 25;
1259 if (config.c_pop3_port == 0) config.c_pop3_port = 110;
1260 if (config.c_imap_port == 0) config.c_imap_port = 143;
1261 if (config.c_msa_port == 0) config.c_msa_port = 587;
1262 if (config.c_smtps_port == 0) config.c_smtps_port = 465;
1263 if (config.c_pop3s_port == 0) config.c_pop3s_port = 995;
1264 if (config.c_imaps_port == 0) config.c_imaps_port = 993;
1266 /* Go through a series of dialogs prompting for config info */
1267 if (setup_type != UI_SILENT) {
1268 for (curr = 1; curr <= MAXSETUP; ++curr) {
1273 /***** begin version update section ***** */
1274 /* take care of any updating that is necessary */
1276 old_setup_level = config.c_setup_level;
1278 if (old_setup_level == 0) {
1282 if (old_setup_level < 555) {
1283 important_message("Citadel Setup",
1284 "This Citadel installation is too old "
1288 write_config_to_disk();
1290 old_setup_level = config.c_setup_level;
1292 /* end of version update section */
1295 config.c_setup_level = REV_LEVEL;
1297 /******************************************/
1299 write_config_to_disk();
1301 mkdir(ctdl_info_dir, 0700);
1302 chmod(ctdl_info_dir, 0700);
1303 mkdir(ctdl_bio_dir, 0700);
1304 chmod(ctdl_bio_dir, 0700);
1305 mkdir(ctdl_usrpic_dir, 0700);
1306 chmod(ctdl_usrpic_dir, 0700);
1307 mkdir(ctdl_message_dir, 0700);
1308 chmod(ctdl_message_dir, 0700);
1309 mkdir(ctdl_hlp_dir, 0700);
1310 chmod(ctdl_hlp_dir, 0700);
1311 mkdir(ctdl_image_dir, 0700);
1312 chmod(ctdl_image_dir, 0700);
1313 /* TODO: where to put this? */
1314 mkdir("netconfigs", 0700);
1315 chmod("netconfigs", 0700);
1317 /* Delete files and directories used by older Citadel versions */
1318 system("exec /bin/rm -fr ./rooms ./chatpipes ./expressmsgs ./sessions 2>/dev/null");
1319 unlink("citadel.log");
1322 check_services_entry(); /* Check /etc/services */
1324 check_inittab_entry(); /* Check /etc/inittab */
1325 check_xinetd_entry(); /* Check /etc/xinetd.d/telnet */
1327 /* Offer to disable other MTA's on the system. */
1328 disable_other_mta("courier-authdaemon");
1329 disable_other_mta("courier-imap");
1330 disable_other_mta("courier-imap-ssl");
1331 disable_other_mta("courier-pop");
1332 disable_other_mta("courier-pop3");
1333 disable_other_mta("courier-pop3d");
1334 disable_other_mta("cyrmaster");
1335 disable_other_mta("cyrus");
1336 disable_other_mta("dovecot");
1337 disable_other_mta("exim");
1338 disable_other_mta("exim4");
1339 disable_other_mta("hula");
1340 disable_other_mta("imapd");
1341 disable_other_mta("mta");
1342 disable_other_mta("pop3d");
1343 disable_other_mta("popd");
1344 disable_other_mta("postfix");
1345 disable_other_mta("qmail");
1346 disable_other_mta("saslauthd");
1347 disable_other_mta("sendmail");
1348 disable_other_mta("vmailmgrd");
1349 disable_other_mta("zimbra");
1352 if ((pw = getpwuid(config.c_ctdluid)) == NULL)
1357 progress("Setting file permissions", 0, 4);
1358 chown(".", config.c_ctdluid, gid);
1360 progress("Setting file permissions", 1, 4);
1361 chown(citadel_rc_file, config.c_ctdluid, gid);
1363 progress("Setting file permissions", 2, 4);
1364 snprintf(aaa, sizeof aaa,
1365 "find . | grep -v chkpwd | xargs chown %ld:%ld 2>/dev/null",
1366 (long)config.c_ctdluid, (long)gid);
1369 progress("Setting file permissions", 3, 4);
1370 chmod(citadel_rc_file, S_IRUSR | S_IWUSR);
1372 progress("Setting file permissions", 4, 4);
1375 /* Contemplate the possibility of auto-configuring OpenLDAP */
1379 /* See if we can start the Citadel service. */
1380 if (strlen(citserver_init_entry) > 0) {
1381 for (a=0; a<=3; ++a) {
1382 progress("Starting the Citadel service...", a, 3);
1383 if (a == 0) start_citserver();
1386 if (test_server() == 0) {
1387 important_message("Setup finished",
1388 "Setup of the Citadel server is complete.\n"
1389 "If you will be using WebCit, please run its\n"
1390 "setup program now; otherwise, run './citadel'\n"
1394 important_message("Setup finished",
1395 "Setup is finished, but the Citadel service "
1396 "failed to start.\n"
1397 "Go back and check your configuration.");
1401 important_message("Setup finished",
1402 "Setup is finished. You may now start the server.");
1412 * If we're in the middle of an Easy Install, we might just be able to
1413 * auto-configure a standalone OpenLDAP server.
1415 void contemplate_ldap(void) {
1417 char slapd_init_entry[SIZ];
1420 /* If conditions are not ideal, give up on this idea... */
1421 if (using_web_installer == 0) return;
1422 if (getenv("LDAP_CONFIG") == NULL) return;
1423 if (getenv("SUPPORT") == NULL) return;
1424 if (getenv("SLAPD_BINARY") == NULL) return;
1425 if (getenv("CITADEL") == NULL) return;
1427 /* And if inittab is already starting slapd, bail out... */
1428 locate_init_entry(slapd_init_entry, getenv("SLAPD_BINARY"));
1429 if (strlen(slapd_init_entry) > 0) {
1430 important_message("Citadel Setup",
1431 "You appear to already have a standalone LDAP "
1432 "service\nconfigured for use with Citadel. No "
1433 "changes will be made.\n");
1434 /* set_init_entry(slapd_init_entry, "off"); */
1438 /* Generate a unique entry name for slapd if we don't have one. */
1440 generate_entry_name(slapd_init_entry);
1443 /* Ask the user if it's ok to set up slapd automatically. */
1444 snprintf(question, sizeof question,
1446 "Do you want this computer configured to start a standalone\n"
1447 "LDAP service automatically? (If you answer yes, a new\n"
1448 "slapd.conf will be written, and an /etc/inittab entry\n"
1449 "pointing to %s will be added.)\n"
1451 getenv("SLAPD_BINARY")
1453 if (yesno(question) == 0)
1456 strcpy(config.c_ldap_base_dn, "dc=example,dc=com");
1457 strprompt("Base DN",
1459 "Please enter the Base DN for your directory. This will\n"
1460 "generally be something based on the primary DNS domain in\n"
1461 "which you receive mail, but it does not have to be. Your\n"
1462 "LDAP tree will be built using this Distinguished Name.\n"
1464 config.c_ldap_base_dn
1467 strcpy(config.c_ldap_host, "localhost");
1468 config.c_ldap_port = 389;
1469 sprintf(config.c_ldap_bind_dn, "cn=manager,%s", config.c_ldap_base_dn);
1472 * Generate a bind password. If you're some grey hat hacker who
1473 * is just dying to get some street cred on Bugtraq, and you think
1474 * this password generation scheme is too weak, please submit a patch
1475 * instead of just whining about it, ok?
1477 sprintf(config.c_ldap_bind_pw, "%d%ld", getpid(), (long)time(NULL));
1479 write_config_to_disk();
1481 fp = fopen(getenv("LDAP_CONFIG"), "w");
1483 sprintf(question, "\nCannot create %s:\n%s\n\n"
1484 "Citadel will still function, but you will "
1485 "not have an LDAP service.\n\n",
1486 getenv("LDAP_CONFIG"),
1489 important_message("Error", question);
1493 fprintf(fp, "include %s/citadel-openldap.schema\n",
1495 fprintf(fp, "pidfile %s/openldap-data/slapd.pid\n",
1497 fprintf(fp, "argsfile %s/openldap-data/slapd.args\n",
1499 fprintf(fp, "allow bind_v2\n"
1503 fprintf(fp, "suffix \"%s\"\n", config.c_ldap_base_dn);
1504 fprintf(fp, "rootdn \"%s\"\n", config.c_ldap_bind_dn);
1505 fprintf(fp, "rootpw %s\n", config.c_ldap_bind_pw);
1506 fprintf(fp, "directory %s/openldap-data\n",
1508 fprintf(fp, "index objectClass eq\n");
1512 /* This is where our OpenLDAP server will keep its data. */
1513 mkdir("openldap-data", 0700);
1515 /* Now write it out to /etc/inittab.
1516 * FIXME make it run as some non-root user.
1517 * The "-d 0" seems superfluous, but it's actually a way to make
1518 * slapd run in the foreground without spewing messages to the console.
1520 fp = fopen("/etc/inittab", "a");
1522 display_error(strerror(errno));
1524 fprintf(fp, "# Start the OpenLDAP server for Citadel...\n");
1525 fprintf(fp, "%s:2345:respawn:%s -d 0 -f %s\n",
1527 getenv("SLAPD_BINARY"),
1528 getenv("LDAP_CONFIG")
1534 #endif /* HAVE_LDAP */