4 * Citadel setup utility
14 #include <sys/types.h>
16 #include <sys/utsname.h>
30 #include "citadel_dirs.h"
37 #define MAXSETUP 4 /* How many setup questions to ask */
39 #define UI_TEXT 0 /* Default setup type -- text only */
40 #define UI_DIALOG 2 /* Use the 'dialog' program */
41 #define UI_SILENT 3 /* Silent running, for use in scripts */
42 #define UI_NEWT 4 /* Use the "newt" window library */
44 #define SERVICE_NAME "citadel"
45 #define PROTO_NAME "tcp"
48 char setup_directory[SIZ];
49 char citserver_init_entry[SIZ];
50 int using_web_installer = 0;
54 void contemplate_ldap(void);
57 char *setup_titles[] =
59 "Citadel Home Directory",
60 "System Administrator",
69 /* calculate all our path on a central place */
70 /* where to keep our config */
73 char *setup_text[] = {
75 "Enter the full pathname of the directory in which the Citadel\n"
76 "installation you are creating or updating resides. If you\n"
77 "specify a directory other than the default, you will need to\n"
78 "specify the -h flag to the server when you start it up.\n",
80 "Enter the subdirectoryname for an alternating installation of "
81 "Citadel. To do a default installation just leave it blank."
82 "If you specify a directory other than the default, you will need to\n"
83 "specify the -h flag to the server when you start it up.\n"
84 "note that it may not have a leading /",
87 "Enter the name of the system administrator (which is probably\n"
88 "you). When an account is created with this name, it will\n"
89 "automatically be given administrator-level access.\n",
91 "Citadel needs to run under its own user ID. This would\n"
92 "typically be called \"citadel\", but if you are running Citadel\n"
93 "as a public BBS, you might also call it \"bbs\" or \"guest\".\n"
94 "The server will run under this user ID. Please specify that\n"
95 "user ID here. You may specify either a user name or a numeric\n"
98 "Specify the IP address on which your server will run. If you\n"
99 "leave this blank, or if you specify 0.0.0.0, Citadel will listen\n"
100 "on all addresses. You can usually skip this unless you are\n"
101 "running multiple instances of Citadel on the same computer.\n",
103 "Specify the TCP port number on which your server will run.\n"
104 "Normally, this will be port 504, which is the official port\n"
105 "assigned by the IANA for Citadel servers. You will only need\n"
106 "to specify a different port number if you run multiple instances\n"
107 "of Citadel on the same computer and there is something else\n"
108 "already using port 504.\n",
112 struct config config;
116 * Set an entry in inittab to the desired state
118 void set_init_entry(char *which_entry, char *new_state) {
119 char *inittab = NULL;
127 if (which_entry == NULL) return;
128 if (strlen(which_entry) == 0) return;
130 inittab = strdup("");
131 if (inittab == NULL) return;
133 fp = fopen("/etc/inittab", "r");
134 if (fp == NULL) return;
136 while(fgets(buf, sizeof buf, fp) != NULL) {
138 if (num_tokens(buf, ':') == 4) {
139 extract_token(entry, buf, 0, ':', sizeof entry);
140 extract_token(levels, buf, 1, ':', sizeof levels);
141 extract_token(state, buf, 2, ':', sizeof state);
142 extract_token(prog, buf, 3, ':', sizeof prog); /* includes 0x0a LF */
144 if (!strcmp(entry, which_entry)) {
145 strcpy(state, new_state);
146 sprintf(buf, "%s:%s:%s:%s",
147 entry, levels, state, prog);
151 inittab = realloc(inittab, strlen(inittab) + strlen(buf) + 2);
152 if (inittab == NULL) {
157 strcat(inittab, buf);
160 fp = fopen("/etc/inittab", "w");
162 fwrite(inittab, strlen(inittab), 1, fp);
164 kill(1, SIGHUP); /* Tell init to re-read /etc/inittab */
171 * Locate the name of an inittab entry for a specific program
173 void locate_init_entry(char *init_entry, char *looking_for) {
181 strcpy(init_entry, "");
183 /* Pound through /etc/inittab line by line. Set have_entry to 1 if
184 * an entry is found which we believe starts the specified program.
186 infp = fopen("/etc/inittab", "r");
190 while (fgets(buf, sizeof buf, infp) != NULL) {
191 buf[strlen(buf) - 1] = 0;
192 extract_token(entry, buf, 0, ':', sizeof entry);
193 extract_token(prog, buf, 3, ':', sizeof prog);
194 if (!strncasecmp(prog, looking_for,
195 strlen(looking_for))) {
197 strcpy(init_entry, entry);
207 * Shut down the Citadel service if necessary, during setup.
209 void shutdown_citserver(void) {
210 char looking_for[SIZ];
212 snprintf(looking_for,
221 locate_init_entry(citserver_init_entry, looking_for);
222 if (strlen(citserver_init_entry) > 0) {
223 set_init_entry(citserver_init_entry, "off");
229 * Start the Citadel service.
231 void start_citserver(void) {
232 if (strlen(citserver_init_entry) > 0) {
233 set_init_entry(citserver_init_entry, "respawn");
239 void cleanup(int exitcode)
251 void title(char *text)
253 if (setup_type == UI_TEXT) {
254 printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<%s>\n", text);
260 int yesno(char *question)
263 newtComponent form = NULL;
264 newtComponent yesbutton = NULL;
265 newtComponent nobutton = NULL;
266 int prompt_window_height = 0;
272 switch (setup_type) {
276 printf("%s\nYes/No --> ", question);
277 fgets(buf, sizeof buf, stdin);
278 answer = tolower(buf[0]);
281 else if (answer == 'n')
283 } while ((answer < 0) || (answer > 1));
287 sprintf(buf, "exec %s --yesno '%s' 10 72",
288 getenv("CTDL_DIALOG"),
301 prompt_window_height = num_tokens(question, '\n') + 5;
302 newtCenteredWindow(76, prompt_window_height, "Question");
303 form = newtForm(NULL, NULL, 0);
304 for (i=0; i<num_tokens(question, '\n'); ++i) {
305 extract_token(buf, question, i, '\n', sizeof buf);
306 newtFormAddComponent(form, newtLabel(1, 1+i, buf));
308 yesbutton = newtButton(10, (prompt_window_height - 4), "Yes");
309 nobutton = newtButton(60, (prompt_window_height - 4), "No");
310 newtFormAddComponent(form, yesbutton);
311 newtFormAddComponent(form, nobutton);
312 if (newtRunForm(form) == yesbutton) {
319 newtFormDestroy(form);
329 void important_message(char *title, char *msgtext)
332 newtComponent form = NULL;
337 switch (setup_type) {
340 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");
341 printf(" %s \n\n%s\n\n", title, msgtext);
342 printf("Press return to continue...");
343 fgets(buf, sizeof buf, stdin);
347 sprintf(buf, "exec %s --msgbox '%s' 19 72",
348 getenv("CTDL_DIALOG"),
355 newtCenteredWindow(76, 10, title);
356 form = newtForm(NULL, NULL, 0);
357 for (i=0; i<num_tokens(msgtext, '\n'); ++i) {
358 extract_token(buf, msgtext, i, '\n', sizeof buf);
359 newtFormAddComponent(form, newtLabel(1, 1+i, buf));
361 newtFormAddComponent(form, newtButton(35, 5, "OK"));
364 newtFormDestroy(form);
371 void important_msgnum(int msgnum)
373 important_message("Important Message", setup_text[msgnum]);
376 void display_error(char *error_message)
378 important_message("Error", error_message);
381 void progress(char *text, long int curr, long int cmax)
385 /* These variables are static because progress() gets called
386 * multiple times during the course of whatever operation is
387 * being performed. This makes setup non-threadsafe, but who
390 static newtComponent form = NULL;
391 static newtComponent scale = NULL;
393 static long dots_printed = 0L;
395 static FILE *fp = NULL;
398 switch (setup_type) {
402 printf("%s\n", text);
403 printf("..........................");
404 printf("..........................");
405 printf("..........................\r");
408 } else if (curr == cmax) {
409 printf("\r%79s\n", "");
411 a = (curr * 100) / cmax;
414 while (dots_printed < a) {
424 sprintf(buf, "exec %s --gauge '%s' 7 72 0",
425 getenv("CTDL_DIALOG"),
427 fp = popen(buf, "w");
433 else if (curr == cmax) {
435 fprintf(fp, "100\n");
441 a = (curr * 100) / cmax;
443 fprintf(fp, "%ld\n", a);
452 newtCenteredWindow(76, 8, text);
453 form = newtForm(NULL, NULL, 0);
454 scale = newtScale(1, 3, 74, cmax);
455 newtFormAddComponent(form, scale);
459 if ((curr > 0) && (curr <= cmax)) {
460 newtScaleSet(scale, curr);
464 newtFormDestroy(form);
477 * check_services_entry() -- Make sure "citadel" is in /etc/services
480 void check_services_entry(void)
485 if (getservbyname(SERVICE_NAME, PROTO_NAME) == NULL) {
486 for (i=0; i<=3; ++i) {
487 progress("Adding service entry...", i, 3);
489 sfp = fopen("/etc/services", "a");
491 display_error(strerror(errno));
493 fprintf(sfp, "%s 504/tcp\n",
505 * Generate a unique entry name for a new inittab entry
507 void generate_entry_name(char *entryname) {
510 snprintf(entryname, sizeof entryname, "c0");
513 if (entryname[1] > '9') {
516 if (entryname[0] > 'z') {
518 "Can't generate a unique entry name");
522 snprintf(buf, sizeof buf,
523 "grep %s: /etc/inittab >/dev/null 2>&1", entryname);
524 } while (system(buf) == 0);
530 * check_inittab_entry() -- Make sure "citadel" is in /etc/inittab
533 void check_inittab_entry(void)
536 char looking_for[SIZ];
540 /* Determine the fully qualified path name of citserver */
541 snprintf(looking_for,
550 locate_init_entry(citserver_init_entry, looking_for);
552 /* If there's already an entry, then we have nothing left to do. */
553 if (strlen(citserver_init_entry) > 0) {
557 /* Otherwise, prompt the user to create an entry. */
558 if (getenv("CREATE_INITTAB_ENTRY") != NULL) {
559 if (strcasecmp(getenv("CREATE_INITTAB_ENTRY"), "yes")) {
564 snprintf(question, sizeof question,
565 "Do you want this computer configured to start the Citadel\n"
566 "service automatically? (If you answer yes, an entry in\n"
567 "/etc/inittab pointing to %s will be added.)\n",
569 if (yesno(question) == 0) {
574 /* Generate a unique entry name for /etc/inittab */
575 generate_entry_name(entryname);
577 /* Now write it out to /etc/inittab */
578 infp = fopen("/etc/inittab", "a");
580 display_error(strerror(errno));
582 fprintf(infp, "# Start the Citadel server...\n");
583 fprintf(infp, "%s:2345:respawn:%s %s%s -x3 -llocal4\n",
586 (enable_home)?"-h":"",
587 (enable_home)?setup_directory:"");
589 strcpy(citserver_init_entry, entryname);
595 * On systems which use xinetd, see if we can offer to install Citadel as
596 * the default telnet target.
598 void check_xinetd_entry(void) {
599 char *filename = "/etc/xinetd.d/telnet";
602 int already_citadel = 0;
604 fp = fopen(filename, "r+");
605 if (fp == NULL) return; /* Not there. Oh well... */
607 while (fgets(buf, sizeof buf, fp) != NULL) {
608 if (strstr(buf, setup_directory) != NULL) already_citadel = 1;
611 if (already_citadel) return; /* Already set up this way. */
613 /* Otherwise, prompt the user to create an entry. */
614 if (getenv("CREATE_XINETD_ENTRY") != NULL) {
615 if (strcasecmp(getenv("CREATE_XINETD_ENTRY"), "yes")) {
620 snprintf(buf, sizeof buf,
621 "Setup can configure the \"xinetd\" service to automatically\n"
622 "connect incoming telnet sessions to Citadel, bypassing the\n"
623 "host system login: prompt. Would you like to do this?\n"
625 if (yesno(buf) == 0) {
630 fp = fopen(filename, "w");
632 "# description: telnet service for Citadel users\n"
637 " socket_type = stream\n"
640 " server = /usr/sbin/in.telnetd\n"
641 " server_args = -h -L %s/citadel\n"
642 " log_on_failure += USERID\n"
652 /* Now try to restart the service */
653 system("/etc/init.d/xinetd restart >/dev/null 2>&1");
659 * Offer to disable other MTA's
661 void disable_other_mta(char *mta) {
666 sprintf(buf, "/bin/ls -l /etc/rc*.d/S*%s 2>/dev/null; "
667 "/bin/ls -l /etc/rc.d/rc*.d/S*%s 2>/dev/null",
669 fp = popen(buf, "r");
670 if (fp == NULL) return;
672 while (fgets(buf, sizeof buf, fp) != NULL) {
676 if (lines == 0) return; /* Nothing to do. */
679 /* Offer to replace other MTA with the vastly superior Citadel :) */
681 if (getenv("ACT_AS_MTA")) {
682 if (strcasecmp(getenv("ACT_AS_MTA"), "yes")) {
687 snprintf(buf, sizeof buf,
688 "You appear to have the \"%s\" email program\n"
689 "running on your system. If you want Citadel mail\n"
690 "connected with %s, you will have to manually integrate\n"
691 "them. It is preferable to disable %s, and use Citadel's\n"
692 "SMTP, POP3, and IMAP services.\n\n"
693 "May we disable %s so that Citadel has access to ports\n"
694 "25, 110, and 143?\n",
697 if (yesno(buf) == 0) {
702 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);
704 sprintf(buf, "/etc/init.d/%s stop >/dev/null 2>&1", mta);
712 * Check to see if our server really works. Returns 0 on success.
714 int test_server(void) {
721 /* Generate a silly little cookie. We're going to write it out
722 * to the server and try to get it back. The cookie does not
723 * have to be secret ... just unique.
725 sprintf(cookie, "--test--%d--", getpid());
727 sprintf(cmd, "%s/sendcommand %s%s ECHO %s 2>&1",
733 (enable_home)?"-h":"",
734 (enable_home)?setup_directory:"",
737 fp = popen(cmd, "r");
738 if (fp == NULL) return(errno);
740 while (fgets(buf, sizeof buf, fp) != NULL) {
742 && (strstr(buf, cookie) != NULL) ) {
754 void strprompt(char *prompt_title, char *prompt_text, char *str)
760 int prompt_window_height = 0;
764 char dialog_result[PATH_MAX];
767 strcpy(setupmsg, "");
769 switch (setup_type) {
772 printf("\n%s\n", prompt_text);
773 printf("This is currently set to:\n%s\n", str);
774 printf("Enter new value or press return to leave unchanged:\n");
775 fgets(buf, sizeof buf, stdin);
776 buf[strlen(buf) - 1] = 0;
777 if (strlen(buf) != 0)
782 CtdlMakeTempFileName(dialog_result, sizeof dialog_result);
783 sprintf(buf, "exec %s --inputbox '%s' 19 72 '%s' 2>%s",
784 getenv("CTDL_DIALOG"),
789 fp = fopen(dialog_result, "r");
791 fgets(str, sizeof buf, fp);
792 if (str[strlen(str)-1] == 10) {
793 str[strlen(str)-1] = 0;
796 unlink(dialog_result);
803 prompt_window_height = num_tokens(prompt_text, '\n') + 5 ;
804 newtCenteredWindow(76,
805 prompt_window_height,
807 form = newtForm(NULL, NULL, 0);
808 for (i=0; i<num_tokens(prompt_text, '\n'); ++i) {
809 extract_token(buf, prompt_text, i, '\n', sizeof buf);
810 newtFormAddComponent(form, newtLabel(1, 1+i, buf));
812 newtFormAddComponent(form,
814 (prompt_window_height - 2),
817 (const char **) &result,
818 NEWT_FLAG_RETURNEXIT)
824 newtFormDestroy(form);
830 void set_str_val(int msgpos, char *str) {
831 strprompt(setup_titles[msgpos], setup_text[msgpos], str);
836 void set_int_val(int msgpos, int *ip)
839 snprintf(buf, sizeof buf, "%d", (int) *ip);
840 set_str_val(msgpos, buf);
845 void set_char_val(int msgpos, char *ip)
848 snprintf(buf, sizeof buf, "%d", (int) *ip);
849 set_str_val(msgpos, buf);
850 *ip = (char) atoi(buf);
854 void set_long_val(int msgpos, long int *ip)
857 snprintf(buf, sizeof buf, "%ld", *ip);
858 set_str_val(msgpos, buf);
863 void edit_value(int curr)
867 char ctdluidname[SIZ];
872 if (getenv("SYSADMIN_NAME")) {
873 strcpy(config.c_sysadm, getenv("SYSADMIN_NAME"));
876 set_str_val(curr, config.c_sysadm);
882 config.c_ctdluid = 0; /* XXX Windows hack, prob. insecure */
884 i = config.c_ctdluid;
887 set_int_val(curr, &i);
888 config.c_ctdluid = i;
891 strcpy(ctdluidname, pw->pw_name);
892 set_str_val(curr, ctdluidname);
893 pw = getpwnam(ctdluidname);
895 config.c_ctdluid = pw->pw_uid;
897 else if (atoi(ctdluidname) > 0) {
898 config.c_ctdluid = atoi(ctdluidname);
905 set_str_val(curr, config.c_ip_addr);
909 set_int_val(curr, &config.c_port_number);
917 * (re-)write the config data to disk
919 void write_config_to_disk(void)
930 "/citadel.config", S_IRUSR | S_IWUSR)) == -1) {
931 display_error("setup: cannot open citadel.config");
934 fp = fdopen(fd, "wb");
936 display_error("setup: cannot open citadel.config");
939 fwrite((char *) &config, sizeof(struct config), 1, fp);
947 * Figure out what type of user interface we're going to use
949 int discover_ui(void)
952 /* Use "dialog" if we have it */
953 if (getenv("CTDL_DIALOG") != NULL) {
961 newtDrawRootText(0, 0, "Citadel Setup");
971 int main(int argc, char *argv[])
977 int old_setup_level = 0;
979 struct utsname my_utsname;
985 char relhome[PATH_MAX]="";
986 char ctdldir[PATH_MAX]=CTDLDIR;
988 /* set an invalid setup type */
991 /* Check to see if we're running the web installer */
992 if (getenv("CITADEL_INSTALLER") != NULL) {
993 using_web_installer = 1;
996 /* parse command line args */
997 for (a = 0; a < argc; ++a) {
998 if (!strncmp(argv[a], "-u", 2)) {
999 strcpy(aaa, argv[a]);
1000 strcpy(aaa, &aaa[2]);
1001 setup_type = atoi(aaa);
1003 if (!strcmp(argv[a], "-i")) {
1006 if (!strcmp(argv[a], "-q")) {
1007 setup_type = UI_SILENT;
1012 /* If a setup type was not specified, try to determine automatically
1013 * the best one to use out of all available types.
1015 if (setup_type < 0) {
1016 setup_type = discover_ui();
1018 if (info_only == 1) {
1019 important_message("Citadel Setup", CITADEL);
1023 /* Get started in a valid setup directory. */
1024 strcpy(setup_directory,
1031 if ( (using_web_installer) && (getenv("CITADEL") != NULL) ) {
1032 strcpy(setup_directory, getenv("CITADEL"));
1035 set_str_val(0, setup_directory);
1038 home=(setup_directory[1]!='\0');
1039 relh=home&(setup_directory[1]!='/');
1040 if (!relh) safestrncpy(ctdl_home_directory, setup_directory,
1041 sizeof ctdl_home_directory);
1043 safestrncpy(relhome, ctdl_home_directory,
1046 calc_dirs_n_files(relh, home, relhome, ctdldir);
1048 enable_home=(relh|home);
1050 if ((home) && (chdir(setup_directory) != 0)) {
1051 important_message("Citadel Setup",
1052 "The directory you specified does not exist.");
1056 /* Determine our host name, in case we need to use it as a default */
1059 /* See if we need to shut down the Citadel service. */
1060 for (a=0; a<=3; ++a) {
1061 progress("Shutting down the Citadel service...", a, 3);
1062 if (a == 0) shutdown_citserver();
1066 /* Make sure it's stopped. */
1067 if (test_server() == 0) {
1068 important_message("Citadel Setup",
1069 "The Citadel service is still running.\n"
1070 "Please stop the service manually and run "
1076 switch (setup_type) {
1080 " *** Citadel setup program ***\n\n");
1086 * What we're going to try to do here is append a whole bunch of
1087 * nulls to the citadel.config file, so we can keep the old config
1088 * values if they exist, but if the file is missing or from an
1089 * earlier version with a shorter config structure, when setup tries
1090 * to read the old config parameters, they'll all come up zero.
1091 * The length of the config file will be set to what it's supposed
1092 * to be when we rewrite it, because we replace the old file with a
1093 * completely new copy.
1095 if ((a = open(file_citadel_config, O_WRONLY | O_CREAT | O_APPEND,
1096 S_IRUSR | S_IWUSR)) == -1) {
1097 display_error("setup: cannot append citadel.config");
1100 fp = fdopen(a, "ab");
1102 display_error("setup: cannot append citadel.config");
1105 for (a = 0; a < sizeof(struct config); ++a)
1109 /* now we re-open it, and read the old or blank configuration */
1110 fp = fopen(file_citadel_config, "rb");
1112 display_error("setup: cannot open citadel.config");
1115 fread((char *) &config, sizeof(struct config), 1, fp);
1118 /* set some sample/default values in place of blanks... */
1119 if (strlen(config.c_nodename) == 0)
1120 safestrncpy(config.c_nodename, my_utsname.nodename,
1121 sizeof config.c_nodename);
1122 strtok(config.c_nodename, ".");
1123 if (strlen(config.c_fqdn) == 0) {
1124 if ((he = gethostbyname(my_utsname.nodename)) != NULL)
1125 safestrncpy(config.c_fqdn, he->h_name,
1126 sizeof config.c_fqdn);
1128 safestrncpy(config.c_fqdn, my_utsname.nodename,
1129 sizeof config.c_fqdn);
1131 if (strlen(config.c_humannode) == 0)
1132 strcpy(config.c_humannode, "My System");
1133 if (strlen(config.c_phonenum) == 0)
1134 strcpy(config.c_phonenum, "US 800 555 1212");
1135 if (config.c_initax == 0) {
1136 config.c_initax = 4;
1138 if (strlen(config.c_moreprompt) == 0)
1139 strcpy(config.c_moreprompt, "<more>");
1140 if (strlen(config.c_twitroom) == 0)
1141 strcpy(config.c_twitroom, "Trashcan");
1142 if (strlen(config.c_baseroom) == 0)
1143 strcpy(config.c_baseroom, BASEROOM);
1144 if (strlen(config.c_aideroom) == 0)
1145 strcpy(config.c_aideroom, "Aide");
1146 if (config.c_port_number == 0) {
1147 config.c_port_number = 504;
1149 if (config.c_sleeping == 0) {
1150 config.c_sleeping = 900;
1152 if (config.c_ctdluid == 0) {
1153 pw = getpwnam("citadel");
1155 config.c_ctdluid = pw->pw_uid;
1157 if (config.c_ctdluid == 0) {
1158 pw = getpwnam("bbs");
1160 config.c_ctdluid = pw->pw_uid;
1162 if (config.c_ctdluid == 0) {
1163 pw = getpwnam("guest");
1165 config.c_ctdluid = pw->pw_uid;
1167 if (config.c_createax == 0) {
1168 config.c_createax = 3;
1171 * Negative values for maxsessions are not allowed.
1173 if (config.c_maxsessions < 0) {
1174 config.c_maxsessions = 0;
1176 /* We need a system default message expiry policy, because this is
1177 * the top level and there's no 'higher' policy to fall back on.
1178 * By default, do not expire messages at all.
1180 if (config.c_ep.expire_mode == 0) {
1181 config.c_ep.expire_mode = EXPIRE_MANUAL;
1182 config.c_ep.expire_value = 0;
1186 * Default port numbers for various services
1188 if (config.c_smtp_port == 0) config.c_smtp_port = 25;
1189 if (config.c_pop3_port == 0) config.c_pop3_port = 110;
1190 if (config.c_imap_port == 0) config.c_imap_port = 143;
1191 if (config.c_msa_port == 0) config.c_msa_port = 587;
1192 if (config.c_smtps_port == 0) config.c_smtps_port = 465;
1193 if (config.c_pop3s_port == 0) config.c_pop3s_port = 995;
1194 if (config.c_imaps_port == 0) config.c_imaps_port = 993;
1196 /* Go through a series of dialogs prompting for config info */
1197 if (setup_type != UI_SILENT) {
1198 for (curr = 1; curr <= MAXSETUP; ++curr) {
1203 /***** begin version update section ***** */
1204 /* take care of any updating that is necessary */
1206 old_setup_level = config.c_setup_level;
1208 if (old_setup_level == 0) {
1212 if (old_setup_level < 555) {
1213 important_message("Citadel Setup",
1214 "This Citadel installation is too old "
1218 write_config_to_disk();
1220 old_setup_level = config.c_setup_level;
1222 /* end of version update section */
1225 config.c_setup_level = REV_LEVEL;
1227 /******************************************/
1229 write_config_to_disk();
1231 mkdir(ctdl_info_dir, 0700);
1232 chmod(ctdl_info_dir, 0700);
1233 mkdir(ctdl_bio_dir, 0700);
1234 chmod(ctdl_bio_dir, 0700);
1235 mkdir(ctdl_usrpic_dir, 0700);
1236 chmod(ctdl_usrpic_dir, 0700);
1237 mkdir(ctdl_message_dir, 0700);
1238 chmod(ctdl_message_dir, 0700);
1239 mkdir(ctdl_hlp_dir, 0700);
1240 chmod(ctdl_hlp_dir, 0700);
1241 mkdir(ctdl_image_dir, 0700);
1242 chmod(ctdl_image_dir, 0700);
1243 /* TODO: where to put this? */
1244 mkdir("netconfigs", 0700);
1245 chmod("netconfigs", 0700);
1247 /* Delete files and directories used by older Citadel versions */
1248 system("exec /bin/rm -fr ./rooms ./chatpipes ./expressmsgs ./sessions 2>/dev/null");
1249 unlink("citadel.log");
1252 check_services_entry(); /* Check /etc/services */
1254 check_inittab_entry(); /* Check /etc/inittab */
1255 check_xinetd_entry(); /* Check /etc/xinetd.d/telnet */
1257 /* Offer to disable other MTA's on the system. */
1258 disable_other_mta("courier-authdaemon");
1259 disable_other_mta("courier-imap");
1260 disable_other_mta("courier-imap-ssl");
1261 disable_other_mta("courier-pop");
1262 disable_other_mta("courier-pop3");
1263 disable_other_mta("courier-pop3d");
1264 disable_other_mta("cyrmaster");
1265 disable_other_mta("cyrus");
1266 disable_other_mta("dovecot");
1267 disable_other_mta("exim");
1268 disable_other_mta("exim4");
1269 disable_other_mta("hula");
1270 disable_other_mta("imapd");
1271 disable_other_mta("mta");
1272 disable_other_mta("pop3d");
1273 disable_other_mta("popd");
1274 disable_other_mta("postfix");
1275 disable_other_mta("qmail");
1276 disable_other_mta("saslauthd");
1277 disable_other_mta("sendmail");
1278 disable_other_mta("vmailmgrd");
1279 disable_other_mta("zimbra");
1282 if ((pw = getpwuid(config.c_ctdluid)) == NULL)
1287 progress("Setting file permissions", 0, 4);
1288 chown(".", config.c_ctdluid, gid);
1290 progress("Setting file permissions", 1, 4);
1291 chown(file_citadel_config, config.c_ctdluid, gid);
1293 progress("Setting file permissions", 2, 4);
1295 snprintf(aaa, sizeof aaa,
1298 chown(aaa,0,0); /* config.c_ctdluid, gid); chkpwd needs to be root owned*/
1300 progress("Setting file permissions", 3, 4);
1304 progress("Setting file permissions", 3, 4);
1305 chmod(file_citadel_config, S_IRUSR | S_IWUSR);
1307 progress("Setting file permissions", 4, 4);
1310 /* Contemplate the possibility of auto-configuring OpenLDAP */
1314 /* See if we can start the Citadel service. */
1315 if (strlen(citserver_init_entry) > 0) {
1316 for (a=0; a<=3; ++a) {
1317 progress("Starting the Citadel service...", a, 3);
1318 if (a == 0) start_citserver();
1321 if (test_server() == 0) {
1322 important_message("Setup finished",
1323 "Setup of the Citadel server is complete.\n"
1324 "If you will be using WebCit, please run its\n"
1325 "setup program now; otherwise, run './citadel'\n"
1329 important_message("Setup finished",
1330 "Setup is finished, but the Citadel service "
1331 "failed to start.\n"
1332 "Go back and check your configuration.");
1336 important_message("Setup finished",
1337 "Setup is finished. You may now start the server.");
1347 * If we're in the middle of an Easy Install, we might just be able to
1348 * auto-configure a standalone OpenLDAP server.
1350 void contemplate_ldap(void) {
1352 char slapd_init_entry[SIZ];
1355 /* If conditions are not ideal, give up on this idea... */
1356 if (using_web_installer == 0) return;
1357 if (getenv("LDAP_CONFIG") == NULL) return;
1358 if (getenv("SUPPORT") == NULL) return;
1359 if (getenv("SLAPD_BINARY") == NULL) return;
1360 if (getenv("CITADEL") == NULL) return;
1362 /* And if inittab is already starting slapd, bail out... */
1363 locate_init_entry(slapd_init_entry, getenv("SLAPD_BINARY"));
1364 if (strlen(slapd_init_entry) > 0) {
1365 important_message("Citadel Setup",
1366 "You appear to already have a standalone LDAP "
1367 "service\nconfigured for use with Citadel. No "
1368 "changes will be made.\n");
1369 /* set_init_entry(slapd_init_entry, "off"); */
1373 /* Generate a unique entry name for slapd if we don't have one. */
1375 generate_entry_name(slapd_init_entry);
1378 /* Ask the user if it's ok to set up slapd automatically. */
1379 snprintf(question, sizeof question,
1381 "Do you want this computer configured to start a standalone\n"
1382 "LDAP service automatically? (If you answer yes, a new\n"
1383 "slapd.conf will be written, and an /etc/inittab entry\n"
1384 "pointing to %s will be added.)\n"
1386 getenv("SLAPD_BINARY")
1388 if (yesno(question) == 0)
1391 strcpy(config.c_ldap_base_dn, "dc=example,dc=com");
1392 strprompt("Base DN",
1394 "Please enter the Base DN for your directory. This will\n"
1395 "generally be something based on the primary DNS domain in\n"
1396 "which you receive mail, but it does not have to be. Your\n"
1397 "LDAP tree will be built using this Distinguished Name.\n"
1399 config.c_ldap_base_dn
1402 strcpy(config.c_ldap_host, "localhost");
1403 config.c_ldap_port = 389;
1404 sprintf(config.c_ldap_bind_dn, "cn=manager,%s", config.c_ldap_base_dn);
1407 * Generate a bind password. If you're some grey hat hacker who
1408 * is just dying to get some street cred on Bugtraq, and you think
1409 * this password generation scheme is too weak, please submit a patch
1410 * instead of just whining about it, ok?
1412 sprintf(config.c_ldap_bind_pw, "%d%ld", getpid(), (long)time(NULL));
1414 write_config_to_disk();
1416 fp = fopen(getenv("LDAP_CONFIG"), "w");
1418 sprintf(question, "\nCannot create %s:\n%s\n\n"
1419 "Citadel will still function, but you will "
1420 "not have an LDAP service.\n\n",
1421 getenv("LDAP_CONFIG"),
1424 important_message("Error", question);
1428 fprintf(fp, "include %s/citadel-openldap.schema\n",
1430 fprintf(fp, "pidfile %s/openldap-data/slapd.pid\n",
1432 fprintf(fp, "argsfile %s/openldap-data/slapd.args\n",
1434 fprintf(fp, "allow bind_v2\n"
1438 fprintf(fp, "suffix \"%s\"\n", config.c_ldap_base_dn);
1439 fprintf(fp, "rootdn \"%s\"\n", config.c_ldap_bind_dn);
1440 fprintf(fp, "rootpw %s\n", config.c_ldap_bind_pw);
1441 fprintf(fp, "directory %s/openldap-data\n",
1443 fprintf(fp, "index objectClass eq\n");
1447 /* This is where our OpenLDAP server will keep its data. */
1448 mkdir("openldap-data", 0700);
1450 /* Now write it out to /etc/inittab.
1451 * FIXME make it run as some non-root user.
1452 * The "-d 0" seems superfluous, but it's actually a way to make
1453 * slapd run in the foreground without spewing messages to the console.
1455 fp = fopen("/etc/inittab", "a");
1457 display_error(strerror(errno));
1459 fprintf(fp, "# Start the OpenLDAP server for Citadel...\n");
1460 fprintf(fp, "%s:2345:respawn:%s -d 0 -f %s\n",
1462 getenv("SLAPD_BINARY"),
1463 getenv("LDAP_CONFIG")
1469 #endif /* HAVE_LDAP */