4 * Citadel setup utility
14 #include <sys/types.h>
16 #include <sys/utsname.h>
35 #define MAXSETUP 4 /* How many setup questions to ask */
37 #define UI_TEXT 0 /* Default setup type -- text only */
38 #define UI_SILENT 3 /* Silent running, for use in scripts */
39 #define UI_NEWT 4 /* Use the "newt" window library */
41 #define SERVICE_NAME "citadel"
42 #define PROTO_NAME "tcp"
45 char setup_directory[SIZ];
46 char citserver_init_entry[SIZ];
47 int using_web_installer = 0;
50 void contemplate_ldap(void);
53 char *setup_titles[] =
55 "Citadel Home Directory",
56 "System Administrator",
65 "Enter the full pathname of the directory in which the Citadel installation\n"
66 "you are creating or updating resides. If you specify a directory other\n"
67 "than the default, you will need to specify the -h flag to the server when\n"
70 "Enter the name of the system administrator (which is probably you).\n"
71 "When an account is created with this name, it will automatically be\n"
72 "assigned the highest access level.\n",
74 "Citadel needs to run under its own user ID. This would typically be\n"
75 "called \"citadel\", but if you are running Citadel as a public BBS, you\n"
76 "might also call it \"bbs\" or \"guest\". The server will run under this\n"
77 "user ID. Please specify that user ID here. You may specify either a\n"
78 "user name or a numeric UID.\n",
80 "Specify the IP address on which your server will run. If you leave this\n"
81 "blank, or if you specify 0.0.0.0, Citadel will listen on all addresses.\n"
82 "You can usually skip this unless you're running multiple instances of\n"
83 "Citadel on the same computer.\n",
85 "Specify the TCP port number on which your server will run. Normally, this\n"
86 "will be port 504, which is the official port assigned by the IANA for\n"
87 "Citadel servers. You'll only need to specify a different port number if\n"
88 "you run multiple instances of Citadel on the same computer and there's\n"
89 "something else already using port 504.\n",
91 "Setup has detected that you currently have data files from a Citadel\n"
92 "version 3.2x installation. The program 'conv_32_40' can upgrade your\n"
93 "files to version 4.0x format.\n"
94 " Setup will now exit. Please either run 'conv_32_40' or delete your data\n"
95 "files, and run setup again.\n"
103 * Set an entry in inittab to the desired state
105 void set_init_entry(char *which_entry, char *new_state) {
106 char *inittab = NULL;
114 if (which_entry == NULL) return;
115 if (strlen(which_entry) == 0) return;
117 inittab = strdup("");
118 if (inittab == NULL) return;
120 fp = fopen("/etc/inittab", "r");
121 if (fp == NULL) return;
123 while(fgets(buf, sizeof buf, fp) != NULL) {
125 if (num_tokens(buf, ':') == 4) {
126 extract_token(entry, buf, 0, ':');
127 extract_token(levels, buf, 1, ':');
128 extract_token(state, buf, 2, ':');
129 extract_token(prog, buf, 3, ':'); /* includes 0x0a LF */
131 if (!strcmp(entry, which_entry)) {
132 strcpy(state, new_state);
133 sprintf(buf, "%s:%s:%s:%s",
134 entry, levels, state, prog);
138 inittab = realloc(inittab, strlen(inittab) + strlen(buf) + 2);
139 if (inittab == NULL) {
144 strcat(inittab, buf);
147 fp = fopen("/etc/inittab", "w");
149 fwrite(inittab, strlen(inittab), 1, fp);
151 kill(1, SIGHUP); /* Tell init to re-read /etc/inittab */
158 * Locate the name of an inittab entry for a specific program
160 void locate_init_entry(char *init_entry, char *program) {
165 char looking_for[SIZ];
169 strcpy(init_entry, "");
171 /* Pound through /etc/inittab line by line. Set have_entry to 1 if
172 * an entry is found which we believe starts the specified program.
174 infp = fopen("/etc/inittab", "r");
178 while (fgets(buf, sizeof buf, infp) != NULL) {
179 buf[strlen(buf) - 1] = 0;
180 extract_token(entry, buf, 0, ':');
181 extract_token(prog, buf, 3, ':');
182 if (!strncasecmp(prog, looking_for,
183 strlen(looking_for))) {
185 strcpy(init_entry, entry);
195 * Shut down the Citadel service if necessary, during setup.
197 void shutdown_citserver(void) {
198 char looking_for[SIZ];
200 snprintf(looking_for, sizeof looking_for, "%s/citserver", BBSDIR);
201 locate_init_entry(citserver_init_entry, looking_for);
202 if (strlen(citserver_init_entry) > 0) {
203 set_init_entry(citserver_init_entry, "off");
209 * Start the Citadel service.
211 void start_citserver(void) {
212 if (strlen(citserver_init_entry) > 0) {
213 set_init_entry(citserver_init_entry, "respawn");
219 void cleanup(int exitcode)
231 void title(char *text)
233 if (setup_type == UI_TEXT) {
234 printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<%s>\n", text);
240 int yesno(char *question)
243 newtComponent form = NULL;
244 newtComponent yesbutton = NULL;
245 newtComponent nobutton = NULL;
247 int prompt_window_height = 0;
252 switch (setup_type) {
256 printf("%s\nYes/No --> ", question);
257 fgets(buf, sizeof buf, stdin);
258 answer = tolower(buf[0]);
261 else if (answer == 'n')
263 } while ((answer < 0) || (answer > 1));
268 prompt_window_height = num_tokens(question, '\n') + 5;
269 newtCenteredWindow(76, prompt_window_height, "Question");
270 form = newtForm(NULL, NULL, 0);
271 for (i=0; i<num_tokens(question, '\n'); ++i) {
272 extract_token(buf, question, i, '\n');
273 newtFormAddComponent(form, newtLabel(1, 1+i, buf));
275 yesbutton = newtButton(10, (prompt_window_height - 4), "Yes");
276 nobutton = newtButton(60, (prompt_window_height - 4), "No");
277 newtFormAddComponent(form, yesbutton);
278 newtFormAddComponent(form, nobutton);
279 if (newtRunForm(form) == yesbutton) {
286 newtFormDestroy(form);
296 void important_message(char *title, char *msgtext)
299 newtComponent form = NULL;
304 switch (setup_type) {
307 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");
308 printf(" %s \n\n%s\n\n", title, msgtext);
309 printf("Press return to continue...");
310 fgets(buf, sizeof buf, stdin);
315 newtCenteredWindow(76, 10, title);
316 form = newtForm(NULL, NULL, 0);
317 for (i=0; i<num_tokens(msgtext, '\n'); ++i) {
318 extract_token(buf, msgtext, i, '\n');
319 newtFormAddComponent(form, newtLabel(1, 1+i, buf));
321 newtFormAddComponent(form, newtButton(35, 5, "OK"));
324 newtFormDestroy(form);
331 void important_msgnum(int msgnum)
333 important_message("Important Message", setup_text[msgnum]);
336 void display_error(char *error_message)
338 important_message("Error", error_message);
341 void progress(char *text, long int curr, long int cmax)
345 /* These variables are static because progress() gets called
346 * multiple times during the course of whatever operation is
347 * being performed. This makes setup non-threadsafe, but who
350 static newtComponent form = NULL;
351 static newtComponent scale = NULL;
353 static long dots_printed = 0L;
356 switch (setup_type) {
360 printf("%s\n", text);
361 printf("..........................");
362 printf("..........................");
363 printf("..........................\r");
366 } else if (curr == cmax) {
367 printf("\r%79s\n", "");
369 a = (curr * 100) / cmax;
372 while (dots_printed < a) {
383 newtCenteredWindow(76, 8, text);
384 form = newtForm(NULL, NULL, 0);
385 scale = newtScale(1, 3, 74, cmax);
386 newtFormAddComponent(form, scale);
390 if ((curr > 0) && (curr <= cmax)) {
391 newtScaleSet(scale, curr);
395 newtFormDestroy(form);
408 * check_services_entry() -- Make sure "citadel" is in /etc/services
411 void check_services_entry(void)
416 if (getservbyname(SERVICE_NAME, PROTO_NAME) == NULL) {
417 for (i=0; i<3; ++i) {
418 progress("Adding service entry...", i, 3);
420 sfp = fopen("/etc/services", "a");
422 display_error(strerror(errno));
424 fprintf(sfp, "%s 504/tcp\n",
436 * Generate a unique entry name for a new inittab entry
438 void generate_entry_name(char *entryname) {
441 snprintf(entryname, sizeof entryname, "c0");
444 if (entryname[1] > '9') {
447 if (entryname[0] > 'z') {
449 "Can't generate a unique entry name");
453 snprintf(buf, sizeof buf,
454 "grep %s: /etc/inittab >/dev/null 2>&1", entryname);
455 } while (system(buf) == 0);
461 * check_inittab_entry() -- Make sure "citadel" is in /etc/inittab
464 void check_inittab_entry(void)
467 char looking_for[SIZ];
471 /* Determine the fully qualified path name of citserver */
472 snprintf(looking_for, sizeof looking_for, "%s/citserver", BBSDIR);
473 locate_init_entry(citserver_init_entry, looking_for);
475 /* If there's already an entry, then we have nothing left to do. */
476 if (strlen(citserver_init_entry) > 0) {
480 /* Otherwise, prompt the user to create an entry. */
481 snprintf(question, sizeof question,
482 "Do you want this computer configured to start the Citadel\n"
483 "service automatically? (If you answer yes, an entry in\n"
484 "/etc/inittab pointing to %s will be added.)\n",
486 if (yesno(question) == 0)
489 /* Generate a unique entry name for /etc/inittab */
490 generate_entry_name(entryname);
492 /* Now write it out to /etc/inittab */
493 infp = fopen("/etc/inittab", "a");
495 display_error(strerror(errno));
497 fprintf(infp, "# Start the Citadel server...\n");
498 fprintf(infp, "%s:2345:respawn:%s -h%s -x3 -llocal4\n",
499 entryname, looking_for, setup_directory);
501 strcpy(citserver_init_entry, entryname);
507 * On systems which use xinetd, see if we can offer to install Citadel as
508 * the default telnet target.
510 void check_xinetd_entry(void) {
511 char *filename = "/etc/xinetd.d/telnet";
514 int already_citadel = 0;
516 fp = fopen(filename, "r+");
517 if (fp == NULL) return; /* Not there. Oh well... */
519 while (fgets(buf, sizeof buf, fp) != NULL) {
520 if (strstr(buf, setup_directory) != NULL) already_citadel = 1;
523 if (already_citadel) return; /* Already set up this way. */
525 /* Otherwise, prompt the user to create an entry. */
526 snprintf(buf, sizeof buf,
527 "Setup can configure the 'xinetd' service to automatically\n"
528 "connect incoming telnet sessions to Citadel, bypassing the\n"
529 "host system's login prompt. Would you like to do this?\n"
534 fp = fopen(filename, "w");
536 "# description: telnet service for Citadel users\n"
541 " socket_type = stream\n"
544 " server = /usr/sbin/in.telnetd\n"
545 " server_args = -h -L %s/citadel\n"
546 " log_on_failure += USERID\n"
552 /* Now try to restart the service */
553 system("/etc/init.d/xinetd restart >/dev/null 2>&1");
559 * Offer to disable other MTA's
561 void disable_other_mta(char *mta) {
566 sprintf(buf, "/bin/ls -l /etc/rc*.d/S*%s 2>/dev/null", mta);
567 fp = popen(buf, "r");
568 if (fp == NULL) return;
570 while (fgets(buf, sizeof buf, fp) != NULL) {
574 if (lines == 0) return; /* Nothing to do. */
576 /* Offer to replace other MTA with the vastly superior Citadel :) */
577 snprintf(buf, sizeof buf,
578 "You appear to have the '%s' email program\n"
579 "running on your system. Would you like to disable it,\n"
580 "allowing Citadel to handle your system's Internet mail\n"
587 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);
589 sprintf(buf, "/etc/init.d/%s stop >/dev/null 2>&1", mta);
597 * Check to see if our server really works. Returns 0 on success.
599 int test_server(void) {
606 /* Generate a silly little cookie. We're going to write it out
607 * to the server and try to get it back. The cookie does not
608 * have to be secret ... just unique.
610 sprintf(cookie, "%ld.%d", time(NULL), getpid());
612 sprintf(cmd, "%s/sendcommand -h%s ECHO %s 2>&1",
617 fp = popen(cmd, "r");
618 if (fp == NULL) return(errno);
620 while (fgets(buf, sizeof buf, fp) != NULL) {
622 && (strstr(buf, cookie) != NULL) ) {
634 void strprompt(char *prompt_title, char *prompt_text, char *str)
640 int prompt_window_height = 0;
645 strcpy(setupmsg, "");
647 switch (setup_type) {
650 printf("\n%s\n", prompt_text);
651 printf("This is currently set to:\n%s\n", str);
652 printf("Enter new value or press return to leave unchanged:\n");
653 fgets(buf, sizeof buf, stdin);
654 buf[strlen(buf) - 1] = 0;
655 if (strlen(buf) != 0)
661 prompt_window_height = num_tokens(prompt_text, '\n') + 5 ;
662 newtCenteredWindow(76,
663 prompt_window_height,
665 form = newtForm(NULL, NULL, 0);
666 for (i=0; i<num_tokens(prompt_text, '\n'); ++i) {
667 extract_token(buf, prompt_text, i, '\n');
668 newtFormAddComponent(form, newtLabel(1, 1+i, buf));
670 newtFormAddComponent(form,
672 (prompt_window_height - 2),
676 NEWT_FLAG_RETURNEXIT)
682 newtFormDestroy(form);
688 void set_str_val(int msgpos, char *str) {
689 strprompt(setup_titles[msgpos], setup_text[msgpos], str);
694 void set_int_val(int msgpos, int *ip)
697 snprintf(buf, sizeof buf, "%d", (int) *ip);
698 set_str_val(msgpos, buf);
703 void set_char_val(int msgpos, char *ip)
706 snprintf(buf, sizeof buf, "%d", (int) *ip);
707 set_str_val(msgpos, buf);
708 *ip = (char) atoi(buf);
712 void set_long_val(int msgpos, long int *ip)
715 snprintf(buf, sizeof buf, "%ld", *ip);
716 set_str_val(msgpos, buf);
721 void edit_value(int curr)
725 char bbsuidname[SIZ];
730 set_str_val(curr, config.c_sysadm);
735 config.c_bbsuid = 0; /* XXX Windows hack, prob. insecure */
740 set_int_val(curr, &i);
744 strcpy(bbsuidname, pw->pw_name);
745 set_str_val(curr, bbsuidname);
746 pw = getpwnam(bbsuidname);
748 config.c_bbsuid = pw->pw_uid;
750 else if (atoi(bbsuidname) > 0) {
751 config.c_bbsuid = atoi(bbsuidname);
758 set_str_val(curr, config.c_ip_addr);
762 set_int_val(curr, &config.c_port_number);
770 * (re-)write the config data to disk
772 void write_config_to_disk(void)
777 if ((fd = creat("citadel.config", S_IRUSR | S_IWUSR)) == -1) {
778 display_error("setup: cannot open citadel.config");
781 fp = fdopen(fd, "wb");
783 display_error("setup: cannot open citadel.config");
786 fwrite((char *) &config, sizeof(struct config), 1, fp);
794 * Figure out what type of user interface we're going to use
796 int discover_ui(void)
802 newtDrawRootText(0, 0, "Citadel Setup");
812 int main(int argc, char *argv[])
818 int old_setup_level = 0;
820 struct utsname my_utsname;
825 /* set an invalid setup type */
828 /* Check to see if we're running the web installer */
829 if (getenv("CITADEL_INSTALLER") != NULL) {
830 using_web_installer = 1;
833 /* parse command line args */
834 for (a = 0; a < argc; ++a) {
835 if (!strncmp(argv[a], "-u", 2)) {
836 strcpy(aaa, argv[a]);
837 strcpy(aaa, &aaa[2]);
838 setup_type = atoi(aaa);
840 if (!strcmp(argv[a], "-i")) {
843 if (!strcmp(argv[a], "-q")) {
844 setup_type = UI_SILENT;
849 /* If a setup type was not specified, try to determine automatically
850 * the best one to use out of all available types.
852 if (setup_type < 0) {
853 setup_type = discover_ui();
855 if (info_only == 1) {
856 important_message("Citadel Setup", CITADEL);
860 /* Get started in a valid setup directory. */
861 strcpy(setup_directory, BBSDIR);
862 if ( (using_web_installer) && (getenv("CITADEL") != NULL) ) {
863 strcpy(setup_directory, getenv("CITADEL"));
866 set_str_val(0, setup_directory);
869 if (chdir(setup_directory) != 0) {
870 important_message("Citadel Setup",
871 "The directory you specified does not exist.");
875 /* Determine our host name, in case we need to use it as a default */
878 /* See if we need to shut down the Citadel service. */
879 for (a=0; a<=3; ++a) {
880 progress("Shutting down the Citadel service...", a, 3);
881 if (a == 0) shutdown_citserver();
885 /* Make sure it's stopped. */
886 if (test_server() == 0) {
887 important_message("Citadel Setup",
888 "The Citadel service is still running.\n"
889 "Please stop the service manually and run "
895 switch (setup_type) {
899 " *** Citadel setup program ***\n\n");
905 * What we're going to try to do here is append a whole bunch of
906 * nulls to the citadel.config file, so we can keep the old config
907 * values if they exist, but if the file is missing or from an
908 * earlier version with a shorter config structure, when setup tries
909 * to read the old config parameters, they'll all come up zero.
910 * The length of the config file will be set to what it's supposed
911 * to be when we rewrite it, because we replace the old file with a
912 * completely new copy.
915 if ((a = open("citadel.config", O_WRONLY | O_CREAT | O_APPEND,
916 S_IRUSR | S_IWUSR)) == -1) {
917 display_error("setup: cannot append citadel.config");
920 fp = fdopen(a, "ab");
922 display_error("setup: cannot append citadel.config");
925 for (a = 0; a < sizeof(struct config); ++a)
929 /* now we re-open it, and read the old or blank configuration */
930 fp = fopen("citadel.config", "rb");
932 display_error("setup: cannot open citadel.config");
935 fread((char *) &config, sizeof(struct config), 1, fp);
938 /* set some sample/default values in place of blanks... */
939 if (strlen(config.c_nodename) == 0)
940 safestrncpy(config.c_nodename, my_utsname.nodename,
941 sizeof config.c_nodename);
942 strtok(config.c_nodename, ".");
943 if (strlen(config.c_fqdn) == 0) {
944 if ((he = gethostbyname(my_utsname.nodename)) != NULL)
945 safestrncpy(config.c_fqdn, he->h_name,
946 sizeof config.c_fqdn);
948 safestrncpy(config.c_fqdn, my_utsname.nodename,
949 sizeof config.c_fqdn);
951 if (strlen(config.c_humannode) == 0)
952 strcpy(config.c_humannode, "My System");
953 if (strlen(config.c_phonenum) == 0)
954 strcpy(config.c_phonenum, "US 800 555 1212");
955 if (config.c_initax == 0) {
958 if (strlen(config.c_moreprompt) == 0)
959 strcpy(config.c_moreprompt, "<more>");
960 if (strlen(config.c_twitroom) == 0)
961 strcpy(config.c_twitroom, "Trashcan");
962 if (strlen(config.c_baseroom) == 0)
963 strcpy(config.c_baseroom, "Lobby");
964 if (strlen(config.c_aideroom) == 0)
965 strcpy(config.c_aideroom, "Aide");
966 if (config.c_port_number == 0) {
967 config.c_port_number = 504;
969 if (config.c_sleeping == 0) {
970 config.c_sleeping = 900;
972 if (config.c_bbsuid == 0) {
973 pw = getpwnam("citadel");
975 config.c_bbsuid = pw->pw_uid;
977 if (config.c_bbsuid == 0) {
978 pw = getpwnam("bbs");
980 config.c_bbsuid = pw->pw_uid;
982 if (config.c_bbsuid == 0) {
983 pw = getpwnam("guest");
985 config.c_bbsuid = pw->pw_uid;
987 if (config.c_createax == 0) {
988 config.c_createax = 3;
991 * Negative values for maxsessions are not allowed.
993 if (config.c_maxsessions < 0) {
994 config.c_maxsessions = 0;
996 /* We need a system default message expiry policy, because this is
997 * the top level and there's no 'higher' policy to fall back on.
999 if (config.c_ep.expire_mode == 0) {
1000 config.c_ep.expire_mode = EXPIRE_NUMMSGS;
1001 config.c_ep.expire_value = 150;
1005 * Default port numbers for various services
1007 if (config.c_smtp_port == 0) config.c_smtp_port = 25;
1008 if (config.c_pop3_port == 0) config.c_pop3_port = 110;
1009 if (config.c_imap_port == 0) config.c_imap_port = 143;
1011 /* Go through a series of dialogs prompting for config info */
1012 if (setup_type != UI_SILENT) {
1013 for (curr = 1; curr <= MAXSETUP; ++curr) {
1019 if (setuid(config.c_bbsuid) != 0) {
1020 important_message("Citadel Setup",
1021 "Failed to change the user ID to your Citadel user.");
1026 /***** begin version update section ***** */
1027 /* take care of any updating that is necessary */
1029 old_setup_level = config.c_setup_level;
1031 if (old_setup_level == 0) {
1035 if (old_setup_level < 555) {
1036 important_message("Citadel Setup",
1037 "This Citadel installation is too old "
1041 write_config_to_disk();
1043 old_setup_level = config.c_setup_level;
1045 /* end of version update section */
1048 config.c_setup_level = REV_LEVEL;
1050 /******************************************/
1052 write_config_to_disk();
1054 mkdir("info", 0700);
1055 chmod("info", 0700);
1058 mkdir("userpics", 0700);
1059 chmod("userpics", 0700);
1060 mkdir("messages", 0700);
1061 chmod("messages", 0700);
1062 mkdir("help", 0700);
1063 chmod("help", 0700);
1064 mkdir("images", 0700);
1065 chmod("images", 0700);
1066 mkdir("netconfigs", 0700);
1067 chmod("netconfigs", 0700);
1069 /* Delete files and directories used by older Citadel versions */
1070 system("exec /bin/rm -fr ./rooms ./chatpipes ./expressmsgs ./sessions 2>/dev/null");
1071 unlink("citadel.log");
1074 check_services_entry(); /* Check /etc/services */
1076 check_inittab_entry(); /* Check /etc/inittab */
1077 check_xinetd_entry(); /* Check /etc/xinetd.d/telnet */
1079 /* Offer to disable other MTA's on the system. */
1080 disable_other_mta("sendmail");
1081 disable_other_mta("postfix");
1082 disable_other_mta("qmail");
1083 disable_other_mta("cyrus");
1084 disable_other_mta("cyrmaster");
1085 disable_other_mta("saslauthd");
1086 disable_other_mta("mta");
1087 disable_other_mta("courier-imap");
1088 disable_other_mta("courier-imap-ssl");
1089 disable_other_mta("courier-authdaemon");
1090 disable_other_mta("courier-pop3");
1091 disable_other_mta("courier-pop3d");
1092 disable_other_mta("courier-pop");
1093 disable_other_mta("vmailmgrd");
1094 disable_other_mta("imapd");
1095 disable_other_mta("popd");
1096 disable_other_mta("pop3d");
1097 disable_other_mta("exim");
1100 if ((pw = getpwuid(config.c_bbsuid)) == NULL)
1105 progress("Setting file permissions", 0, 4);
1106 chown(".", config.c_bbsuid, gid);
1107 progress("Setting file permissions", 1, 4);
1108 chown("citadel.config", config.c_bbsuid, gid);
1109 progress("Setting file permissions", 2, 4);
1110 snprintf(aaa, sizeof aaa,
1111 "find . | grep -v chkpwd | xargs chown %ld:%ld 2>/dev/null",
1112 (long)config.c_bbsuid, (long)gid);
1114 progress("Setting file permissions", 3, 4);
1115 chmod("citadel.config", S_IRUSR | S_IWUSR);
1116 progress("Setting file permissions", 4, 4);
1119 /* Contemplate the possibility of auto-configuring OpenLDAP */
1123 /* See if we can start the Citadel service. */
1124 if (strlen(citserver_init_entry) > 0) {
1125 for (a=0; a<=3; ++a) {
1126 progress("Starting the Citadel service...", a, 3);
1127 if (a == 0) start_citserver();
1130 if (test_server() == 0) {
1131 important_message("Setup finished",
1132 "Setup is finished. You may now log in.");
1135 important_message("Setup finished",
1136 "Setup is finished, but the Citadel service "
1137 "failed to start.\n"
1138 "Go back and check your configuration.");
1142 important_message("Setup finished",
1143 "Setup is finished. You may now start the server.");
1153 * If we're in the middle of an Easy Install, we might just be able to
1154 * auto-configure a standalone OpenLDAP server.
1156 void contemplate_ldap(void) {
1158 char slapd_init_entry[SIZ];
1161 /* If conditions are not ideal, give up on this idea. */
1162 if (using_web_installer == 0) return;
1163 if (getenv("LDAP_CONFIG") == NULL) return;
1164 if (getenv("SUPPORT") == NULL) return;
1165 if (getenv("SLAPD_BINARY") == NULL) return;
1166 if (getenv("CITADEL") == NULL) return;
1168 /* Otherwise, prompt the user to create an entry. */
1169 snprintf(question, sizeof question,
1171 "Do you want this computer configured to start a standalone\n"
1172 "LDAP service automatically? (If you answer yes, a custom\n"
1173 "slapd.conf will be written, and an /etc/inittab entry\n"
1174 "pointing to %s will be added.)\n"
1176 getenv("SLAPD_BINARY")
1178 if (yesno(question) == 0)
1181 strcpy(config.c_ldap_base_dn, "dc=example,dc=com");
1182 strprompt("Base DN",
1184 "Please enter the Base DN for your directory. This will\n"
1185 "generally be something based on the primary DNS domain in\n"
1186 "which you receive mail, but it doesn't have to be. Your\n"
1187 "LDAP tree will be built using this Distinguished Name.\n"
1189 config.c_ldap_base_dn
1192 strcpy(config.c_ldap_host, "localhost");
1193 config.c_ldap_port = 389;
1194 sprintf(config.c_ldap_bind_dn, "cn=manager,%s", config.c_ldap_base_dn);
1196 /* FIXME ... make the generated password harder to guess */
1197 sprintf(config.c_ldap_bind_pw, "%d%ld", getpid(), time(NULL));
1199 write_config_to_disk();
1201 fp = fopen(getenv("LDAP_CONFIG"), "w");
1203 sprintf(question, "\nCannot create %s:\n%s\n\n"
1204 "Citadel will still function, but you will "
1205 "not have an LDAP service.\n\n",
1206 getenv("LDAP_CONFIG"),
1209 important_message("Error", question);
1213 fprintf(fp, "include %s/citadel-openldap.schema\n",
1215 fprintf(fp, "pidfile %s/openldap-data/slapd.pid\n",
1217 fprintf(fp, "argsfile %s/openldap-data/slapd.args\n",
1219 fprintf(fp, "allow bind_v2\n"
1223 fprintf(fp, "suffix \"%s\"\n", config.c_ldap_base_dn);
1224 fprintf(fp, "rootdn \"%s\"\n", config.c_ldap_bind_dn);
1225 fprintf(fp, "rootpw %s\n", config.c_ldap_bind_pw);
1226 fprintf(fp, "directory %s/openldap-data\n",
1228 fprintf(fp, "index objectClass eq\n");
1232 /* This is where our OpenLDAP server will keep its data. */
1233 mkdir("openldap-data", 0700);
1235 /* If inittab is already starting slapd, disable the old entry. */
1236 locate_init_entry(slapd_init_entry, getenv("SLAPD_BINARY"));
1237 if (strlen(slapd_init_entry) > 0) {
1238 set_init_entry(slapd_init_entry, "off");
1241 /* Generate a unique entry name for slapd */
1242 generate_entry_name(slapd_init_entry);
1244 /* Now write it out to /etc/inittab.
1245 * FIXME make it run as some non-root user.
1246 * The "-d 0" seems superfluous, but it's actually a way to make
1247 * slapd run in the foreground without spewing messages to the console.
1249 fp = fopen("/etc/inittab", "a");
1251 display_error(strerror(errno));
1253 fprintf(fp, "# Start the OpenLDAP server for Citadel...\n");
1254 fprintf(fp, "%s:2345:respawn:%s -d 0 -f %s\n",
1256 getenv("SLAPD_BINARY"),
1257 getenv("LDAP_CONFIG")
1263 #endif /* HAVE_LDAP */