2 * Citadel setup utility
4 * Copyright (c) 1987-2014 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;
100 int serv_sock = (-1) ;
101 char configs[NUM_CONFIGS][1024];
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]));
243 * Print the stack frame for a backtrace
245 void cit_backtrace(void)
247 #ifdef HAVE_BACKTRACE
248 void *stack_frames[50];
252 size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
253 strings = backtrace_symbols(stack_frames, size);
254 for (i = 0; i < size; i++) {
256 fprintf(stderr, "%s\n", strings[i]);
258 fprintf(stderr, "%p\n", stack_frames[i]);
266 void title(const char *text)
268 if (setup_type == UI_TEXT) {
269 printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<%s>\n", text);
275 int yesno(const char *question, int default_value)
281 switch (setup_type) {
285 printf("%s\n%s [%s] --> ",
288 ( default_value ? _("Yes") : _("No") )
290 if (fgets(buf, sizeof buf, stdin))
292 answer = tolower(buf[0]);
293 if ((buf[0]==0) || (buf[0]==13) || (buf[0]==10)) {
294 answer = default_value;
296 else if (answer == 'y') {
299 else if (answer == 'n') {
303 } while ((answer < 0) || (answer > 1));
307 snprintf(buf, sizeof buf, "exec %s --backtitle '%s' %s --yesno '%s' 15 75",
308 getenv("CTDL_DIALOG"),
310 ( default_value ? "" : "--defaultno" ),
327 void important_message(const char *title, const char *msgtext)
331 switch (setup_type) {
334 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");
335 printf(" %s \n\n%s\n\n", title, msgtext);
336 printf("%s", _("Press return to continue..."));
337 if (fgets(buf, sizeof buf, stdin))
342 snprintf(buf, sizeof buf, "exec %s --backtitle '%s' --msgbox '%s' 19 72",
343 getenv("CTDL_DIALOG"),
346 int rv = system(buf);
348 fprintf(stderr, _("failed to run the dialog command\n"));
352 fprintf(stderr, "%s\n", msgtext);
357 void important_msgnum(int msgnum)
359 important_message(_("Important Message"), setup_text[msgnum]);
362 void display_error(char *error_message_format, ...)
368 va_start(arg_ptr, error_message_format);
369 StrBufVAppendPrintf(Msg, error_message_format, arg_ptr);
372 important_message(_("Error"), ChrPtr(Msg));
376 void progress(char *text, long int curr, long int cmax)
378 static long dots_printed = 0L;
380 static FILE *fp = NULL;
383 switch (setup_type) {
387 printf("%s\n", text);
388 printf("....................................................");
389 printf("..........................\r");
391 } else if (curr == cmax) {
392 printf("\r%79s\n", "");
394 a = (curr * 100) / cmax;
397 while (dots_printed < a) {
407 snprintf(buf, sizeof buf, "exec %s --backtitle '%s' --gauge '%s' 7 72 0",
408 getenv("CTDL_DIALOG"),
411 fp = popen(buf, "w");
417 else if (curr == cmax) {
419 fprintf(fp, "100\n");
425 a = (curr * 100) / cmax;
427 fprintf(fp, "%ld\n", a);
436 assert(1==0); /* If we got here then the developer is a moron */
442 int uds_connectsock(char *sockpath)
445 struct sockaddr_un addr;
447 memset(&addr, 0, sizeof(addr));
448 addr.sun_family = AF_UNIX;
449 strncpy(addr.sun_path, sockpath, sizeof addr.sun_path);
451 s = socket(AF_UNIX, SOCK_STREAM, 0);
456 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
466 * input binary data from socket
468 void serv_read(char *buf, int bytes)
473 while (len < bytes) {
474 rlen = read(serv_sock, &buf[len], bytes - len);
484 * send binary to server
486 void serv_write(char *buf, int nbytes)
488 int bytes_written = 0;
490 while (bytes_written < nbytes) {
491 retval = write(serv_sock, &buf[bytes_written], nbytes - bytes_written);
495 bytes_written = bytes_written + retval;
502 * input string from socket - implemented in terms of serv_read()
504 void serv_gets(char *buf)
508 /* Read one character at a time.
511 serv_read(&buf[i], 1);
512 if (buf[i] == '\n' || i == (SIZ-1))
516 /* If we got a long line, discard characters until the newline.
519 while (buf[i] != '\n') {
520 serv_read(&buf[i], 1);
524 /* Strip all trailing nonprintables (crlf)
531 * send line to server - implemented in terms of serv_write()
533 void serv_puts(char *buf)
535 serv_write(buf, strlen(buf));
541 * On systems which use xinetd, see if we can offer to install Citadel as
542 * the default telnet target.
544 void check_xinetd_entry(void) {
545 char *filename = "/etc/xinetd.d/telnet";
548 int already_citadel = 0;
551 fp = fopen(filename, "r+");
552 if (fp == NULL) return; /* Not there. Oh well... */
554 while (fgets(buf, sizeof buf, fp) != NULL) {
555 if (strstr(buf, "/citadel") != NULL) {
560 if (already_citadel) return; /* Already set up this way. */
562 /* Otherwise, prompt the user to create an entry. */
563 if (getenv("CREATE_XINETD_ENTRY") != NULL) {
564 if (strcasecmp(getenv("CREATE_XINETD_ENTRY"), "yes")) {
569 snprintf(buf, sizeof buf,
570 _("Setup can configure the \"xinetd\" service to automatically\n"
571 "connect incoming telnet sessions to Citadel, bypassing the\n"
572 "host system login: prompt. Would you like to do this?\n"
575 if (yesno(buf, 1) == 0) {
580 fp = fopen(filename, "w");
582 "# description: telnet service for Citadel users\n"
587 " socket_type = stream\n"
590 " server = /usr/sbin/in.telnetd\n"
591 " server_args = -h -L %s/citadel\n"
592 " log_on_failure += USERID\n"
597 /* Now try to restart the service */
598 rv = system("/etc/init.d/xinetd restart >/dev/null 2>&1");
600 display_error(_("failed to restart xinetd.\n"));
607 * Offer to disable other MTA's
609 void disable_other_mta(const char *mta) {
615 snprintf(buf, sizeof buf,
616 "/bin/ls -l /etc/rc*.d/S*%s 2>/dev/null; "
617 "/bin/ls -l /etc/rc.d/rc*.d/S*%s 2>/dev/null",
620 fp = popen(buf, "r");
621 if (fp == NULL) return;
623 while (fgets(buf, sizeof buf, fp) != NULL) {
627 if (lines == 0) return; /* Nothing to do. */
629 /* Offer to replace other MTA with the vastly superior Citadel :) */
631 snprintf(buf, sizeof buf,
632 "%s \"%s\" %s%s%s%s%s%s%s",
633 _("You appear to have the "),
636 "running on your system. If you want Citadel mail\n"
639 _(" you will have to manually integrate\n"
640 "them. It is preferable to disable "),
642 _(", and use Citadel's\n"
643 "SMTP, POP3, and IMAP services.\n\n"
646 _("so that Citadel has access to ports\n"
647 "25, 110, and 143?\n")
649 if (yesno(buf, 1) == 0) {
654 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);
657 display_error("%s %s.\n", _("failed to disable other mta"), mta);
659 snprintf(buf, sizeof buf, "/etc/init.d/%s stop >/dev/null 2>&1", mta);
662 display_error(" %s.\n", _("failed to disable other mta"), mta);
665 const char *other_mtas[] = {
666 "courier-authdaemon",
689 void disable_other_mtas(void)
692 if ((getenv("ACT_AS_MTA") == NULL) ||
693 (getenv("ACT_AS_MTA") &&
694 strcasecmp(getenv("ACT_AS_MTA"), "yes") == 0)) {
695 /* Offer to disable other MTA's on the system. */
696 while (!IsEmptyStr(other_mtas[i]))
698 disable_other_mta(other_mtas[i]);
704 void strprompt(const char *prompt_title, const char *prompt_text, char *Target, char *DefValue)
708 char dialog_result[PATH_MAX];
712 strcpy(setupmsg, "");
714 switch (setup_type) {
717 printf("\n%s\n", prompt_text);
718 printf("%s\n%s\n", _("This is currently set to:"), Target);
719 printf("%s\n", _("Enter new value or press return to leave unchanged:"));
720 if (fgets(buf, sizeof buf, stdin)){
721 buf[strlen(buf) - 1] = 0;
723 if (!IsEmptyStr(buf))
728 CtdlMakeTempFileName(dialog_result, sizeof dialog_result);
729 snprintf(buf, sizeof buf, "exec %s --backtitle '%s' --nocancel --inputbox '%s' 19 72 '%s' 2>%s",
730 getenv("CTDL_DIALOG"),
737 fprintf(stderr, "failed to run whiptail or dialog\n");
740 fp = fopen(dialog_result, "r");
742 if (fgets(Target, sizeof buf, fp)) {
743 if (Target[strlen(Target)-1] == 10) {
744 Target[strlen(Target)-1] = 0;
748 unlink(dialog_result);
752 if (*DefValue != '\0')
753 strcpy(Target, DefValue);
758 void set_bool_val(int msgpos, int *ip, char *DefValue)
760 title(setup_titles[msgpos]);
761 *ip = yesno(setup_text[msgpos], *ip);
764 void set_str_val(int msgpos, char *Target, char *DefValue)
766 strprompt(setup_titles[msgpos],
773 /* like set_str_val() but make sure we ended up with a numeric value */
774 void set_int_val(int msgpos, char *target, char *DefValue)
777 set_str_val(msgpos, target, DefValue);
778 if (!strcmp(target, "0")) return;
779 if (atoi(target) != 0) return;
784 void edit_value(int curr)
788 char ctdluidname[256];
791 if (setup_type == UI_SILENT)
793 Value = getenv(EnvNames[curr]);
802 set_str_val(curr, configs[13], Value);
806 set_str_val(curr, admin_pass, Value);
810 if (setup_type == UI_SILENT)
813 sprintf(configs[69], "%d", atoi(Value));
819 strcpy(configs[69], "0"); /* work-around for Windows */
821 i = atoi(configs[69]);
824 set_int_val(curr, configs[69], Value);
825 sprintf(configs[69], "%d", i);
828 strcpy(ctdluidname, pw->pw_name);
829 set_str_val(curr, ctdluidname, Value);
830 pw = getpwnam(ctdluidname);
832 sprintf(configs[69], "%d", pw->pw_uid);
834 else if (atoi(ctdluidname) > 0) {
835 sprintf(configs[69], "%d", atoi(ctdluidname));
843 set_str_val(curr, configs[37], Value);
847 set_int_val(curr, configs[68], Value);
851 if (setup_type == UI_SILENT)
854 //config.c_auth_mode = AUTHMODE_NATIVE;
858 if ((strcasecmp(auth, "yes") == 0) ||
859 (strcasecmp(auth, "host") == 0))
861 //config.c_auth_mode = AUTHMODE_HOST;
863 else if (strcasecmp(auth, "ldap") == 0){
864 //config.c_auth_mode = AUTHMODE_LDAP;
866 else if ((strcasecmp(auth, "ldap_ad") == 0) ||
867 (strcasecmp(auth, "active directory") == 0)){
868 //config.c_auth_mode = AUTHMODE_LDAP_AD;
873 set_int_val(curr, configs[52], Value);
878 if (IsEmptyStr(configs[32])) {
879 strcpy(configs[32], "localhost");
881 set_str_val(curr, configs[32], Value);
885 if (atoi(configs[33]) == 0) {
886 strcpy(configs[33], "389");
888 set_int_val(curr, configs[33], Value);
892 set_str_val(curr, configs[34], Value);
896 set_str_val(curr, configs[35], Value);
900 set_str_val(curr, configs[36], Value);
909 * Figure out what type of user interface we're going to use
911 int discover_ui(void)
914 /* Use "whiptail" or "dialog" if we have it */
915 if (getenv("CTDL_DIALOG") != NULL) {
925 * Strip "db" entries out of /etc/nsswitch.conf
934 int file_changed = 0;
935 char new_filename[64];
938 fp_read = fopen(NSSCONF, "r");
939 if (fp_read == NULL) {
943 strcpy(new_filename, "/tmp/ctdl_fixnss_XXXXXX");
944 fd_write = mkstemp(new_filename);
950 while (fgets(buf, sizeof buf, fp_read) != NULL) {
952 for (i=0; buf_nc[i]; ++i) {
953 if (buf_nc[i] == '#') {
958 for (i=0; i<strlen(buf_nc); ++i) {
959 if (!strncasecmp(&buf_nc[i], "db", 2)) {
961 if ((isspace(buf_nc[i+2])) || (buf_nc[i+2]==0)) {
963 strcpy(&buf_nc[i], &buf_nc[i+2]);
964 strcpy(&buf[i], &buf[i+2]);
966 strcpy(&buf_nc[i], &buf_nc[i+1]);
967 strcpy(&buf[i], &buf[i+1]);
973 long buflen = strlen(buf);
974 if (write(fd_write, buf, buflen) != buflen) {
977 unlink(new_filename);
985 unlink(new_filename);
989 snprintf(question, sizeof question,
992 "/etc/nsswitch.conf is configured to use the 'db' module for\n"
993 "one or more services. This is not necessary on most systems,\n"
994 "and it is known to crash the Citadel server when delivering\n"
995 "mail to the Internet.\n"
997 "Do you want this module to be automatically disabled?\n"
1002 if (yesno(question, 1)) {
1003 snprintf(buf, sizeof buf, "/bin/mv -f %s %s", new_filename, NSSCONF);
1006 fprintf(stderr, "failed to edit %s.\n", NSSCONF);
1008 chmod(NSSCONF, 0644);
1010 unlink(new_filename);
1016 important_message(_("Setup finished"),
1017 _("Setup of the Citadel server is complete.\n"
1018 "If you will be using WebCit, please run its\n"
1019 "setup program now; otherwise, run './citadel'\n"
1021 important_message(_("Setup failed"),
1022 _("Setup is finished, but the Citadel server failed to start.\n"
1023 "Go back and check your configuration.\n")
1024 important_message(_("Setup finished"),
1025 _("Setup is finished. You may now start the server."));
1030 #define GetDefaultVALINT(CFGNAME, DEFL) GetDefaultValInt(&config.CFGNAME, "CITADEL_"#CFGNAME, DEFL)
1031 void GetDefaultValInt(int *WhereTo, const char *VarName, int DefVal)
1034 if (*WhereTo == 0) *WhereTo = DefVal;
1036 if ((setup_type == UI_SILENT) &&
1037 (ch = getenv(VarName), ch != NULL))
1039 *WhereTo = atoi(ch);
1042 #define GetDefaultVALCHAR(CFGNAME, DEFL) GetDefaultValChar(&config.CFGNAME, "CITADEL_"#CFGNAME, DEFL)
1043 void GetDefaultValChar(char *WhereTo, const char *VarName, char DefVal)
1046 if (*WhereTo == 0) *WhereTo = DefVal;
1048 if ((setup_type == UI_SILENT) &&
1049 (ch = getenv(VarName), ch != NULL))
1051 *WhereTo = atoi(ch);
1054 #define GetDefaultVALSTR(CFGNAME, DEFL) GetDefaultValStr(&config.CFGNAME[0], sizeof(config.CFGNAME), "CITADEL_"#CFGNAME, DEFL)
1055 void GetDefaultValStr(char *WhereTo, size_t nMax, const char *VarName, const char *DefVal)
1058 if (*WhereTo == '\0')
1059 safestrncpy(WhereTo, DefVal, nMax);
1061 if ((setup_type == UI_SILENT) &&
1062 (ch = getenv(VarName), ch != NULL))
1064 safestrncpy(WhereTo, ch, nMax);
1070 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], "-i")) {
1107 else if (!strcmp(argv[a], "-q")) {
1108 setup_type = UI_SILENT;
1110 else if (!strncmp(argv[a], "-h", 2)) {
1111 relh=argv[a][2]!='/';
1113 safestrncpy(ctdl_home_directory, &argv[a][2], sizeof ctdl_home_directory);
1115 safestrncpy(relhome, &argv[a][2], sizeof relhome);
1122 calc_dirs_n_files(relh, home, relhome, ctdldir, 0);
1125 /* If a setup type was not specified, try to determine automatically
1126 * the best one to use out of all available types.
1128 if (setup_type < 0) {
1129 setup_type = discover_ui();
1131 if (info_only == 1) {
1132 important_message(_("Citadel Setup"), CITADEL);
1136 enable_home = ( relh | home );
1138 if (chdir(ctdl_run_dir) != 0) {
1139 display_error("%s: [%s]\n",
1140 _("The directory you specified does not exist"),
1147 * Connect to the running Citadel server.
1149 while ((serv_sock < 0) && (nRetries < 10)) {
1150 serv_sock = uds_connectsock(file_citadel_admin_socket);
1155 if (serv_sock < 0) {
1158 _("Setup could not connect to a running Citadel server."),
1159 strerror(errno), file_citadel_admin_socket
1165 * read the server greeting
1168 if (buf[0] != '2') {
1169 display_error("%s\n", buf);
1174 * Are we connected to the correct Citadel server?
1178 if (buf[0] != '1') {
1179 display_error("%s\n", buf);
1183 while (serv_gets(buf), strcmp(buf, "000")) {
1185 if (atoi(buf) != REV_LEVEL) {
1186 display_error("%s\n",
1187 _("Your setup program and Citadel server are from different versions.")
1196 * Load the server's configuration
1198 serv_puts("CONF GET");
1200 if (buf[0] != '1') {
1201 display_error("%s\n", buf);
1204 memset(configs, 0, sizeof configs);
1206 while (serv_gets(buf), strcmp(buf, "000")) {
1207 if (a < NUM_CONFIGS) {
1208 safestrncpy(configs[a], buf, sizeof(configs[a]));
1217 /* _("Citadel Setup"), */
1219 if (setup_type == UI_TEXT) {
1220 printf("\n\n\n *** %s ***\n\n", program_title);
1223 if (setup_type == UI_DIALOG) {
1224 system("clear 2>/dev/null");
1227 /* Go through a series of dialogs prompting for config info */
1228 for (curr = 1; curr < eMaxQuestions; ++curr) {
1232 && (atoi(configs[52]) != AUTHMODE_LDAP)
1233 && (atoi(configs[52]) != AUTHMODE_LDAP_AD)
1235 curr += 5; /* skip LDAP questions if we're not authenticating against LDAP */
1238 if (curr == eSysAdminName) {
1239 if (atoi(configs[52]) == AUTHMODE_NATIVE) {
1240 /* for native auth mode, fetch the admin's existing pw */
1241 snprintf(buf, sizeof buf, "AGUP %s", configs[13]);
1244 if (buf[0] == '2') {
1245 extract_token(admin_pass, &buf[4], 1, '|', sizeof admin_pass);
1249 ++curr; /* skip the password question for non-native auth modes */
1254 if ((pw = getpwuid(atoi(configs[69]))) == NULL) {
1260 if (create_run_directories(atoi(configs[69]), gid) != 0) {
1261 display_error("%s\n",
1262 _("failed to create directories"));
1266 activity = _("Reconfiguring Citadel server");
1267 progress(activity, 0, NUM_CONFIGS+3);
1268 sleep(1); /* Let the message appear briefly */
1269 serv_puts("CONF SET");
1271 if (buf[0] == '4') {
1272 for (i=0; i<NUM_CONFIGS; ++i) {
1273 progress(activity, i+1, NUM_CONFIGS+3);
1274 serv_puts(configs[i]);
1278 sleep(1); /* Let the message appear briefly */
1281 * Create the administrator account. It's ok if the command fails if this user already exists.
1283 progress(activity, NUM_CONFIGS+1, NUM_CONFIGS+3);
1284 snprintf(buf, sizeof buf, "CREU %s|%s", configs[13], admin_pass);
1286 progress(activity, NUM_CONFIGS+2, NUM_CONFIGS+3);
1288 progress(activity, NUM_CONFIGS+3, NUM_CONFIGS+3);
1291 * Assign the desired password and access level to the administrator account.
1293 snprintf(buf, sizeof buf, "AGUP %s", configs[13]);
1296 if (buf[0] == '2') {
1297 int admin_flags = extract_int(&buf[4], 2);
1298 int admin_times_called = extract_int(&buf[4], 3);
1299 int admin_msgs_posted = extract_int(&buf[4], 4);
1300 snprintf(buf, sizeof buf, "ASUP %s|%s|%d|%d|%d|6",
1301 configs[13], admin_pass, admin_flags, admin_times_called, admin_msgs_posted
1308 check_xinetd_entry(); /* Check /etc/xinetd.d/telnet */
1309 disable_other_mtas(); /* Offer to disable other MTAs */
1310 fixnss(); /* Check for the 'db' nss and offer to disable it */
1313 activity = _("Setting file permissions");
1314 progress(activity, 0, 2);
1315 //chown(file_citadel_config, config.c_ctdluid, gid);
1316 progress(activity, 1, 2);
1317 chmod(file_citadel_config, S_IRUSR | S_IWUSR);
1318 progress(activity, 2, 2);
1323 activity = _("Restarting Citadel server to apply changes");
1324 progress(activity, 0, 41);
1328 long original_start_time = extract_long(&buf[4], 3);
1330 progress(activity, 1, 41);
1331 serv_puts("DOWN 1");
1332 progress(activity, 2, 41);
1334 if (buf[0] != '2') {
1335 display_error("%s\n", buf);
1342 for (i=3; i<=6; ++i) { /* wait for server to shut down */
1343 progress(activity, i, 41);
1347 for (i=7; ((i<=38) && (serv_sock < 0)) ; ++i) { /* wait for server to start up */
1348 progress(activity, i, 41);
1349 serv_sock = uds_connectsock(file_citadel_admin_socket);
1353 progress(activity, 39, 41);
1356 progress(activity, 40, 41);
1359 long new_start_time = extract_long(&buf[4], 3);
1362 progress(activity, 41, 41);
1364 if ( (original_start_time == new_start_time)
1365 || (new_start_time <= 0)
1367 display_error("%s\n",
1368 _("Setup failed to restart Citadel server. Please restart it manually.")