2 * Citadel setup utility
5 #define SHOW_ME_VAPPEND_PRINTF
6 #include "ctdl_module.h"
13 #include <sys/types.h>
15 #include <sys/utsname.h>
23 #include <libcitadel.h>
28 #include "citadel_dirs.h"
39 #define _(string) gettext(string)
41 #define _(string) (string)
45 #define MAXSETUP 11 /* How many setup questions to ask */
47 #define UI_TEXT 0 /* Default setup type -- text only */
48 #define UI_DIALOG 2 /* Use the 'dialog' program */
49 #define UI_SILENT 3 /* Silent running, for use in scripts */
51 #define SERVICE_NAME "citadel"
52 #define PROTO_NAME "tcp"
53 #define NSSCONF "/etc/nsswitch.conf"
56 typedef enum _SetupStep {
72 ///"CREATE_XINETD_ENTRY";
73 /* Environment variables, don't translate! */
74 const char *EnvNames [eMaxQuestions] = {
90 int using_web_installer = 0;
95 const char *setup_titles[eMaxQuestions];
96 const char *setup_text[eMaxQuestions];
98 /* calculate all our path on a central place */
99 /* where to keep our config */
111 setup_titles[eCitadelHomeDir] = _("Citadel Home Directory");
113 setup_text[eCitadelHomeDir] = _(
114 "Enter the full pathname of the directory in which the Citadel\n"
115 "installation you are creating or updating resides. If you\n"
116 "specify a directory other than the default, you will need to\n"
117 "specify the -h flag to the server when you start it up.\n");
119 setup_text[eCitadelHomeDir] = _(
120 "Enter the subdirectory name for an alternate installation of "
121 "Citadel. To do a default installation just leave it blank."
122 "If you specify a directory other than the default, you will need to\n"
123 "specify the -h flag to the server when you start it up.\n"
124 "note that it may not have a leading /");
127 setup_titles[eSysAdminName] = _("Citadel administrator username:");
128 setup_text[eSysAdminName] = _(
129 "Please enter the name of the Citadel user account that should be granted "
130 "administrative privileges once created. If using internal authentication "
131 "this user account will be created if it does not exist. For external "
132 "authentication this user account has to exist.");
135 setup_titles[eSysAdminPW] = _("Administrator password:");
136 setup_text[eSysAdminPW] = _(
137 "Enter a password for the system administrator. When setup\n"
138 "completes it will attempt to create the administrator user\n"
139 "and set the password specified here.\n");
141 setup_titles[eUID] = _("Citadel User ID:");
142 setup_text[eUID] = _(
143 "Citadel needs to run under its own user ID. This would\n"
144 "typically be called \"citadel\", but if you are running Citadel\n"
145 "as a public BBS, you might also call it \"bbs\" or \"guest\".\n"
146 "The server will run under this user ID. Please specify that\n"
147 "user ID here. You may specify either a user name or a numeric\n"
150 setup_titles[eIP_ADDR] = _("Listening address for the Citadel server:");
151 setup_text[eIP_ADDR] = _(
152 "Please specify the IP address which the server should be listening to. "
153 "You can name a specific IPv4 or IPv6 address, or you can specify\n"
154 "'*' for 'any address', '::' for 'any IPv6 address', or '0.0.0.0'\n"
155 "for 'any IPv4 address'. If you leave this blank, Citadel will\n"
156 "listen on all addresses. "
157 "This can usually be left to the default unless multiple instances of Citadel "
158 "are running on the same computer.");
160 setup_titles[eCTDL_Port] = _("Server port number:");
161 setup_text[eCTDL_Port] = _(
162 "Specify the TCP port number on which your server will run.\n"
163 "Normally, this will be port 504, which is the official port\n"
164 "assigned by the IANA for Citadel servers. You will only need\n"
165 "to specify a different port number if you run multiple instances\n"
166 "of Citadel on the same computer and there is something else\n"
167 "already using port 504.\n");
169 setup_titles[eAuthType] = _("Authentication method to use:");
170 setup_text[eAuthType] = _(
171 "Please choose the user authentication mode. By default Citadel will use its "
172 "own internal user accounts database. If you choose Host, Citadel users will "
173 "have accounts on the host system, authenticated via /etc/passwd or a PAM "
174 "source. LDAP chooses an RFC 2307 compliant directory server, the last option "
175 "chooses the nonstandard MS Active Directory LDAP scheme."
177 "Do not change this option unless you are sure it is required, since changing "
178 "back requires a full reinstall of Citadel."
180 " 0. Self contained authentication\n"
181 " 1. Host system integrated authentication\n"
182 " 2. External LDAP - RFC 2307 compliant directory\n"
183 " 3. External LDAP - nonstandard MS Active Directory\n"
185 "For help: http://www.citadel.org/doku.php/faq:installation:authmodes\n"
187 "ANSWER \"0\" UNLESS YOU COMPLETELY UNDERSTAND THIS OPTION.\n");
189 setup_titles[eLDAP_Host] = _("LDAP host:");
190 setup_text[eLDAP_Host] = _(
191 "Please enter the host name or IP address of your LDAP server.\n");
193 setup_titles[eLDAP_Port] = _("LDAP port number:");
194 setup_text[eLDAP_Port] = _(
195 "Please enter the port number of the LDAP service (usually 389).\n");
197 setup_titles[eLDAP_Base_DN] = _("LDAP base DN:");
198 setup_text[eLDAP_Base_DN] = _(
199 "Please enter the Base DN to search for authentication\n"
200 "(for example: dc=example,dc=com)\n");
202 setup_titles[eLDAP_Bind_DN] = _("LDAP bind DN:");
203 setup_text[eLDAP_Bind_DN] = _(
204 "Please enter the DN of an account to use for binding to the LDAP server for "
205 "performing queries. The account does not require any other privileges. If "
206 "your LDAP server allows anonymous queries, you can leave this blank."
207 "Please enter the DN of an account to use for binding to the LDAP server\n"
208 "for performing queries. The account does not require any other\n"
209 "privileges. If your LDAP server allows anonymous queries, you can\n"
210 "leave this blank.\n");
212 setup_titles[eLDAP_Bind_PW] = _("LDAP bind password:");
213 setup_text[eLDAP_Bind_PW] = _(
214 "If you entered a Bind DN in the previous question, you must now enter\n"
215 "the password associated with that account. Otherwise, you can leave this\n"
220 * print the actual stack frame.
222 void cit_backtrace(void)
224 #ifdef HAVE_BACKTRACE
225 void *stack_frames[50];
229 size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
230 strings = backtrace_symbols(stack_frames, size);
231 for (i = 0; i < size; i++) {
233 fprintf(stderr, "%s\n", strings[i]);
235 fprintf(stderr, "%p\n", stack_frames[i]);
241 struct config config;
244 struct config config;
248 void cleanup(int exitcode)
250 // printf("Exitcode: %d\n", exitcode);
257 void title(const char *text)
259 if (setup_type == UI_TEXT) {
260 printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<%s>\n", text);
266 int yesno(const char *question, int default_value)
272 switch (setup_type) {
276 printf("%s\nYes/No [%s] --> ",
278 ( default_value ? "Yes" : "No" )
280 if (fgets(buf, sizeof buf, stdin))
282 answer = tolower(buf[0]);
283 if ((buf[0]==0) || (buf[0]==13) || (buf[0]==10))
284 answer = default_value;
285 else if (answer == 'y')
287 else if (answer == 'n')
290 } while ((answer < 0) || (answer > 1));
294 sprintf(buf, "exec %s %s --yesno '%s' 15 75",
295 getenv("CTDL_DIALOG"),
296 ( default_value ? "" : "--defaultno" ),
314 void important_message(const char *title, const char *msgtext)
319 switch (setup_type) {
322 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");
323 printf(" %s \n\n%s\n\n", title, msgtext);
324 printf("Press return to continue...");
325 if (fgets(buf, sizeof buf, stdin));
329 sprintf(buf, "exec %s --msgbox '%s' 19 72",
330 getenv("CTDL_DIALOG"),
335 fprintf(stderr, "%s\n", msgtext);
340 void important_msgnum(int msgnum)
342 important_message("Important Message", setup_text[msgnum]);
345 void display_error(char *error_message)
347 important_message("Error", error_message);
350 void progress(char *text, long int curr, long int cmax)
352 static long dots_printed = 0L;
354 static FILE *fp = NULL;
357 switch (setup_type) {
361 printf("%s\n", text);
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) {
382 sprintf(buf, "exec %s --gauge '%s' 7 72 0",
383 getenv("CTDL_DIALOG"),
385 fp = popen(buf, "w");
391 else if (curr == cmax) {
393 fprintf(fp, "100\n");
399 a = (curr * 100) / cmax;
401 fprintf(fp, "%ld\n", a);
415 * check_services_entry() -- Make sure "citadel" is in /etc/services
418 void check_services_entry(void)
424 if (getservbyname(SERVICE_NAME, PROTO_NAME) == NULL) {
425 for (i=0; i<=2; ++i) {
426 progress("Adding service entry...", i, 2);
428 sfp = fopen("/etc/services", "a");
430 sprintf(errmsg, "Cannot open /etc/services: %s", strerror(errno));
431 display_error(errmsg);
433 fprintf(sfp, "%s 504/tcp\n", SERVICE_NAME);
445 * delete_inittab_entry() -- Remove obsolete /etc/inittab entry for Citadel
447 void delete_inittab_entry(void)
451 char looking_for[256];
453 char outfilename[32];
454 int changes_made = 0;
457 /* Determine the fully qualified path name of citserver */
458 snprintf(looking_for,
464 /* Now tweak /etc/inittab */
465 infp = fopen("/etc/inittab", "r");
468 /* If /etc/inittab does not exist, return quietly.
469 * Not all host platforms have it.
471 if (errno == ENOENT) {
475 /* Other errors might mean something really did go wrong.
477 sprintf(buf, "Cannot open /etc/inittab: %s", strerror(errno));
482 strcpy(outfilename, "/tmp/ctdlsetup.XXXXXX");
483 outfp = fdopen(mkstemp(outfilename), "w+");
485 sprintf(buf, "Cannot open %s: %s", outfilename, strerror(errno));
491 while (fgets(buf, sizeof buf, infp) != NULL) {
492 if (strstr(buf, looking_for) != NULL) {
493 rv = fwrite("#", 1, 1, outfp);
496 rv = fwrite(buf, strlen(buf), 1, outfp);
503 sprintf(buf, "/bin/mv -f %s /etc/inittab 2>/dev/null", outfilename);
505 rv = system("/sbin/init q 2>/dev/null");
514 * install_init_scripts() -- Try to configure to start Citadel at boot
516 void install_init_scripts(void)
518 struct stat etcinitd;
520 char *initfile = "/etc/init.d/citadel";
524 if ((stat("/etc/init.d/", &etcinitd) == -1) &&
527 if ((stat("/etc/rc.d/init.d/", &etcinitd) == -1) &&
529 initfile = CTDLDIR"/citadel.init";
531 initfile = "/etc/rc.d/init.d/citadel";
534 fp = fopen(initfile, "r");
536 if (yesno("Citadel already appears to be configured to start at boot.\n"
537 "Would you like to keep your boot configuration as is?\n", 1) == 1) {
544 if (yesno("Would you like to automatically start Citadel at boot?\n", 1) == 0) {
548 fp = fopen(initfile, "w");
550 display_error("Cannot create /etc/init.d/citadel");
554 fprintf(fp, "#!/bin/sh\n"
556 "# Init file for Citadel\n"
558 "# chkconfig: - 79 30\n"
559 "# description: Citadel service\n"
560 "# processname: citserver\n"
561 "# pidfile: %s/citadel.pid\n\n"
562 "# uncomment this to create coredumps as described in\n"
563 "# http://www.citadel.org/doku.php/faq:mastering_your_os:gdb#how.do.i.make.my.system.produce.core-files\n"
564 "# ulimit -c unlimited\n"
572 "test -d /var/run || exit 0\n"
576 "start) echo -n \"Starting Citadel... \"\n"
577 " if $CITADEL_DIR/citserver -lmail -d\n"
584 "stop) echo -n \"Stopping Citadel... \"\n"
585 " if $CITADEL_DIR/sendcommand DOWN >/dev/null 2>&1 ; then\n"
590 " rm -f %s/citadel.pid 2>/dev/null\n"
595 "restart) if $CITADEL_DIR/sendcommand DOWN 1 >/dev/null 2>&1 ; then\n"
601 "*) echo \"Usage: $0 {start|stop|restart}\"\n"
608 chmod(initfile, 0755);
610 /* Set up the run levels. */
611 rv = system("/bin/rm -f /etc/rc?.d/[SK]??citadel 2>/dev/null");
612 snprintf(command, sizeof(command), "for x in 2 3 4 5 ; do [ -d /etc/rc$x.d ] && ln -s %s /etc/rc$x.d/S79citadel ; done 2>/dev/null", initfile);
613 rv = system(command);
614 snprintf(command, sizeof(command),"for x in 0 6 S; do [ -d /etc/rc$x.d ] && ln -s %s /etc/rc$x.d/K30citadel ; done 2>/dev/null", initfile);
615 rv = system(command);
622 * On systems which use xinetd, see if we can offer to install Citadel as
623 * the default telnet target.
625 void check_xinetd_entry(void) {
626 char *filename = "/etc/xinetd.d/telnet";
629 int already_citadel = 0;
632 fp = fopen(filename, "r+");
633 if (fp == NULL) return; /* Not there. Oh well... */
635 while (fgets(buf, sizeof buf, fp) != NULL) {
636 if (strstr(buf, "/citadel") != NULL) already_citadel = 1;
639 if (already_citadel) return; /* Already set up this way. */
641 /* Otherwise, prompt the user to create an entry. */
642 if (getenv("CREATE_XINETD_ENTRY") != NULL) {
643 if (strcasecmp(getenv("CREATE_XINETD_ENTRY"), "yes")) {
648 snprintf(buf, sizeof buf,
649 "Setup can configure the \"xinetd\" service to automatically\n"
650 "connect incoming telnet sessions to Citadel, bypassing the\n"
651 "host system login: prompt. Would you like to do this?\n"
653 if (yesno(buf, 1) == 0) {
658 fp = fopen(filename, "w");
660 "# description: telnet service for Citadel users\n"
665 " socket_type = stream\n"
668 " server = /usr/sbin/in.telnetd\n"
669 " server_args = -h -L %s/citadel\n"
670 " log_on_failure += USERID\n"
675 /* Now try to restart the service */
676 rv = system("/etc/init.d/xinetd restart >/dev/null 2>&1");
682 * Offer to disable other MTA's
684 void disable_other_mta(const char *mta) {
690 sprintf(buf, "/bin/ls -l /etc/rc*.d/S*%s 2>/dev/null; "
691 "/bin/ls -l /etc/rc.d/rc*.d/S*%s 2>/dev/null",
693 fp = popen(buf, "r");
694 if (fp == NULL) return;
696 while (fgets(buf, sizeof buf, fp) != NULL) {
700 if (lines == 0) return; /* Nothing to do. */
703 /* Offer to replace other MTA with the vastly superior Citadel :) */
705 snprintf(buf, sizeof buf,
706 "You appear to have the \"%s\" email program\n"
707 "running on your system. If you want Citadel mail\n"
708 "connected with %s, you will have to manually integrate\n"
709 "them. It is preferable to disable %s, and use Citadel's\n"
710 "SMTP, POP3, and IMAP services.\n\n"
711 "May we disable %s so that Citadel has access to ports\n"
712 "25, 110, and 143?\n",
715 if (yesno(buf, 1) == 0) {
720 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);
722 sprintf(buf, "/etc/init.d/%s stop >/dev/null 2>&1", mta);
726 const char *other_mtas[] = {
727 "courier-authdaemon",
750 void disable_other_mtas(void)
753 if ((getenv("ACT_AS_MTA") == NULL) ||
754 (getenv("ACT_AS_MTA") &&
755 strcasecmp(getenv("ACT_AS_MTA"), "yes") == 0)) {
756 /* Offer to disable other MTA's on the system. */
757 while (!IsEmptyStr(other_mtas[i]))
759 disable_other_mta(other_mtas[i]);
766 * Check to see if our server really works. Returns 0 on success.
768 int test_server(char *relhomestr, int relhome) {
775 /* Generate a silly little cookie. We're going to write it out
776 * to the server and try to get it back. The cookie does not
777 * have to be secret ... just unique.
779 sprintf(cookie, "--test--%d--", getpid());
782 sprintf(cmd, "%s/sendcommand -h%s ECHO %s 2>&1",
787 sprintf(cmd, "%s/sendcommand ECHO %s 2>&1",
791 fp = popen(cmd, "r");
792 if (fp == NULL) return(errno);
794 while (fgets(buf, sizeof buf, fp) != NULL) {
796 && (strstr(buf, cookie) != NULL) ) {
808 void strprompt(const char *prompt_title, const char *prompt_text, char *Target, char *DefValue)
812 char dialog_result[PATH_MAX];
816 strcpy(setupmsg, "");
818 switch (setup_type) {
821 printf("\n%s\n", prompt_text);
822 printf("This is currently set to:\n%s\n", Target);
823 printf("Enter new value or press return to leave unchanged:\n");
824 if (fgets(buf, sizeof buf, stdin)){
825 buf[strlen(buf) - 1] = 0;
827 if (!IsEmptyStr(buf))
832 CtdlMakeTempFileName(dialog_result, sizeof dialog_result);
833 sprintf(buf, "exec %s --inputbox '%s' 19 72 '%s' 2>%s",
834 getenv("CTDL_DIALOG"),
839 fp = fopen(dialog_result, "r");
841 if (fgets(Target, sizeof buf, fp)) {
842 if (Target[strlen(Target)-1] == 10) {
843 Target[strlen(Target)-1] = 0;
847 unlink(dialog_result);
851 strcpy(Target, DefValue);
856 void set_bool_val(int msgpos, int *ip, char *DefValue)
858 title(setup_titles[msgpos]);
859 *ip = yesno(setup_text[msgpos], *ip);
862 void set_str_val(int msgpos, char *Target, char *DefValue)
864 strprompt(setup_titles[msgpos],
870 void set_int_val(int msgpos, int *ip, char *DefValue)
873 snprintf(buf, sizeof buf, "%d", (int) *ip);
874 set_str_val(msgpos, buf, DefValue);
879 void set_char_val(int msgpos, char *ip, char *DefValue)
882 snprintf(buf, sizeof buf, "%d", (int) *ip);
883 set_str_val(msgpos, buf, DefValue);
884 *ip = (char) atoi(buf);
888 void set_long_val(int msgpos, long int *ip, char *DefValue)
891 snprintf(buf, sizeof buf, "%ld", *ip);
892 set_str_val(msgpos, buf, DefValue);
897 void edit_value(int curr)
901 char ctdluidname[256];
904 if (setup_type == UI_SILENT)
906 Value = getenv(EnvNames[curr]);
915 set_str_val(curr, config.c_sysadm, Value);
919 set_str_val(curr, admin_pass, Value);
923 if (setup_type == UI_SILENT)
926 config.c_ctdluid = atoi(Value);
932 config.c_ctdluid = 0; /* XXX Windows hack, prob. insecure */
934 i = config.c_ctdluid;
937 set_int_val(curr, &i, Value);
938 config.c_ctdluid = i;
941 strcpy(ctdluidname, pw->pw_name);
942 set_str_val(curr, ctdluidname, Value);
943 pw = getpwnam(ctdluidname);
945 config.c_ctdluid = pw->pw_uid;
947 else if (atoi(ctdluidname) > 0) {
948 config.c_ctdluid = atoi(ctdluidname);
956 set_str_val(curr, config.c_ip_addr, Value);
960 set_int_val(curr, &config.c_port_number, Value);
964 if (setup_type == UI_SILENT)
967 config.c_auth_mode = AUTHMODE_NATIVE;
971 if ((strcasecmp(auth, "yes") == 0) ||
972 (strcasecmp(auth, "host") == 0))
974 config.c_auth_mode = AUTHMODE_HOST;
976 else if (strcasecmp(auth, "ldap") == 0){
977 config.c_auth_mode = AUTHMODE_LDAP;
979 else if ((strcasecmp(auth, "ldap_ad") == 0) ||
980 (strcasecmp(auth, "active directory") == 0)){
981 config.c_auth_mode = AUTHMODE_LDAP_AD;
986 set_int_val(curr, &config.c_auth_mode, Value);
991 set_str_val(curr, config.c_ldap_host, Value);
995 if (config.c_ldap_port == 0) {
996 config.c_ldap_port = 389;
998 set_int_val(curr, &config.c_ldap_port, Value);
1002 set_str_val(curr, config.c_ldap_base_dn, Value);
1006 set_str_val(curr, config.c_ldap_bind_dn, Value);
1010 set_str_val(curr, config.c_ldap_bind_pw, Value);
1017 * (re-)write the config data to disk
1019 void write_config_to_disk(void)
1025 if ((fd = creat(file_citadel_config, S_IRUSR | S_IWUSR)) == -1) {
1026 display_error("setup: cannot open citadel.config");
1029 fp = fdopen(fd, "wb");
1031 display_error("setup: cannot open citadel.config");
1034 rv = fwrite((char *) &config, sizeof(struct config), 1, fp);
1042 * Figure out what type of user interface we're going to use
1044 int discover_ui(void)
1047 /* Use "dialog" if we have it */
1048 if (getenv("CTDL_DIALOG") != NULL) {
1057 void migrate_old_installs(void)
1060 rv = system("exec /bin/rm -fr ./rooms ./chatpipes ./expressmsgs ./sessions 2>/dev/null");
1061 unlink("citadel.log");
1067 * Strip "db" entries out of /etc/nsswitch.conf
1077 int file_changed = 0;
1078 char new_filename[64];
1081 fp_read = fopen(NSSCONF, "r");
1082 if (fp_read == NULL) {
1086 strcpy(new_filename, "/tmp/ctdl_fixnss_XXXXXX");
1087 fd_write = mkstemp(new_filename);
1093 while (fgets(buf, sizeof buf, fp_read) != NULL) {
1095 strcpy(buf_nc, buf);
1096 for (i=0; i<strlen(buf_nc); ++i) {
1097 if (buf_nc[i] == '#') {
1101 for (i=0; i<strlen(buf_nc); ++i) {
1102 if (!strncasecmp(&buf_nc[i], "db", 2)) {
1104 if ((isspace(buf_nc[i+2])) || (buf_nc[i+2]==0)) {
1107 strcpy(&buf_nc[i], &buf_nc[i+2]);
1108 strcpy(&buf[i], &buf[i+2]);
1110 strcpy(&buf_nc[i], &buf_nc[i+1]);
1111 strcpy(&buf[i], &buf[i+1]);
1117 if (write(fd_write, buf, strlen(buf)) != strlen(buf)) {
1120 unlink(new_filename);
1127 if (!file_changed) {
1128 unlink(new_filename);
1132 snprintf(question, sizeof question,
1134 "/etc/nsswitch.conf is configured to use the 'db' module for\n"
1135 "one or more services. This is not necessary on most systems,\n"
1136 "and it is known to crash the Citadel server when delivering\n"
1137 "mail to the Internet.\n"
1139 "Do you want this module to be automatically disabled?\n"
1143 if (yesno(question, 1)) {
1144 sprintf(buf, "/bin/mv -f %s %s", new_filename, NSSCONF);
1146 chmod(NSSCONF, 0644);
1148 unlink(new_filename);
1151 void check_init_script (char *relhome)
1157 * If we're running on SysV, install init scripts.
1159 if (!access("/var/run", W_OK)) {
1161 if (getenv("NO_INIT_SCRIPTS") == NULL) {
1162 install_init_scripts();
1165 if (!access("/etc/init.d/citadel", X_OK)) {
1166 rv = system("/etc/init.d/citadel start");
1170 if (test_server(relhome, enable_home) == 0) {
1174 if (config.c_auth_mode == AUTHMODE_NATIVE) {
1175 snprintf (admin_cmd, sizeof(admin_cmd), "%s/sendcommand \"CREU %s|%s\" 2>&1",
1176 ctdl_sbin_dir, config.c_sysadm, admin_pass);
1177 fp = popen(admin_cmd, "r");
1179 while (fgets(buf, sizeof buf, fp) != NULL)
1181 if ((atol(buf) == 574) || (atol(buf) == 200))
1187 if (found_it == 0) {
1188 important_message("Error","Setup failed to create your admin user");
1192 if (setup_type != UI_SILENT)
1193 important_message("Setup finished",
1194 "Setup of the Citadel server is complete.\n"
1195 "If you will be using WebCit, please run its\n"
1196 "setup program now; otherwise, run './citadel'\n"
1200 important_message("Setup failed",
1201 "Setup is finished, but the Citadel server failed to start.\n"
1202 "Go back and check your configuration.\n"
1209 important_message("Setup finished",
1210 "Setup is finished. You may now start the server.");
1214 void set_default_values(void)
1217 struct utsname my_utsname;
1220 /* Determine our host name, in case we need to use it as a default */
1223 /* set some sample/default values in place of blanks... */
1224 if (IsEmptyStr(config.c_nodename))
1225 safestrncpy(config.c_nodename, my_utsname.nodename,
1226 sizeof config.c_nodename);
1227 strtok(config.c_nodename, ".");
1228 if (IsEmptyStr(config.c_fqdn) ) {
1229 if ((he = gethostbyname(my_utsname.nodename)) != NULL) {
1230 safestrncpy(config.c_fqdn, he->h_name, sizeof config.c_fqdn);
1232 safestrncpy(config.c_fqdn, my_utsname.nodename, sizeof config.c_fqdn);
1235 if (IsEmptyStr(config.c_humannode)) {
1236 strcpy(config.c_humannode, "My System");
1238 if (IsEmptyStr(config.c_phonenum)) {
1239 strcpy(config.c_phonenum, "US 800 555 1212");
1241 if (config.c_initax == 0) {
1242 config.c_initax = 4;
1244 if (IsEmptyStr(config.c_moreprompt)) strcpy(config.c_moreprompt, "<more>");
1245 if (IsEmptyStr(config.c_twitroom)) strcpy(config.c_twitroom, "Trashcan");
1246 if (IsEmptyStr(config.c_baseroom)) strcpy(config.c_baseroom, BASEROOM);
1247 if (IsEmptyStr(config.c_aideroom)) strcpy(config.c_aideroom, "Aide");
1248 if (config.c_port_number == 0) {
1249 config.c_port_number = 504;
1251 if (config.c_sleeping == 0) {
1252 config.c_sleeping = 900;
1254 if (config.c_ctdluid == 0) {
1255 pw = getpwnam("citadel");
1257 config.c_ctdluid = pw->pw_uid;
1260 if (config.c_ctdluid == 0) {
1261 pw = getpwnam("bbs");
1263 config.c_ctdluid = pw->pw_uid;
1266 if (config.c_ctdluid == 0) {
1267 pw = getpwnam("guest");
1269 config.c_ctdluid = pw->pw_uid;
1272 if (config.c_createax == 0) {
1273 config.c_createax = 3;
1276 * Negative values for maxsessions are not allowed.
1278 if (config.c_maxsessions < 0) {
1279 config.c_maxsessions = 0;
1281 /* We need a system default message expiry policy, because this is
1282 * the top level and there's no 'higher' policy to fall back on.
1283 * By default, do not expire messages at all.
1285 if (config.c_ep.expire_mode == 0) {
1286 config.c_ep.expire_mode = EXPIRE_MANUAL;
1287 config.c_ep.expire_value = 0;
1291 * Default port numbers for various services
1293 if (config.c_smtp_port == 0) config.c_smtp_port = 25;
1294 if (config.c_pop3_port == 0) config.c_pop3_port = 110;
1295 if (config.c_imap_port == 0) config.c_imap_port = 143;
1296 if (config.c_msa_port == 0) config.c_msa_port = 587;
1297 if (config.c_smtps_port == 0) config.c_smtps_port = 465;
1298 if (config.c_pop3s_port == 0) config.c_pop3s_port = 995;
1299 if (config.c_imaps_port == 0) config.c_imaps_port = 993;
1300 if (config.c_pftcpdict_port == 0) config.c_pftcpdict_port = -1;
1301 if (config.c_managesieve_port == 0) config.c_managesieve_port = 2020;
1302 if (config.c_xmpp_c2s_port == 0) config.c_xmpp_c2s_port = 5222;
1303 if (config.c_xmpp_s2s_port == 0) config.c_xmpp_s2s_port = 5269;
1307 void get_config (void)
1314 * What we're going to try to do here is append a whole bunch of
1315 * nulls to the citadel.config file, so we can keep the old config
1316 * values if they exist, but if the file is missing or from an
1317 * earlier version with a shorter config structure, when setup tries
1318 * to read the old config parameters, they'll all come up zero.
1319 * The length of the config file will be set to what it's supposed
1320 * to be when we rewrite it, because we replace the old file with a
1321 * completely new copy.
1323 if ((a = open(file_citadel_config, O_WRONLY | O_CREAT | O_APPEND,
1324 S_IRUSR | S_IWUSR)) == -1) {
1325 display_error("setup: cannot append citadel.config");
1328 fp = fdopen(a, "ab");
1330 display_error("setup: cannot append citadel.config");
1333 for (a = 0; a < sizeof(struct config); ++a) {
1338 /* now we re-open it, and read the old or blank configuration */
1339 fp = fopen(file_citadel_config, "rb");
1341 display_error("setup: cannot open citadel.config");
1344 rv = fread((char *) &config, sizeof(struct config), 1, fp);
1349 int main(int argc, char *argv[])
1354 int old_setup_level = 0;
1358 char relhome[PATH_MAX]="";
1359 char ctdldir[PATH_MAX]=CTDLDIR;
1364 /* set an invalid setup type */
1367 /* Check to see if we're running the web installer */
1368 if (getenv("CITADEL_INSTALLER") != NULL) {
1369 using_web_installer = 1;
1372 /* parse command line args */
1373 for (a = 0; a < argc; ++a) {
1374 if (!strncmp(argv[a], "-u", 2)) {
1375 strcpy(aaa, argv[a]);
1376 strcpy(aaa, &aaa[2]);
1377 setup_type = atoi(aaa);
1379 else if (!strcmp(argv[a], "-i")) {
1382 else if (!strcmp(argv[a], "-q")) {
1383 setup_type = UI_SILENT;
1385 else if (!strncmp(argv[a], "-h", 2)) {
1386 relh=argv[a][2]!='/';
1388 safestrncpy(ctdl_home_directory, &argv[a][2], sizeof ctdl_home_directory);
1390 safestrncpy(relhome, &argv[a][2], sizeof relhome);
1397 calc_dirs_n_files(relh, home, relhome, ctdldir, 0);
1400 /* If a setup type was not specified, try to determine automatically
1401 * the best one to use out of all available types.
1403 if (setup_type < 0) {
1404 setup_type = discover_ui();
1406 if (info_only == 1) {
1407 important_message("Citadel Setup", CITADEL);
1411 enable_home = ( relh | home );
1413 if (chdir(ctdl_run_dir) != 0) {
1415 sprintf(errmsg, "The directory you specified does not exist: [%s]\n", ctdl_run_dir);
1417 important_message("Citadel Setup", errmsg);
1422 /* Try to stop Citadel if we can */
1423 if (!access("/etc/init.d/citadel", X_OK)) {
1424 rv = system("/etc/init.d/citadel stop");
1427 /* Make sure Citadel is not running. */
1428 if (test_server(relhome, enable_home) == 0) {
1429 important_message("Citadel Setup",
1430 "The Citadel service is still running.\n"
1431 "Please stop the service manually and run "
1437 switch (setup_type) {
1441 " *** Citadel setup program ***\n\n");
1448 set_default_values();
1450 /* Go through a series of dialogs prompting for config info */
1451 for (curr = 1; curr <= MAXSETUP; ++curr) {
1453 if ((curr == 6) && (config.c_auth_mode != AUTHMODE_LDAP) && (config.c_auth_mode != AUTHMODE_LDAP_AD)) {
1454 curr += 5; /* skip LDAP questions if we're not authenticating against LDAP */
1458 /***** begin version update section *****/
1460 old_setup_level = config.c_setup_level;
1462 if (old_setup_level == 0) {
1466 if (old_setup_level < 555) {
1469 "This Citadel installation is too old to be upgraded."
1473 write_config_to_disk();
1475 old_setup_level = config.c_setup_level;
1477 /***** end of version update section *****/
1480 config.c_setup_level = REV_LEVEL;
1482 if ((pw = getpwuid(config.c_ctdluid)) == NULL) {
1488 create_run_directories(config.c_ctdluid, gid);
1490 write_config_to_disk();
1492 migrate_old_installs(); /* Delete files and directories used by older Citadel versions */
1494 if ( ((setup_type == UI_SILENT)
1495 && (getenv("ALTER_ETC_SERVICES")!=NULL))
1496 || (setup_type != UI_SILENT)
1498 check_services_entry(); /* Check /etc/services */
1502 delete_inittab_entry(); /* Remove obsolete /etc/inittab entry */
1503 check_xinetd_entry(); /* Check /etc/xinetd.d/telnet */
1504 disable_other_mtas(); /* Offer to disable other MTAs */
1505 fixnss(); /* Check for the 'db' nss and offer to disable it */
1508 progress("Setting file permissions", 1, 3);
1509 rv = chown(file_citadel_config, config.c_ctdluid, gid);
1510 progress("Setting file permissions", 2, 3);
1511 rv = chmod(file_citadel_config, S_IRUSR | S_IWUSR);
1512 progress("Setting file permissions", 3, 3);
1514 check_init_script(relhome);