2 * Citadel setup utility
4 * Copyright (c) 1987-2015 by the citadel.org team
6 * This program is open source software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version 3.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
15 #define SHOW_ME_VAPPEND_PRINTF
22 #include <sys/types.h>
31 #include <sys/socket.h>
34 #include <libcitadel.h>
38 #include "citadel_dirs.h"
49 #define _(string) gettext(string)
51 #define _(string) (string)
54 #define UI_TEXT 0 /* Default setup type -- text only */
55 #define UI_DIALOG 2 /* Use the 'whiptail' or 'dialog' program */
56 #define UI_SILENT 3 /* Silent running, for use in scripts */
58 #define SERVICE_NAME "citadel"
59 #define PROTO_NAME "tcp"
60 #define NSSCONF "/etc/nsswitch.conf"
62 typedef enum _SetupStep {
78 ///"CREATE_XINETD_ENTRY";
79 /* Environment variables, don't translate! */
80 const char *EnvNames [eMaxQuestions] = {
95 int setup_type = (-1);
96 int using_web_installer = 0;
101 int serv_sock = (-1) ;
103 const char *setup_titles[eMaxQuestions];
104 const char *setup_text[eMaxQuestions];
118 setlocale(LC_MESSAGES, getenv("LANG"));
120 bindtextdomain("citadel-setup", LOCALEDIR"/locale");
121 textdomain("citadel-setup");
122 bind_textdomain_codeset("citadel-setup","UTF8");
125 setup_titles[eCitadelHomeDir] = _("Citadel Home Directory");
127 setup_text[eCitadelHomeDir] = _(
128 "Enter the full pathname of the directory in which the Citadel\n"
129 "installation you are creating or updating resides. If you\n"
130 "specify a directory other than the default, you will need to\n"
131 "specify the -h flag to the server when you start it up.\n");
133 setup_text[eCitadelHomeDir] = _(
134 "Enter the subdirectory name for an alternate installation of "
135 "Citadel. To do a default installation just leave it blank."
136 "If you specify a directory other than the default, you will need to\n"
137 "specify the -h flag to the server when you start it up.\n"
138 "note that it may not have a leading /");
141 setup_titles[eSysAdminName] = _("Citadel administrator username:");
142 setup_text[eSysAdminName] = _(
143 "Please enter the name of the Citadel user account that should be granted "
144 "administrative privileges once created. If using internal authentication "
145 "this user account will be created if it does not exist. For external "
146 "authentication this user account has to exist.");
149 setup_titles[eSysAdminPW] = _("Administrator password:");
150 setup_text[eSysAdminPW] = _(
151 "Enter a password for the system administrator. When setup\n"
152 "completes it will attempt to create the administrator user\n"
153 "and set the password specified here.\n");
155 setup_titles[eUID] = _("Citadel User ID:");
156 setup_text[eUID] = _(
157 "Citadel needs to run under its own user ID. This would\n"
158 "typically be called \"citadel\", but if you are running Citadel\n"
159 "as a public site, you might also call it \"bbs\" or \"guest\".\n"
160 "The server will run under this user ID. Please specify that\n"
161 "user ID here. You may specify either a user name or a numeric\n"
164 setup_titles[eIP_ADDR] = _("Listening address for the Citadel server:");
165 setup_text[eIP_ADDR] = _(
166 "Please specify the IP address which the server should be listening to. "
167 "You can name a specific IPv4 or IPv6 address, or you can specify\n"
168 "\"*\" for \"any address\", \"::\" for \"any IPv6 address\", or \"0.0.0.0\"\n"
169 "for \"any IPv4 address\". If you leave this blank, Citadel will\n"
170 "listen on all addresses. "
171 "This can usually be left to the default unless multiple instances of Citadel "
172 "are running on the same computer.");
174 setup_titles[eCTDL_Port] = _("Server port number:");
175 setup_text[eCTDL_Port] = _(
176 "Specify the TCP port number on which your server will run.\n"
177 "Normally, this will be port 504, which is the official port\n"
178 "assigned by the IANA for Citadel servers. You will only need\n"
179 "to specify a different port number if you run multiple instances\n"
180 "of Citadel on the same computer and there is something else\n"
181 "already using port 504.\n");
183 setup_titles[eAuthType] = _("Authentication method to use:");
184 setup_text[eAuthType] = _(
185 "Please choose the user authentication mode. By default Citadel will use its "
186 "own internal user accounts database. If you choose Host, Citadel users will "
187 "have accounts on the host system, authenticated via /etc/passwd or a PAM "
188 "source. LDAP chooses an RFC 2307 compliant directory server, the last option "
189 "chooses the nonstandard MS Active Directory LDAP scheme."
191 "Do not change this option unless you are sure it is required, since changing "
192 "back requires a full reinstall of Citadel."
194 " 0. Self contained authentication\n"
195 " 1. Host system integrated authentication\n"
196 " 2. External LDAP - RFC 2307 compliant directory\n"
197 " 3. External LDAP - nonstandard MS Active Directory\n"
199 "For help: http://www.citadel.org/doku.php/faq:installation:authmodes\n"
201 "ANSWER \"0\" UNLESS YOU COMPLETELY UNDERSTAND THIS OPTION.\n");
203 setup_titles[eLDAP_Host] = _("LDAP host:");
204 setup_text[eLDAP_Host] = _(
205 "Please enter the host name or IP address of your LDAP server.\n");
207 setup_titles[eLDAP_Port] = _("LDAP port number:");
208 setup_text[eLDAP_Port] = _(
209 "Please enter the port number of the LDAP service (usually 389).\n");
211 setup_titles[eLDAP_Base_DN] = _("LDAP base DN:");
212 setup_text[eLDAP_Base_DN] = _(
213 "Please enter the Base DN to search for authentication\n"
214 "(for example: dc=example,dc=com)\n");
216 setup_titles[eLDAP_Bind_DN] = _("LDAP bind DN:");
217 setup_text[eLDAP_Bind_DN] = _(
218 "Please enter the DN of an account to use for binding to the LDAP server for "
219 "performing queries. The account does not require any other privileges. If "
220 "your LDAP server allows anonymous queries, you can leave this blank.\n");
222 setup_titles[eLDAP_Bind_PW] = _("LDAP bind password:");
223 setup_text[eLDAP_Bind_PW] = _(
224 "If you entered a Bind DN in the previous question, you must now enter\n"
225 "the password associated with that account. Otherwise, you can leave this\n"
229 // Debug loading of locales... Strace does a better job though.
230 printf("Message catalog directory: %s\n", bindtextdomain("citadel-setup", LOCALEDIR"/locale"));
231 printf("Text domain: %s\n", textdomain("citadel-setup"));
232 printf("Text domain Charset: %s\n", bind_textdomain_codeset("citadel-setup","UTF8"));
235 for (i = 0; i < eMaxQuestions; i++)
236 printf("%s - %s\n", setup_titles[i], _(setup_titles[i]));
244 void title(const char *text)
246 if (setup_type == UI_TEXT) {
247 printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<%s>\n", text);
253 int yesno(const char *question, int default_value)
259 switch (setup_type) {
263 printf("%s\n%s [%s] --> ",
266 ( default_value ? _("Yes") : _("No") )
268 if (fgets(buf, sizeof buf, stdin))
270 answer = tolower(buf[0]);
271 if ((buf[0]==0) || (buf[0]==13) || (buf[0]==10)) {
272 answer = default_value;
274 else if (answer == 'y') {
277 else if (answer == 'n') {
281 } while ((answer < 0) || (answer > 1));
285 snprintf(buf, sizeof buf, "exec %s --backtitle '%s' %s --yesno '%s' 15 75",
286 getenv("CTDL_DIALOG"),
288 ( default_value ? "" : "--defaultno" ),
305 void important_message(const char *title, const char *msgtext)
309 switch (setup_type) {
312 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");
313 printf(" %s \n\n%s\n\n", title, msgtext);
314 printf("%s", _("Press return to continue..."));
315 if (fgets(buf, sizeof buf, stdin))
320 snprintf(buf, sizeof buf, "exec %s --backtitle '%s' --msgbox '%s' 19 72",
321 getenv("CTDL_DIALOG"),
324 int rv = system(buf);
326 fprintf(stderr, _("failed to run the dialog command\n"));
330 fprintf(stderr, "%s\n", msgtext);
335 void important_msgnum(int msgnum)
337 important_message(_("Important Message"), setup_text[msgnum]);
340 void display_error(char *error_message_format, ...)
346 va_start(arg_ptr, error_message_format);
347 StrBufVAppendPrintf(Msg, error_message_format, arg_ptr);
350 important_message(_("Error"), ChrPtr(Msg));
354 void progress(char *text, long int curr, long int cmax)
356 static long dots_printed = 0L;
358 static FILE *fp = NULL;
361 switch (setup_type) {
365 printf("%s\n", text);
366 printf("....................................................");
367 printf("..........................\r");
369 } else if (curr == cmax) {
370 printf("\r%79s\n", "");
372 a = (curr * 100) / cmax;
375 while (dots_printed < a) {
385 snprintf(buf, sizeof buf, "exec %s --backtitle '%s' --gauge '%s' 7 72 0",
386 getenv("CTDL_DIALOG"),
389 fp = popen(buf, "w");
395 else if (curr == cmax) {
397 fprintf(fp, "100\n");
403 a = (curr * 100) / cmax;
405 fprintf(fp, "%ld\n", a);
414 assert(1==0); /* If we got here then the developer is a moron */
420 int uds_connectsock(char *sockpath)
423 struct sockaddr_un addr;
425 memset(&addr, 0, sizeof(addr));
426 addr.sun_family = AF_UNIX;
427 strncpy(addr.sun_path, sockpath, sizeof addr.sun_path);
429 s = socket(AF_UNIX, SOCK_STREAM, 0);
434 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
444 * input binary data from socket
446 void serv_read(char *buf, int bytes)
451 while (len < bytes) {
452 rlen = read(serv_sock, &buf[len], bytes - len);
462 * send binary to server
464 void serv_write(char *buf, int nbytes)
466 int bytes_written = 0;
468 while (bytes_written < nbytes) {
469 retval = write(serv_sock, &buf[bytes_written], nbytes - bytes_written);
473 bytes_written = bytes_written + retval;
480 * input string from socket - implemented in terms of serv_read()
482 void serv_gets(char *buf)
486 /* Read one character at a time.
489 serv_read(&buf[i], 1);
490 if (buf[i] == '\n' || i == (SIZ-1))
494 /* If we got a long line, discard characters until the newline.
497 while (buf[i] != '\n') {
498 serv_read(&buf[i], 1);
502 /* Strip all trailing nonprintables (crlf)
509 * send line to server - implemented in terms of serv_write()
511 void serv_puts(char *buf)
513 serv_write(buf, strlen(buf));
519 * Convenience functions to get/set system configuration entries
521 void getconf_str(char *buf, char *key)
526 sprintf(cmd, "CONF GETVAL|%s", key);
530 extract_token(buf, &ret[4], 0, '|', SIZ);
537 int getconf_int(char *key)
540 getconf_str(buf, key);
544 void setconf_str(char *key, char *val)
548 sprintf(buf, "CONF PUTVAL|%s|%s", key, val);
554 void setconf_int(char *key, int val)
558 sprintf(buf, "CONF PUTVAL|%s|%d", key, val);
568 * On systems which use xinetd, see if we can offer to install Citadel as
569 * the default telnet target.
571 void check_xinetd_entry(void)
573 char *filename = "/etc/xinetd.d/telnet";
576 int already_citadel = 0;
579 fp = fopen(filename, "r+");
580 if (fp == NULL) return; /* Not there. Oh well... */
582 while (fgets(buf, sizeof buf, fp) != NULL) {
583 if (strstr(buf, "/citadel") != NULL) {
588 if (already_citadel) return; /* Already set up this way. */
590 /* Otherwise, prompt the user to create an entry. */
591 if (getenv("CREATE_XINETD_ENTRY") != NULL) {
592 if (strcasecmp(getenv("CREATE_XINETD_ENTRY"), "yes")) {
597 snprintf(buf, sizeof buf,
598 _("Setup can configure the \"xinetd\" service to automatically\n"
599 "connect incoming telnet sessions to Citadel, bypassing the\n"
600 "host system login: prompt. Would you like to do this?\n"
603 if (yesno(buf, 1) == 0) {
608 fp = fopen(filename, "w");
610 "# description: telnet service for Citadel users\n"
615 " socket_type = stream\n"
618 " server = /usr/sbin/in.telnetd\n"
619 " server_args = -h -L %s/citadel\n"
620 " log_on_failure += USERID\n"
625 /* Now try to restart the service */
626 rv = system("/etc/init.d/xinetd restart >/dev/null 2>&1");
628 display_error(_("failed to restart xinetd.\n"));
635 * Offer to disable other MTA's
637 void disable_other_mta(const char *mta) {
643 snprintf(buf, sizeof buf,
644 "/bin/ls -l /etc/rc*.d/S*%s 2>/dev/null; "
645 "/bin/ls -l /etc/rc.d/rc*.d/S*%s 2>/dev/null",
648 fp = popen(buf, "r");
649 if (fp == NULL) return;
651 while (fgets(buf, sizeof buf, fp) != NULL) {
655 if (lines == 0) return; /* Nothing to do. */
657 /* Offer to replace other MTA with the vastly superior Citadel :) */
659 snprintf(buf, sizeof buf,
660 "%s \"%s\" %s%s%s%s%s%s%s",
661 _("You appear to have the "),
664 "running on your system. If you want Citadel mail\n"
667 _(" you will have to manually integrate\n"
668 "them. It is preferable to disable "),
670 _(", and use Citadel's\n"
671 "SMTP, POP3, and IMAP services.\n\n"
674 _("so that Citadel has access to ports\n"
675 "25, 110, and 143?\n")
677 if (yesno(buf, 1) == 0) {
682 snprintf(buf, sizeof 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);
685 display_error("%s %s.\n", _("failed to disable other mta"), mta);
687 snprintf(buf, sizeof buf, "/etc/init.d/%s stop >/dev/null 2>&1", mta);
690 display_error(" %s.\n", _("failed to disable other mta"), mta);
693 const char *other_mtas[] = {
694 "courier-authdaemon",
717 void disable_other_mtas(void)
720 if ((getenv("ACT_AS_MTA") == NULL) ||
721 (getenv("ACT_AS_MTA") &&
722 strcasecmp(getenv("ACT_AS_MTA"), "yes") == 0)) {
723 /* Offer to disable other MTA's on the system. */
724 while (!IsEmptyStr(other_mtas[i]))
726 disable_other_mta(other_mtas[i]);
732 void strprompt(const char *prompt_title, const char *prompt_text, char *Target, char *DefValue)
736 char dialog_result[PATH_MAX];
740 strcpy(setupmsg, "");
742 switch (setup_type) {
745 printf("\n%s\n", prompt_text);
746 printf("%s\n%s\n", _("This is currently set to:"), Target);
747 printf("%s\n", _("Enter new value or press return to leave unchanged:"));
748 if (fgets(buf, sizeof buf, stdin)) {
749 buf[strlen(buf) - 1] = 0;
751 if (!IsEmptyStr(buf))
756 CtdlMakeTempFileName(dialog_result, sizeof dialog_result);
757 snprintf(buf, sizeof buf, "exec %s --backtitle '%s' --nocancel --inputbox '%s' 19 72 '%s' 2>%s",
758 getenv("CTDL_DIALOG"),
765 fprintf(stderr, "failed to run whiptail or dialog\n");
768 fp = fopen(dialog_result, "r");
770 if (fgets(Target, sizeof buf, fp)) {
771 if (Target[strlen(Target)-1] == 10) {
772 Target[strlen(Target)-1] = 0;
776 unlink(dialog_result);
780 if (*DefValue != '\0')
781 strcpy(Target, DefValue);
786 void set_bool_val(int msgpos, int *ip, char *DefValue)
788 title(setup_titles[msgpos]);
789 *ip = yesno(setup_text[msgpos], *ip);
792 void set_str_val(int msgpos, char *Target, char *DefValue)
794 strprompt(setup_titles[msgpos],
801 /* like set_str_val() but for numeric values */
802 void set_int_val(int msgpos, int *target, char *default_value)
805 sprintf(buf, "%d", *target);
807 set_str_val(msgpos, buf, default_value);
808 } while ( (strcmp(buf, "0")) && (atoi(buf) == 0) );
813 void edit_value(int curr)
815 struct passwd *pw = NULL;
816 char ctdluidname[256];
818 char *default_value = NULL;
824 if (setup_type == UI_SILENT)
826 default_value = getenv(EnvNames[curr]);
828 if (default_value == NULL) {
835 getconf_str(admin_name, "c_sysadm");
836 set_str_val(curr, admin_name, default_value);
837 setconf_str("c_sysadm", admin_name);
841 set_str_val(curr, admin_pass, default_value);
846 if (setup_type == UI_SILENT)
849 ctdluid = atoi(default_value);
855 ctdluid = 0; /* work-around for Windows */
857 pw = getpwuid(ctdluid);
859 set_int_val(curr, &ctdluid, default_value);
862 strcpy(ctdluidname, pw->pw_name);
863 set_str_val(curr, ctdluidname, default_value);
864 pw = getpwnam(ctdluidname);
866 ctdluid = pw->pw_uid;
868 else if (atoi(ctdluidname) > 0) {
869 ctdluid = atoi(ctdluidname);
874 setconf_int("c_ctdluid", ctdluid);
878 getconf_str(buf, "c_ip_addr");
879 set_str_val(curr, buf, default_value);
880 setconf_str("c_ip_addr", buf);
884 portnum = getconf_int("c_port_number");
885 set_int_val(curr, &portnum, default_value);
886 setconf_int("c_port_number", portnum);
890 auth = getconf_int("c_auth_mode");
891 if (setup_type == UI_SILENT)
893 if ( (default_value) && (!strcasecmp(default_value, "yes")) ) auth = AUTHMODE_HOST;
894 if ( (default_value) && (!strcasecmp(default_value, "host")) ) auth = AUTHMODE_HOST;
895 if ( (default_value) && (!strcasecmp(default_value, "ldap")) ) auth = AUTHMODE_LDAP;
896 if ( (default_value) && (!strcasecmp(default_value, "ldap_ad")) ) auth = AUTHMODE_LDAP_AD;
897 if ( (default_value) && (!strcasecmp(default_value, "active directory")) ) auth = AUTHMODE_LDAP_AD;
900 set_int_val(curr, &auth, default_value);
902 setconf_int("c_auth_mode", auth);
906 getconf_str(buf, "c_ldap_host");
907 if (IsEmptyStr(buf)) {
908 strcpy(buf, "localhost");
910 set_str_val(curr, buf, default_value);
911 setconf_str("c_ldap_host", buf);
915 lportnum = getconf_int("c_ldap_port");
919 set_int_val(curr, &lportnum, default_value);
920 setconf_int("c_ldap_port", lportnum);
924 getconf_str(buf, "c_ldap_base_dn");
925 set_str_val(curr, buf, default_value);
926 setconf_str("c_ldap_base_dn", buf);
930 getconf_str(buf, "c_ldap_bind_dn");
931 set_str_val(curr, buf, default_value);
932 setconf_str("c_ldap_bind_dn", buf);
936 getconf_str(buf, "c_ldap_bind_pw");
937 set_str_val(curr, buf, default_value);
938 setconf_str("c_ldap_bind_pw", buf);
946 * Figure out what type of user interface we're going to use
948 int discover_ui(void)
951 /* Use "whiptail" or "dialog" if we have it */
952 if (getenv("CTDL_DIALOG") != NULL) {
962 * Strip "db" entries out of /etc/nsswitch.conf
971 int file_changed = 0;
972 char new_filename[64];
975 fp_read = fopen(NSSCONF, "r");
976 if (fp_read == NULL) {
980 strcpy(new_filename, "/tmp/ctdl_fixnss_XXXXXX");
981 fd_write = mkstemp(new_filename);
987 while (fgets(buf, sizeof buf, fp_read) != NULL) {
989 for (i=0; buf_nc[i]; ++i) {
990 if (buf_nc[i] == '#') {
995 for (i=0; i<strlen(buf_nc); ++i) {
996 if (!strncasecmp(&buf_nc[i], "db", 2)) {
998 if ((isspace(buf_nc[i+2])) || (buf_nc[i+2]==0)) {
1000 strcpy(&buf_nc[i], &buf_nc[i+2]);
1001 strcpy(&buf[i], &buf[i+2]);
1003 strcpy(&buf_nc[i], &buf_nc[i+1]);
1004 strcpy(&buf[i], &buf[i+1]);
1010 long buflen = strlen(buf);
1011 if (write(fd_write, buf, buflen) != buflen) {
1014 unlink(new_filename);
1021 if (!file_changed) {
1022 unlink(new_filename);
1026 snprintf(question, sizeof question,
1029 "/etc/nsswitch.conf is configured to use the 'db' module for\n"
1030 "one or more services. This is not necessary on most systems,\n"
1031 "and it is known to crash the Citadel server when delivering\n"
1032 "mail to the Internet.\n"
1034 "Do you want this module to be automatically disabled?\n"
1039 if (yesno(question, 1)) {
1040 snprintf(buf, sizeof buf, "/bin/mv -f %s %s", new_filename, NSSCONF);
1043 fprintf(stderr, "failed to edit %s.\n", NSSCONF);
1045 chmod(NSSCONF, 0644);
1047 unlink(new_filename);
1052 * Messages that are no longer in use.
1053 * We keep them here so we don't lose the translations if we need them later.
1056 important_message(_("Setup finished"),
1057 _("Setup of the Citadel server is complete.\n"
1058 "If you will be using WebCit, please run its\n"
1059 "setup program now; otherwise, run './citadel'\n"
1061 important_message(_("Setup failed"),
1062 _("Setup is finished, but the Citadel server failed to start.\n"
1063 "Go back and check your configuration.\n")
1064 important_message(_("Setup finished"),
1065 _("Setup is finished. You may now start the server."));
1071 int main(int argc, char *argv[])
1080 char relhome[PATH_MAX]="";
1081 char ctdldir[PATH_MAX]=CTDLDIR;
1084 char *activity = NULL;
1086 /* Keep a mild groove on */
1087 program_title = _("Citadel setup program");
1089 /* set an invalid setup type */
1092 /* Check to see if we're running the web installer */
1093 if (getenv("CITADEL_INSTALLER") != NULL) {
1094 using_web_installer = 1;
1097 /* parse command line args */
1098 for (a = 0; a < argc; ++a) {
1099 if (!strncmp(argv[a], "-u", 2)) {
1100 strcpy(aaa, argv[a]);
1101 strcpy(aaa, &aaa[2]);
1102 setup_type = atoi(aaa);
1104 else if (!strcmp(argv[a], "-q")) {
1105 setup_type = UI_SILENT;
1107 else if (!strncmp(argv[a], "-h", 2)) {
1108 relh=argv[a][2]!='/';
1110 safestrncpy(ctdl_home_directory, &argv[a][2], sizeof ctdl_home_directory);
1112 safestrncpy(relhome, &argv[a][2], sizeof relhome);
1119 calc_dirs_n_files(relh, home, relhome, ctdldir, 0);
1122 /* If a setup type was not specified, try to determine automatically
1123 * the best one to use out of all available types.
1125 if (setup_type < 0) {
1126 setup_type = discover_ui();
1129 enable_home = ( relh | home );
1131 if (chdir(ctdl_run_dir) != 0) {
1132 display_error("%s: [%s]\n", _("The directory you specified does not exist"), ctdl_run_dir);
1138 * Connect to the running Citadel server.
1140 while ((serv_sock < 0) && (nRetries < 10)) {
1141 serv_sock = uds_connectsock(file_citadel_admin_socket);
1146 if (serv_sock < 0) {
1149 _("Setup could not connect to a running Citadel server."),
1150 strerror(errno), file_citadel_admin_socket
1156 * read the server greeting
1159 if (buf[0] != '2') {
1160 display_error("%s\n", buf);
1165 * Are we connected to the correct Citadel server?
1169 if (buf[0] != '1') {
1170 display_error("%s\n", buf);
1174 while (serv_gets(buf), strcmp(buf, "000")) {
1176 if (atoi(buf) != REV_LEVEL) {
1177 display_error("%s\n",
1178 _("Your setup program and Citadel server are from different versions.")
1191 if (setup_type == UI_TEXT) {
1192 printf("\n\n\n *** %s ***\n\n", program_title);
1195 if (setup_type == UI_DIALOG) {
1196 system("clear 2>/dev/null");
1199 /* Go through a series of dialogs prompting for config info */
1200 for (curr = 1; curr < eMaxQuestions; ++curr) {
1203 if ( (curr == eAuthType)
1204 && (getconf_int("c_auth_mode") != AUTHMODE_LDAP)
1205 && (getconf_int("c_auth_mode") != AUTHMODE_LDAP_AD)
1207 curr += 5; /* skip LDAP questions if we're not authenticating against LDAP */
1210 if (curr == eSysAdminName) {
1211 if (getconf_int("c_auth_mode") == AUTHMODE_NATIVE) {
1212 /* for native auth mode, fetch the admin's existing pw */
1213 snprintf(buf, sizeof buf, "AGUP %s", admin_name);
1216 if (buf[0] == '2') {
1217 extract_token(admin_pass, &buf[4], 1, '|', sizeof admin_pass);
1221 ++curr; /* skip the password question for non-native auth modes */
1226 if ((pw = getpwuid( getconf_int("c_ctdluid") )) == NULL) {
1232 if (create_run_directories(getconf_int("c_ctdluid"), gid) != 0) {
1233 display_error("%s\n", _("failed to create directories"));
1236 activity = _("Reconfiguring Citadel server");
1237 progress(activity, 0, 5);
1238 sleep(1); /* Let the message appear briefly */
1241 * Create the administrator account. It's ok if the command fails if this user already exists.
1243 progress(activity, 1, 5);
1244 snprintf(buf, sizeof buf, "CREU %s|%s", admin_name, admin_pass);
1246 progress(activity, 2, 5);
1248 progress(activity, 3, 5);
1251 * Assign the desired password and access level to the administrator account.
1253 snprintf(buf, sizeof buf, "AGUP %s", admin_name);
1255 progress(activity, 4, 5);
1257 if (buf[0] == '2') {
1258 int admin_flags = extract_int(&buf[4], 2);
1259 int admin_times_called = extract_int(&buf[4], 3);
1260 int admin_msgs_posted = extract_int(&buf[4], 4);
1261 snprintf(buf, sizeof buf, "ASUP %s|%s|%d|%d|%d|6",
1262 admin_name, admin_pass, admin_flags, admin_times_called, admin_msgs_posted
1267 progress(activity, 5, 5);
1270 check_xinetd_entry(); /* Check /etc/xinetd.d/telnet */
1271 disable_other_mtas(); /* Offer to disable other MTAs */
1272 fixnss(); /* Check for the 'db' nss and offer to disable it */
1278 activity = _("Restarting Citadel server to apply changes");
1279 progress(activity, 0, 41);
1283 long original_start_time = extract_long(&buf[4], 3);
1285 progress(activity, 1, 41);
1286 serv_puts("DOWN 1");
1287 progress(activity, 2, 41);
1289 if (buf[0] != '2') {
1290 display_error("%s\n", buf);
1297 for (i=3; i<=6; ++i) { /* wait for server to shut down */
1298 progress(activity, i, 41);
1302 for (i=7; ((i<=38) && (serv_sock < 0)) ; ++i) { /* wait for server to start up */
1303 progress(activity, i, 41);
1304 serv_sock = uds_connectsock(file_citadel_admin_socket);
1308 progress(activity, 39, 41);
1311 progress(activity, 40, 41);
1314 long new_start_time = extract_long(&buf[4], 3);
1317 progress(activity, 41, 41);
1319 if ( (original_start_time == new_start_time)
1320 || (new_start_time <= 0)
1322 display_error("%s\n", _("Setup failed to restart Citadel server. Please restart it manually."));