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 * We will set have_sysv_init to nonzero if the host operating system
55 * has a System V style init driven by /etc/inittab. This will cause
56 * setup to offer to automatically start and stop the Citadel service.
58 int have_sysv_init = 0;
61 void contemplate_ldap(void);
64 char *setup_titles[] =
66 "Citadel Home Directory",
67 "System Administrator",
76 /* calculate all our path on a central place */
77 /* where to keep our config */
80 char *setup_text[] = {
82 "Enter the full pathname of the directory in which the Citadel\n"
83 "installation you are creating or updating resides. If you\n"
84 "specify a directory other than the default, you will need to\n"
85 "specify the -h flag to the server when you start it up.\n",
87 "Enter the subdirectoryname for an alternating installation of "
88 "Citadel. To do a default installation just leave it blank."
89 "If you specify a directory other than the default, you will need to\n"
90 "specify the -h flag to the server when you start it up.\n"
91 "note that it may not have a leading /",
94 "Enter the name of the system administrator (which is probably\n"
95 "you). When an account is created with this name, it will\n"
96 "automatically be given administrator-level access.\n",
98 "Citadel needs to run under its own user ID. This would\n"
99 "typically be called \"citadel\", but if you are running Citadel\n"
100 "as a public BBS, you might also call it \"bbs\" or \"guest\".\n"
101 "The server will run under this user ID. Please specify that\n"
102 "user ID here. You may specify either a user name or a numeric\n"
105 "Specify the IP address on which your server will run. If you\n"
106 "leave this blank, or if you specify 0.0.0.0, Citadel will listen\n"
107 "on all addresses. You can usually skip this unless you are\n"
108 "running multiple instances of Citadel on the same computer.\n",
110 "Specify the TCP port number on which your server will run.\n"
111 "Normally, this will be port 504, which is the official port\n"
112 "assigned by the IANA for Citadel servers. You will only need\n"
113 "to specify a different port number if you run multiple instances\n"
114 "of Citadel on the same computer and there is something else\n"
115 "already using port 504.\n",
119 struct config config;
123 * Set an entry in inittab to the desired state
125 void set_init_entry(char *which_entry, char *new_state) {
126 char *inittab = NULL;
134 if (which_entry == NULL) return;
135 if (strlen(which_entry) == 0) return;
137 inittab = strdup("");
138 if (inittab == NULL) return;
140 fp = fopen("/etc/inittab", "r");
141 if (fp == NULL) return;
143 while(fgets(buf, sizeof buf, fp) != NULL) {
145 if (num_tokens(buf, ':') == 4) {
146 extract_token(entry, buf, 0, ':', sizeof entry);
147 extract_token(levels, buf, 1, ':', sizeof levels);
148 extract_token(state, buf, 2, ':', sizeof state);
149 extract_token(prog, buf, 3, ':', sizeof prog); /* includes 0x0a LF */
151 if (!strcmp(entry, which_entry)) {
152 strcpy(state, new_state);
153 sprintf(buf, "%s:%s:%s:%s",
154 entry, levels, state, prog);
158 inittab = realloc(inittab, strlen(inittab) + strlen(buf) + 2);
159 if (inittab == NULL) {
164 strcat(inittab, buf);
167 fp = fopen("/etc/inittab", "w");
169 fwrite(inittab, strlen(inittab), 1, fp);
171 kill(1, SIGHUP); /* Tell init to re-read /etc/inittab */
178 * Locate the name of an inittab entry for a specific program
180 void locate_init_entry(char *init_entry, char *looking_for) {
188 strcpy(init_entry, "");
190 /* Pound through /etc/inittab line by line. Set have_entry to 1 if
191 * an entry is found which we believe starts the specified program.
193 infp = fopen("/etc/inittab", "r");
197 while (fgets(buf, sizeof buf, infp) != NULL) {
198 buf[strlen(buf) - 1] = 0;
199 extract_token(entry, buf, 0, ':', sizeof entry);
200 extract_token(prog, buf, 3, ':', sizeof prog);
201 if (!strncasecmp(prog, looking_for,
202 strlen(looking_for))) {
204 strcpy(init_entry, entry);
214 * Shut down the Citadel service if necessary, during setup.
216 void shutdown_citserver(void) {
217 char looking_for[SIZ];
219 snprintf(looking_for,
228 locate_init_entry(citserver_init_entry, looking_for);
229 if (strlen(citserver_init_entry) > 0) {
230 set_init_entry(citserver_init_entry, "off");
236 * Start the Citadel service.
238 void start_citserver(void) {
239 if (strlen(citserver_init_entry) > 0) {
240 set_init_entry(citserver_init_entry, "respawn");
246 void cleanup(int exitcode)
258 void title(char *text)
260 if (setup_type == UI_TEXT) {
261 printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<%s>\n", text);
267 int yesno(char *question)
270 newtComponent form = NULL;
271 newtComponent yesbutton = NULL;
272 newtComponent nobutton = NULL;
273 int prompt_window_height = 0;
279 switch (setup_type) {
283 printf("%s\nYes/No --> ", question);
284 fgets(buf, sizeof buf, stdin);
285 answer = tolower(buf[0]);
288 else if (answer == 'n')
290 } while ((answer < 0) || (answer > 1));
294 sprintf(buf, "exec %s --yesno '%s' 10 72",
295 getenv("CTDL_DIALOG"),
308 prompt_window_height = num_tokens(question, '\n') + 5;
309 newtCenteredWindow(76, prompt_window_height, "Question");
310 form = newtForm(NULL, NULL, 0);
311 for (i=0; i<num_tokens(question, '\n'); ++i) {
312 extract_token(buf, question, i, '\n', sizeof buf);
313 newtFormAddComponent(form, newtLabel(1, 1+i, buf));
315 yesbutton = newtButton(10, (prompt_window_height - 4), "Yes");
316 nobutton = newtButton(60, (prompt_window_height - 4), "No");
317 newtFormAddComponent(form, yesbutton);
318 newtFormAddComponent(form, nobutton);
319 if (newtRunForm(form) == yesbutton) {
326 newtFormDestroy(form);
336 void important_message(char *title, char *msgtext)
339 newtComponent form = NULL;
344 switch (setup_type) {
347 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");
348 printf(" %s \n\n%s\n\n", title, msgtext);
349 printf("Press return to continue...");
350 fgets(buf, sizeof buf, stdin);
354 sprintf(buf, "exec %s --msgbox '%s' 19 72",
355 getenv("CTDL_DIALOG"),
362 newtCenteredWindow(76, 10, title);
363 form = newtForm(NULL, NULL, 0);
364 for (i=0; i<num_tokens(msgtext, '\n'); ++i) {
365 extract_token(buf, msgtext, i, '\n', sizeof buf);
366 newtFormAddComponent(form, newtLabel(1, 1+i, buf));
368 newtFormAddComponent(form, newtButton(35, 5, "OK"));
371 newtFormDestroy(form);
378 void important_msgnum(int msgnum)
380 important_message("Important Message", setup_text[msgnum]);
383 void display_error(char *error_message)
385 important_message("Error", error_message);
388 void progress(char *text, long int curr, long int cmax)
392 /* These variables are static because progress() gets called
393 * multiple times during the course of whatever operation is
394 * being performed. This makes setup non-threadsafe, but who
397 static newtComponent form = NULL;
398 static newtComponent scale = NULL;
400 static long dots_printed = 0L;
402 static FILE *fp = NULL;
405 switch (setup_type) {
409 printf("%s\n", text);
410 printf("..........................");
411 printf("..........................");
412 printf("..........................\r");
415 } else if (curr == cmax) {
416 printf("\r%79s\n", "");
418 a = (curr * 100) / cmax;
421 while (dots_printed < a) {
431 sprintf(buf, "exec %s --gauge '%s' 7 72 0",
432 getenv("CTDL_DIALOG"),
434 fp = popen(buf, "w");
440 else if (curr == cmax) {
442 fprintf(fp, "100\n");
448 a = (curr * 100) / cmax;
450 fprintf(fp, "%ld\n", a);
459 newtCenteredWindow(76, 8, text);
460 form = newtForm(NULL, NULL, 0);
461 scale = newtScale(1, 3, 74, cmax);
462 newtFormAddComponent(form, scale);
466 if ((curr > 0) && (curr <= cmax)) {
467 newtScaleSet(scale, curr);
471 newtFormDestroy(form);
484 * check_services_entry() -- Make sure "citadel" is in /etc/services
487 void check_services_entry(void)
492 if (getservbyname(SERVICE_NAME, PROTO_NAME) == NULL) {
493 for (i=0; i<=3; ++i) {
494 progress("Adding service entry...", i, 3);
496 sfp = fopen("/etc/services", "a");
498 display_error(strerror(errno));
500 fprintf(sfp, "%s 504/tcp\n",
512 * Generate a unique entry name for a new inittab entry
514 void generate_entry_name(char *entryname) {
517 snprintf(entryname, sizeof entryname, "c0");
520 if (entryname[1] > '9') {
523 if (entryname[0] > 'z') {
525 "Can't generate a unique entry name");
529 snprintf(buf, sizeof buf,
530 "grep %s: /etc/inittab >/dev/null 2>&1", entryname);
531 } while (system(buf) == 0);
537 * check_inittab_entry() -- Make sure "citadel" is in /etc/inittab
540 void check_inittab_entry(void)
543 char looking_for[SIZ];
547 /* Determine the fully qualified path name of citserver */
548 snprintf(looking_for,
557 locate_init_entry(citserver_init_entry, looking_for);
559 /* If there's already an entry, then we have nothing left to do. */
560 if (strlen(citserver_init_entry) > 0) {
564 /* Otherwise, prompt the user to create an entry. */
565 if (getenv("CREATE_INITTAB_ENTRY") != NULL) {
566 if (strcasecmp(getenv("CREATE_INITTAB_ENTRY"), "yes")) {
571 snprintf(question, sizeof question,
572 "Do you want this computer configured to start the Citadel\n"
573 "service automatically? (If you answer yes, an entry in\n"
574 "/etc/inittab pointing to %s will be added.)\n",
576 if (yesno(question) == 0) {
581 /* Generate a unique entry name for /etc/inittab */
582 generate_entry_name(entryname);
584 /* Now write it out to /etc/inittab */
585 infp = fopen("/etc/inittab", "a");
587 display_error(strerror(errno));
589 fprintf(infp, "# Start the Citadel server...\n");
590 fprintf(infp, "%s:2345:respawn:%s %s%s -llocal4\n",
593 (enable_home)?"-h":"",
594 (enable_home)?setup_directory:"");
596 strcpy(citserver_init_entry, entryname);
602 * On systems which use xinetd, see if we can offer to install Citadel as
603 * the default telnet target.
605 void check_xinetd_entry(void) {
606 char *filename = "/etc/xinetd.d/telnet";
609 int already_citadel = 0;
611 fp = fopen(filename, "r+");
612 if (fp == NULL) return; /* Not there. Oh well... */
614 while (fgets(buf, sizeof buf, fp) != NULL) {
615 if (strstr(buf, setup_directory) != NULL) already_citadel = 1;
618 if (already_citadel) return; /* Already set up this way. */
620 /* Otherwise, prompt the user to create an entry. */
621 if (getenv("CREATE_XINETD_ENTRY") != NULL) {
622 if (strcasecmp(getenv("CREATE_XINETD_ENTRY"), "yes")) {
627 snprintf(buf, sizeof buf,
628 "Setup can configure the \"xinetd\" service to automatically\n"
629 "connect incoming telnet sessions to Citadel, bypassing the\n"
630 "host system login: prompt. Would you like to do this?\n"
632 if (yesno(buf) == 0) {
637 fp = fopen(filename, "w");
639 "# description: telnet service for Citadel users\n"
644 " socket_type = stream\n"
647 " server = /usr/sbin/in.telnetd\n"
648 " server_args = -h -L %s/citadel\n"
649 " log_on_failure += USERID\n"
659 /* Now try to restart the service */
660 system("/etc/init.d/xinetd restart >/dev/null 2>&1");
666 * Offer to disable other MTA's
668 void disable_other_mta(char *mta) {
673 sprintf(buf, "/bin/ls -l /etc/rc*.d/S*%s 2>/dev/null; "
674 "/bin/ls -l /etc/rc.d/rc*.d/S*%s 2>/dev/null",
676 fp = popen(buf, "r");
677 if (fp == NULL) return;
679 while (fgets(buf, sizeof buf, fp) != NULL) {
683 if (lines == 0) return; /* Nothing to do. */
686 /* Offer to replace other MTA with the vastly superior Citadel :) */
688 if (getenv("ACT_AS_MTA")) {
689 if (strcasecmp(getenv("ACT_AS_MTA"), "yes")) {
694 snprintf(buf, sizeof buf,
695 "You appear to have the \"%s\" email program\n"
696 "running on your system. If you want Citadel mail\n"
697 "connected with %s, you will have to manually integrate\n"
698 "them. It is preferable to disable %s, and use Citadel's\n"
699 "SMTP, POP3, and IMAP services.\n\n"
700 "May we disable %s so that Citadel has access to ports\n"
701 "25, 110, and 143?\n",
704 if (yesno(buf) == 0) {
709 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);
711 sprintf(buf, "/etc/init.d/%s stop >/dev/null 2>&1", mta);
719 * Check to see if our server really works. Returns 0 on success.
721 int test_server(void) {
728 /* Generate a silly little cookie. We're going to write it out
729 * to the server and try to get it back. The cookie does not
730 * have to be secret ... just unique.
732 sprintf(cookie, "--test--%d--", getpid());
734 sprintf(cmd, "%s/sendcommand %s%s ECHO %s 2>&1",
740 (enable_home)?"-h":"",
741 (enable_home)?setup_directory:"",
744 fp = popen(cmd, "r");
745 if (fp == NULL) return(errno);
747 while (fgets(buf, sizeof buf, fp) != NULL) {
749 && (strstr(buf, cookie) != NULL) ) {
761 void strprompt(char *prompt_title, char *prompt_text, char *str)
767 int prompt_window_height = 0;
771 char dialog_result[PATH_MAX];
774 strcpy(setupmsg, "");
776 switch (setup_type) {
779 printf("\n%s\n", prompt_text);
780 printf("This is currently set to:\n%s\n", str);
781 printf("Enter new value or press return to leave unchanged:\n");
782 fgets(buf, sizeof buf, stdin);
783 buf[strlen(buf) - 1] = 0;
784 if (strlen(buf) != 0)
789 CtdlMakeTempFileName(dialog_result, sizeof dialog_result);
790 sprintf(buf, "exec %s --inputbox '%s' 19 72 '%s' 2>%s",
791 getenv("CTDL_DIALOG"),
796 fp = fopen(dialog_result, "r");
798 fgets(str, sizeof buf, fp);
799 if (str[strlen(str)-1] == 10) {
800 str[strlen(str)-1] = 0;
803 unlink(dialog_result);
810 prompt_window_height = num_tokens(prompt_text, '\n') + 5 ;
811 newtCenteredWindow(76,
812 prompt_window_height,
814 form = newtForm(NULL, NULL, 0);
815 for (i=0; i<num_tokens(prompt_text, '\n'); ++i) {
816 extract_token(buf, prompt_text, i, '\n', sizeof buf);
817 newtFormAddComponent(form, newtLabel(1, 1+i, buf));
819 newtFormAddComponent(form,
821 (prompt_window_height - 2),
824 (const char **) &result,
825 NEWT_FLAG_RETURNEXIT)
831 newtFormDestroy(form);
837 void set_str_val(int msgpos, char *str) {
838 strprompt(setup_titles[msgpos], setup_text[msgpos], str);
843 void set_int_val(int msgpos, int *ip)
846 snprintf(buf, sizeof buf, "%d", (int) *ip);
847 set_str_val(msgpos, buf);
852 void set_char_val(int msgpos, char *ip)
855 snprintf(buf, sizeof buf, "%d", (int) *ip);
856 set_str_val(msgpos, buf);
857 *ip = (char) atoi(buf);
861 void set_long_val(int msgpos, long int *ip)
864 snprintf(buf, sizeof buf, "%ld", *ip);
865 set_str_val(msgpos, buf);
870 void edit_value(int curr)
874 char ctdluidname[SIZ];
879 if (getenv("SYSADMIN_NAME")) {
880 strcpy(config.c_sysadm, getenv("SYSADMIN_NAME"));
883 set_str_val(curr, config.c_sysadm);
889 config.c_ctdluid = 0; /* XXX Windows hack, prob. insecure */
891 i = config.c_ctdluid;
894 set_int_val(curr, &i);
895 config.c_ctdluid = i;
898 strcpy(ctdluidname, pw->pw_name);
899 set_str_val(curr, ctdluidname);
900 pw = getpwnam(ctdluidname);
902 config.c_ctdluid = pw->pw_uid;
904 else if (atoi(ctdluidname) > 0) {
905 config.c_ctdluid = atoi(ctdluidname);
912 set_str_val(curr, config.c_ip_addr);
916 set_int_val(curr, &config.c_port_number);
924 * (re-)write the config data to disk
926 void write_config_to_disk(void)
937 "/citadel.config", S_IRUSR | S_IWUSR)) == -1) {
938 display_error("setup: cannot open citadel.config");
941 fp = fdopen(fd, "wb");
943 display_error("setup: cannot open citadel.config");
946 fwrite((char *) &config, sizeof(struct config), 1, fp);
954 * Figure out what type of user interface we're going to use
956 int discover_ui(void)
959 /* Use "dialog" if we have it */
960 if (getenv("CTDL_DIALOG") != NULL) {
968 newtDrawRootText(0, 0, "Citadel Setup");
978 int main(int argc, char *argv[])
984 int old_setup_level = 0;
986 struct utsname my_utsname;
992 char relhome[PATH_MAX]="";
993 char ctdldir[PATH_MAX]=CTDLDIR;
995 /* set an invalid setup type */
998 /* Learn whether to skip the auto-service-start questions */
999 fp = fopen("/etc/inittab", "r");
1005 /* Check to see if we're running the web installer */
1006 if (getenv("CITADEL_INSTALLER") != NULL) {
1007 using_web_installer = 1;
1010 /* parse command line args */
1011 for (a = 0; a < argc; ++a) {
1012 if (!strncmp(argv[a], "-u", 2)) {
1013 strcpy(aaa, argv[a]);
1014 strcpy(aaa, &aaa[2]);
1015 setup_type = atoi(aaa);
1017 if (!strcmp(argv[a], "-i")) {
1020 if (!strcmp(argv[a], "-q")) {
1021 setup_type = UI_SILENT;
1026 /* If a setup type was not specified, try to determine automatically
1027 * the best one to use out of all available types.
1029 if (setup_type < 0) {
1030 setup_type = discover_ui();
1032 if (info_only == 1) {
1033 important_message("Citadel Setup", CITADEL);
1037 /* Get started in a valid setup directory. */
1038 strcpy(setup_directory,
1045 if ( (using_web_installer) && (getenv("CITADEL") != NULL) ) {
1046 strcpy(setup_directory, getenv("CITADEL"));
1049 set_str_val(0, setup_directory);
1052 home=(setup_directory[1]!='\0');
1053 relh=home&(setup_directory[1]!='/');
1054 if (!relh) safestrncpy(ctdl_home_directory, setup_directory,
1055 sizeof ctdl_home_directory);
1057 safestrncpy(relhome, ctdl_home_directory,
1060 calc_dirs_n_files(relh, home, relhome, ctdldir);
1062 enable_home=(relh|home);
1064 if ((home) && (chdir(setup_directory) != 0)) {
1065 important_message("Citadel Setup",
1066 "The directory you specified does not exist.");
1070 /* Determine our host name, in case we need to use it as a default */
1073 if (have_sysv_init) {
1074 /* See if we need to shut down the Citadel service. */
1075 for (a=0; a<=3; ++a) {
1076 progress("Shutting down the Citadel service...", a, 3);
1077 if (a == 0) shutdown_citserver();
1081 /* Make sure it's stopped. */
1082 if (test_server() == 0) {
1083 important_message("Citadel Setup",
1084 "The Citadel service is still running.\n"
1085 "Please stop the service manually and run "
1092 switch (setup_type) {
1096 " *** Citadel setup program ***\n\n");
1102 * What we're going to try to do here is append a whole bunch of
1103 * nulls to the citadel.config file, so we can keep the old config
1104 * values if they exist, but if the file is missing or from an
1105 * earlier version with a shorter config structure, when setup tries
1106 * to read the old config parameters, they'll all come up zero.
1107 * The length of the config file will be set to what it's supposed
1108 * to be when we rewrite it, because we replace the old file with a
1109 * completely new copy.
1111 if ((a = open(file_citadel_config, O_WRONLY | O_CREAT | O_APPEND,
1112 S_IRUSR | S_IWUSR)) == -1) {
1113 display_error("setup: cannot append citadel.config");
1116 fp = fdopen(a, "ab");
1118 display_error("setup: cannot append citadel.config");
1121 for (a = 0; a < sizeof(struct config); ++a)
1125 /* now we re-open it, and read the old or blank configuration */
1126 fp = fopen(file_citadel_config, "rb");
1128 display_error("setup: cannot open citadel.config");
1131 fread((char *) &config, sizeof(struct config), 1, fp);
1134 /* set some sample/default values in place of blanks... */
1135 if (strlen(config.c_nodename) == 0)
1136 safestrncpy(config.c_nodename, my_utsname.nodename,
1137 sizeof config.c_nodename);
1138 strtok(config.c_nodename, ".");
1139 if (strlen(config.c_fqdn) == 0) {
1140 if ((he = gethostbyname(my_utsname.nodename)) != NULL)
1141 safestrncpy(config.c_fqdn, he->h_name,
1142 sizeof config.c_fqdn);
1144 safestrncpy(config.c_fqdn, my_utsname.nodename,
1145 sizeof config.c_fqdn);
1147 if (strlen(config.c_humannode) == 0)
1148 strcpy(config.c_humannode, "My System");
1149 if (strlen(config.c_phonenum) == 0)
1150 strcpy(config.c_phonenum, "US 800 555 1212");
1151 if (config.c_initax == 0) {
1152 config.c_initax = 4;
1154 if (strlen(config.c_moreprompt) == 0)
1155 strcpy(config.c_moreprompt, "<more>");
1156 if (strlen(config.c_twitroom) == 0)
1157 strcpy(config.c_twitroom, "Trashcan");
1158 if (strlen(config.c_baseroom) == 0)
1159 strcpy(config.c_baseroom, BASEROOM);
1160 if (strlen(config.c_aideroom) == 0)
1161 strcpy(config.c_aideroom, "Aide");
1162 if (config.c_port_number == 0) {
1163 config.c_port_number = 504;
1165 if (config.c_sleeping == 0) {
1166 config.c_sleeping = 900;
1168 if (config.c_ctdluid == 0) {
1169 pw = getpwnam("citadel");
1171 config.c_ctdluid = pw->pw_uid;
1173 if (config.c_ctdluid == 0) {
1174 pw = getpwnam("bbs");
1176 config.c_ctdluid = pw->pw_uid;
1178 if (config.c_ctdluid == 0) {
1179 pw = getpwnam("guest");
1181 config.c_ctdluid = pw->pw_uid;
1183 if (config.c_createax == 0) {
1184 config.c_createax = 3;
1187 * Negative values for maxsessions are not allowed.
1189 if (config.c_maxsessions < 0) {
1190 config.c_maxsessions = 0;
1192 /* We need a system default message expiry policy, because this is
1193 * the top level and there's no 'higher' policy to fall back on.
1194 * By default, do not expire messages at all.
1196 if (config.c_ep.expire_mode == 0) {
1197 config.c_ep.expire_mode = EXPIRE_MANUAL;
1198 config.c_ep.expire_value = 0;
1202 * Default port numbers for various services
1204 if (config.c_smtp_port == 0) config.c_smtp_port = 25;
1205 if (config.c_pop3_port == 0) config.c_pop3_port = 110;
1206 if (config.c_imap_port == 0) config.c_imap_port = 143;
1207 if (config.c_msa_port == 0) config.c_msa_port = 587;
1208 if (config.c_smtps_port == 0) config.c_smtps_port = 465;
1209 if (config.c_pop3s_port == 0) config.c_pop3s_port = 995;
1210 if (config.c_imaps_port == 0) config.c_imaps_port = 993;
1212 /* Go through a series of dialogs prompting for config info */
1213 if (setup_type != UI_SILENT) {
1214 for (curr = 1; curr <= MAXSETUP; ++curr) {
1219 /***** begin version update section ***** */
1220 /* take care of any updating that is necessary */
1222 old_setup_level = config.c_setup_level;
1224 if (old_setup_level == 0) {
1228 if (old_setup_level < 555) {
1229 important_message("Citadel Setup",
1230 "This Citadel installation is too old "
1234 write_config_to_disk();
1236 old_setup_level = config.c_setup_level;
1238 /* end of version update section */
1241 config.c_setup_level = REV_LEVEL;
1243 /******************************************/
1245 write_config_to_disk();
1247 mkdir(ctdl_info_dir, 0700);
1248 chmod(ctdl_info_dir, 0700);
1249 chown(ctdl_info_dir, config.c_ctdluid, -1);
1251 mkdir(ctdl_bio_dir, 0700);
1252 chmod(ctdl_bio_dir, 0700);
1253 chown(ctdl_bio_dir, config.c_ctdluid, -1);
1255 mkdir(ctdl_usrpic_dir, 0700);
1256 chmod(ctdl_usrpic_dir, 0700);
1257 chown(ctdl_usrpic_dir, config.c_ctdluid, -1);
1259 mkdir(ctdl_message_dir, 0700);
1260 chmod(ctdl_message_dir, 0700);
1261 chown(ctdl_message_dir, config.c_ctdluid, -1);
1263 mkdir(ctdl_hlp_dir, 0700);
1264 chmod(ctdl_hlp_dir, 0700);
1265 chown(ctdl_hlp_dir, config.c_ctdluid, -1);
1267 mkdir(ctdl_image_dir, 0700);
1268 chmod(ctdl_image_dir, 0700);
1269 chown(ctdl_image_dir, config.c_ctdluid, -1);
1271 /* TODO: where to put this? */
1272 mkdir("netconfigs", 0700);
1273 chmod("netconfigs", 0700);
1274 chown("netconfigs", config.c_ctdluid, -1);
1276 /* Delete files and directories used by older Citadel versions */
1277 system("exec /bin/rm -fr ./rooms ./chatpipes ./expressmsgs ./sessions 2>/dev/null");
1278 unlink("citadel.log");
1281 check_services_entry(); /* Check /etc/services */
1283 if (have_sysv_init) {
1284 check_inittab_entry(); /* Check /etc/inittab */
1286 check_xinetd_entry(); /* Check /etc/xinetd.d/telnet */
1288 /* Offer to disable other MTA's on the system. */
1289 disable_other_mta("courier-authdaemon");
1290 disable_other_mta("courier-imap");
1291 disable_other_mta("courier-imap-ssl");
1292 disable_other_mta("courier-pop");
1293 disable_other_mta("courier-pop3");
1294 disable_other_mta("courier-pop3d");
1295 disable_other_mta("cyrmaster");
1296 disable_other_mta("cyrus");
1297 disable_other_mta("dovecot");
1298 disable_other_mta("exim");
1299 disable_other_mta("exim4");
1300 disable_other_mta("hula");
1301 disable_other_mta("imapd");
1302 disable_other_mta("mta");
1303 disable_other_mta("pop3d");
1304 disable_other_mta("popd");
1305 disable_other_mta("postfix");
1306 disable_other_mta("qmail");
1307 disable_other_mta("saslauthd");
1308 disable_other_mta("sendmail");
1309 disable_other_mta("vmailmgrd");
1310 disable_other_mta("zimbra");
1313 if ((pw = getpwuid(config.c_ctdluid)) == NULL)
1318 progress("Setting file permissions", 0, 4);
1319 chown(".", config.c_ctdluid, gid);
1321 progress("Setting file permissions", 1, 4);
1322 chown(file_citadel_config, config.c_ctdluid, gid);
1324 progress("Setting file permissions", 2, 4);
1326 snprintf(aaa, sizeof aaa,
1329 chown(aaa,0,0); /* config.c_ctdluid, gid); chkpwd needs to be root owned*/
1331 progress("Setting file permissions", 3, 4);
1335 progress("Setting file permissions", 3, 4);
1336 chmod(file_citadel_config, S_IRUSR | S_IWUSR);
1338 progress("Setting file permissions", 4, 4);
1341 /* Contemplate the possibility of auto-configuring OpenLDAP */
1345 /* See if we can start the Citadel service. */
1346 if ( (have_sysv_init) && (strlen(citserver_init_entry) > 0) ) {
1347 for (a=0; a<=3; ++a) {
1348 progress("Starting the Citadel service...", a, 3);
1349 if (a == 0) start_citserver();
1352 if (test_server() == 0) {
1353 important_message("Setup finished",
1354 "Setup of the Citadel server is complete.\n"
1355 "If you will be using WebCit, please run its\n"
1356 "setup program now; otherwise, run './citadel'\n"
1360 important_message("Setup finished",
1361 "Setup is finished, but the Citadel service "
1362 "failed to start.\n"
1363 "Go back and check your configuration.");
1367 important_message("Setup finished",
1368 "Setup is finished. You may now start the server.");
1378 * If we're in the middle of an Easy Install, we might just be able to
1379 * auto-configure a standalone OpenLDAP server.
1381 void contemplate_ldap(void) {
1383 char slapd_init_entry[SIZ];
1386 /* If conditions are not ideal, give up on this idea... */
1387 if (!have_sysv_init) return;
1388 if (using_web_installer == 0) return;
1389 if (getenv("LDAP_CONFIG") == NULL) return;
1390 if (getenv("SUPPORT") == NULL) return;
1391 if (getenv("SLAPD_BINARY") == NULL) return;
1392 if (getenv("CITADEL") == NULL) return;
1394 /* And if inittab is already starting slapd, bail out... */
1395 locate_init_entry(slapd_init_entry, getenv("SLAPD_BINARY"));
1396 if (strlen(slapd_init_entry) > 0) {
1397 important_message("Citadel Setup",
1398 "You appear to already have a standalone LDAP "
1399 "service\nconfigured for use with Citadel. No "
1400 "changes will be made.\n");
1401 /* set_init_entry(slapd_init_entry, "off"); */
1405 /* Generate a unique entry name for slapd if we don't have one. */
1407 generate_entry_name(slapd_init_entry);
1410 /* Ask the user if it's ok to set up slapd automatically. */
1411 snprintf(question, sizeof question,
1413 "Do you want this computer configured to start a standalone\n"
1414 "LDAP service automatically? (If you answer yes, a new\n"
1415 "slapd.conf will be written, and an /etc/inittab entry\n"
1416 "pointing to %s will be added.)\n"
1418 getenv("SLAPD_BINARY")
1420 if (yesno(question) == 0)
1423 strcpy(config.c_ldap_base_dn, "dc=example,dc=com");
1424 strprompt("Base DN",
1426 "Please enter the Base DN for your directory. This will\n"
1427 "generally be something based on the primary DNS domain in\n"
1428 "which you receive mail, but it does not have to be. Your\n"
1429 "LDAP tree will be built using this Distinguished Name.\n"
1431 config.c_ldap_base_dn
1434 strcpy(config.c_ldap_host, "localhost");
1435 config.c_ldap_port = 389;
1436 sprintf(config.c_ldap_bind_dn, "cn=manager,%s", config.c_ldap_base_dn);
1439 * Generate a bind password. If you're some grey hat hacker who
1440 * is just dying to get some street cred on Bugtraq, and you think
1441 * this password generation scheme is too weak, please submit a patch
1442 * instead of just whining about it, ok?
1444 sprintf(config.c_ldap_bind_pw, "%d%ld", getpid(), (long)time(NULL));
1446 write_config_to_disk();
1448 fp = fopen(getenv("LDAP_CONFIG"), "w");
1450 sprintf(question, "\nCannot create %s:\n%s\n\n"
1451 "Citadel will still function, but you will "
1452 "not have an LDAP service.\n\n",
1453 getenv("LDAP_CONFIG"),
1456 important_message("Error", question);
1460 fprintf(fp, "include %s/citadel-openldap.schema\n",
1462 fprintf(fp, "pidfile %s/openldap-data/slapd.pid\n",
1464 fprintf(fp, "argsfile %s/openldap-data/slapd.args\n",
1466 fprintf(fp, "allow bind_v2\n"
1470 fprintf(fp, "suffix \"%s\"\n", config.c_ldap_base_dn);
1471 fprintf(fp, "rootdn \"%s\"\n", config.c_ldap_bind_dn);
1472 fprintf(fp, "rootpw %s\n", config.c_ldap_bind_pw);
1473 fprintf(fp, "directory %s/openldap-data\n",
1475 fprintf(fp, "index objectClass eq\n");
1479 /* This is where our OpenLDAP server will keep its data. */
1480 mkdir("openldap-data", 0700);
1482 /* Now write it out to /etc/inittab.
1483 * FIXME make it run as some non-root user.
1484 * The "-d 0" seems superfluous, but it's actually a way to make
1485 * slapd run in the foreground without spewing messages to the console.
1487 fp = fopen("/etc/inittab", "a");
1489 display_error(strerror(errno));
1491 fprintf(fp, "# Start the OpenLDAP server for Citadel...\n");
1492 fprintf(fp, "%s:2345:respawn:%s -d 0 -f %s\n",
1494 getenv("SLAPD_BINARY"),
1495 getenv("LDAP_CONFIG")
1501 #endif /* HAVE_LDAP */