#include "tools.h"
#include "citadel_dirs.h"
-#ifdef HAVE_NEWT
-#include <newt.h>
-#endif
-
-
-#define MAXSETUP 4 /* How many setup questions to ask */
+#define MAXSETUP 5 /* How many setup questions to ask */
#define UI_TEXT 0 /* Default setup type -- text only */
#define UI_DIALOG 2 /* Use the 'dialog' program */
#define UI_SILENT 3 /* Silent running, for use in scripts */
-#define UI_NEWT 4 /* Use the "newt" window library */
#define SERVICE_NAME "citadel"
#define PROTO_NAME "tcp"
#define NSSCONF "/etc/nsswitch.conf"
int setup_type;
-char setup_directory[SIZ];
-char citserver_init_entry[SIZ];
+char setup_directory[PATH_MAX];
int using_web_installer = 0;
int enable_home = 1;
"Citadel User ID",
"Server IP address",
"Server port number",
+ "Authentication mode"
};
"of Citadel on the same computer and there is something else\n"
"already using port 504.\n",
+"Normally, a Citadel system uses a \"black box\" authentication mode.\n"
+"This means that users do not have accounts or home directories on\n"
+"the underlying host system -- Citadel manages its own user database.\n"
+"However, if you wish to override this behavior, you can enable the\n"
+"host based authentication mode which is traditional for Unix systems.\n"
+"WARNING: do *not* change this setting once your system is installed.\n"
+"\n"
+"(Answer \"no\" unless you completely understand this option)\n"
+"Do you want to enable host based authentication mode?\n"
+
};
struct config config;
void cleanup(int exitcode)
{
-#ifdef HAVE_NEWT
- newtCls();
- newtRefresh();
- newtFinished();
-#endif
exit(exitcode);
}
-int yesno(char *question)
+int yesno(char *question, int default_value)
{
-#ifdef HAVE_NEWT
- newtComponent form = NULL;
- newtComponent yesbutton = NULL;
- newtComponent nobutton = NULL;
- int prompt_window_height = 0;
-#endif
int i = 0;
int answer = 0;
char buf[SIZ];
case UI_TEXT:
do {
- printf("%s\nYes/No --> ", question);
+ printf("%s\nYes/No [%s] --> ",
+ question,
+ ( default_value ? "Yes" : "No" )
+ );
fgets(buf, sizeof buf, stdin);
answer = tolower(buf[0]);
- if (answer == 'y')
+ if ((buf[0]==0) || (buf[0]==13) || (buf[0]==10))
+ answer = default_value;
+ else if (answer == 'y')
answer = 1;
else if (answer == 'n')
answer = 0;
break;
case UI_DIALOG:
- sprintf(buf, "exec %s --yesno '%s' 10 72",
+ sprintf(buf, "exec %s %s --yesno '%s' 15 75",
getenv("CTDL_DIALOG"),
+ ( default_value ? "" : "--defaultno" ),
question);
i = system(buf);
if (i == 0) {
}
break;
-#ifdef HAVE_NEWT
- case UI_NEWT:
- prompt_window_height = num_tokens(question, '\n') + 5;
- newtCenteredWindow(76, prompt_window_height, "Question");
- form = newtForm(NULL, NULL, 0);
- for (i=0; i<num_tokens(question, '\n'); ++i) {
- extract_token(buf, question, i, '\n', sizeof buf);
- newtFormAddComponent(form, newtLabel(1, 1+i, buf));
- }
- yesbutton = newtButton(10, (prompt_window_height - 4), "Yes");
- nobutton = newtButton(60, (prompt_window_height - 4), "No");
- newtFormAddComponent(form, yesbutton);
- newtFormAddComponent(form, nobutton);
- if (newtRunForm(form) == yesbutton) {
- answer = 1;
- }
- else {
- answer = 0;
- }
- newtPopWindow();
- newtFormDestroy(form);
-
- break;
-#endif
-
}
return (answer);
}
void important_message(char *title, char *msgtext)
{
-#ifdef HAVE_NEWT
- newtComponent form = NULL;
- int i = 0;
-#endif
char buf[SIZ];
switch (setup_type) {
msgtext);
system(buf);
break;
-
-#ifdef HAVE_NEWT
- case UI_NEWT:
- newtCenteredWindow(76, 10, title);
- form = newtForm(NULL, NULL, 0);
- for (i=0; i<num_tokens(msgtext, '\n'); ++i) {
- extract_token(buf, msgtext, i, '\n', sizeof buf);
- newtFormAddComponent(form, newtLabel(1, 1+i, buf));
- }
- newtFormAddComponent(form, newtButton(35, 5, "OK"));
- newtRunForm(form);
- newtPopWindow();
- newtFormDestroy(form);
- break;
-#endif
-
}
}
void progress(char *text, long int curr, long int cmax)
{
-#ifdef HAVE_NEWT
-
- /* These variables are static because progress() gets called
- * multiple times during the course of whatever operation is
- * being performed. This makes setup non-threadsafe, but who
- * cares?
- */
- static newtComponent form = NULL;
- static newtComponent scale = NULL;
-#endif
static long dots_printed = 0L;
long a = 0;
static FILE *fp = NULL;
}
break;
-#ifdef HAVE_NEWT
- case UI_NEWT:
- if (curr == 0) {
- newtCenteredWindow(76, 8, text);
- form = newtForm(NULL, NULL, 0);
- scale = newtScale(1, 3, 74, cmax);
- newtFormAddComponent(form, scale);
- newtDrawForm(form);
- newtRefresh();
- }
- if ((curr > 0) && (curr <= cmax)) {
- newtScaleSet(scale, curr);
- newtRefresh();
- }
- if (curr == cmax) {
- newtFormDestroy(form);
- newtPopWindow();
- newtRefresh();
- }
- break;
-#endif
-
}
}
{
int i;
FILE *sfp;
+ char errmsg[256];
if (getservbyname(SERVICE_NAME, PROTO_NAME) == NULL) {
- for (i=0; i<=3; ++i) {
- progress("Adding service entry...", i, 3);
+ for (i=0; i<=2; ++i) {
+ progress("Adding service entry...", i, 2);
if (i == 0) {
sfp = fopen("/etc/services", "a");
if (sfp == NULL) {
- display_error(strerror(errno));
+ sprintf(errmsg, "Cannot open /etc/services: %s", strerror(errno));
+ display_error(errmsg);
} else {
- fprintf(sfp, "%s 504/tcp\n",
- SERVICE_NAME);
+ fprintf(sfp, "%s 504/tcp\n", SERVICE_NAME);
fclose(sfp);
}
}
- sleep(1);
}
}
}
/* Determine the fully qualified path name of citserver */
snprintf(looking_for,
- sizeof looking_for,
- "%s/citserver",
-#ifndef HAVE_RUN_DIR
- setup_directory
-#else
- CTDLDIR
-#endif
- );
+ sizeof looking_for,
+ "%s/citserver",
+ ctdl_sbin_dir
+ );
/* Now tweak /etc/inittab */
infp = fopen("/etc/inittab", "r");
if (infp == NULL) {
- display_error(strerror(errno));
+
+ /* If /etc/inittab does not exist, return quietly.
+ * Not all host platforms have it.
+ */
+ if (errno == ENOENT) {
+ return;
+ }
+
+ /* Other errors might mean something really did go wrong.
+ */
+ sprintf(buf, "Cannot open /etc/inittab: %s", strerror(errno));
+ display_error(buf);
return;
}
strcpy(outfilename, "/tmp/ctdlsetup.XXXXXX");
outfp = fdopen(mkstemp(outfilename), "w+");
if (outfp == NULL) {
- display_error(strerror(errno));
+ sprintf(buf, "Cannot open %s: %s", outfilename, strerror(errno));
+ display_error(buf);
fclose(infp);
return;
}
while (fgets(buf, sizeof buf, infp) != NULL) {
- if (strstr(buf, looking_for) == NULL) {
- fwrite(buf, strlen(buf), 1, outfp);
- }
- else {
+ if (strstr(buf, looking_for) != NULL) {
+ fwrite("#", 1, 1, outfp);
++changes_made;
}
+ fwrite(buf, strlen(buf), 1, outfp);
}
fclose(infp);
}
+/*
+ * install_init_scripts() -- Try to configure to start Citadel at boot
+ *
+ */
+void install_init_scripts(void)
+{
+ struct stat etcinitd;
+ FILE *fp;
+ char *initfile = "/etc/init.d/citadel";
+ char command[SIZ];
+
+ if (yesno("Would you like to automatically start Citadel at boot?\n", 1) == 0) {
+ return;
+ }
+
+ if ((stat("/etc/init.d/", &etcinitd) == -1) &&
+ (errno == ENOENT))
+ {
+ if ((stat("/etc/rc.d/init.d/", &etcinitd) == -1) &&
+ (errno == ENOENT))
+ initfile = CTDLDIR"/citadel.init";
+ else
+ initfile = "/etc/rc.d/init.d/citadel";
+ }
+
+ fp = fopen(initfile, "w");
+ if (fp == NULL) {
+ display_error("Cannot create /etc/init.d/citadel");
+ return;
+ }
+
+ fprintf(fp, "#!/bin/sh\n"
+ "#\n"
+ "# Init file for Citadel\n"
+ "#\n"
+ "# chkconfig: - 79 30\n"
+ "# description: Citadel service\n"
+ "# processname: citserver\n"
+ "# pidfile: %s/citadel.pid\n"
+ "\n"
+ "CITADEL_DIR=%s\n"
+ ,
+ setup_directory,
+ setup_directory
+ );
+ fprintf(fp, "\n"
+ "test -d /var/run || exit 0\n"
+ "\n"
+ "case \"$1\" in\n"
+ "\n"
+ "start) echo -n \"Starting Citadel... \"\n"
+ " if $CITADEL_DIR/citserver -d -h$CITADEL_DIR\n"
+ " then\n"
+ " echo \"ok\"\n"
+ " else\n"
+ " echo \"failed\"\n"
+ " fi\n");
+ fprintf(fp, " ;;\n"
+ "stop) echo -n \"Stopping Citadel... \"\n"
+ " if $CITADEL_DIR/sendcommand DOWN >/dev/null 2>&1 ; then\n"
+ " echo \"ok\"\n"
+ " else\n"
+ " echo \"failed\"\n"
+ " fi\n"
+ " rm -f %s/citadel.pid 2>/dev/null\n"
+ ,
+ setup_directory
+ );
+ fprintf(fp, " ;;\n"
+ "restart) $0 stop\n"
+ " $0 start\n"
+ " ;;\n"
+ "*) echo \"Usage: $0 {start|stop|restart}\"\n"
+ " exit 1\n"
+ " ;;\n"
+ "esac\n"
+ );
+
+ fclose(fp);
+ chmod(initfile, 0755);
+
+ /* Set up the run levels. */
+ system("/bin/rm -f /etc/rc?.d/[SK]??citadel 2>/dev/null");
+ 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);
+ system(command);
+ 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);
+ system(command);
+
+}
+
+
+
+
+
+
/*
* On systems which use xinetd, see if we can offer to install Citadel as
* the default telnet target.
"connect incoming telnet sessions to Citadel, bypassing the\n"
"host system login: prompt. Would you like to do this?\n"
);
- if (yesno(buf) == 0) {
+ if (yesno(buf, 1) == 0) {
return;
}
}
" server_args = -h -L %s/citadel\n"
" log_on_failure += USERID\n"
"}\n",
-#ifndef HAVE_RUN_DIR
- setup_directory
-#else
- RUN_DIR
-#endif
- );
+ ctdl_bin_dir);
fclose(fp);
/* Now try to restart the service */
"25, 110, and 143?\n",
mta, mta, mta, mta
);
- if (yesno(buf) == 0) {
+ if (yesno(buf, 1) == 0) {
return;
}
}
sprintf(cookie, "--test--%d--", getpid());
sprintf(cmd, "%s/sendcommand %s%s ECHO %s 2>&1",
-#ifndef HAVE_RUN_DIR
- setup_directory,
-#else
- CTDLDIR,
-#endif
- (enable_home)?"-h":"",
- (enable_home)?setup_directory:"",
- cookie);
+ ctdl_sbin_dir,
+ (enable_home)?"-h":"",
+ (enable_home)?ctdl_run_dir:"",
+ cookie);
fp = popen(cmd, "r");
if (fp == NULL) return(errno);
void strprompt(char *prompt_title, char *prompt_text, char *str)
{
-#ifdef HAVE_NEWT
- newtComponent form;
- char *result;
- int i;
- int prompt_window_height = 0;
-#endif
char buf[SIZ];
char setupmsg[SIZ];
char dialog_result[PATH_MAX];
}
break;
-#ifdef HAVE_NEWT
- case UI_NEWT:
-
- prompt_window_height = num_tokens(prompt_text, '\n') + 5 ;
- newtCenteredWindow(76,
- prompt_window_height,
- prompt_title);
- form = newtForm(NULL, NULL, 0);
- for (i=0; i<num_tokens(prompt_text, '\n'); ++i) {
- extract_token(buf, prompt_text, i, '\n', sizeof buf);
- newtFormAddComponent(form, newtLabel(1, 1+i, buf));
- }
- newtFormAddComponent(form,
- newtEntry(1,
- (prompt_window_height - 2),
- str,
- 74,
- (const char **) &result,
- NEWT_FLAG_RETURNEXIT)
- );
- newtRunForm(form);
- strcpy(str, result);
-
- newtPopWindow();
- newtFormDestroy(form);
-
-#endif
}
}
+void set_bool_val(int msgpos, int *ip) {
+ title(setup_titles[msgpos]);
+ *ip = yesno(setup_text[msgpos], *ip);
+}
+
void set_str_val(int msgpos, char *str) {
strprompt(setup_titles[msgpos], setup_text[msgpos], str);
}
-
-
void set_int_val(int msgpos, int *ip)
{
char buf[16];
{
int i;
struct passwd *pw;
- char ctdluidname[SIZ];
+ char ctdluidname[256];
switch (curr) {
case 1:
- if (getenv("SYSADMIN_NAME")) {
- strcpy(config.c_sysadm, getenv("SYSADMIN_NAME"));
+ if (setup_type == UI_SILENT)
+ {
+ if (getenv("SYSADMIN_NAME")) {
+ strcpy(config.c_sysadm, getenv("SYSADMIN_NAME"));
+ }
}
else {
set_str_val(curr, config.c_sysadm);
break;
case 2:
+ if (setup_type == UI_SILENT)
+ {
+ if (getenv("CITADEL_UID")) {
+ config.c_ctdluid = atoi(getenv("CITADEL_UID"));
+ }
+ }
+ else
+ {
#ifdef __CYGWIN__
- config.c_ctdluid = 0; /* XXX Windows hack, prob. insecure */
+ config.c_ctdluid = 0; /* XXX Windows hack, prob. insecure */
#else
- i = config.c_ctdluid;
- pw = getpwuid(i);
- if (pw == NULL) {
- set_int_val(curr, &i);
- config.c_ctdluid = i;
- }
- else {
- strcpy(ctdluidname, pw->pw_name);
- set_str_val(curr, ctdluidname);
- pw = getpwnam(ctdluidname);
- if (pw != NULL) {
- config.c_ctdluid = pw->pw_uid;
+ i = config.c_ctdluid;
+ pw = getpwuid(i);
+ if (pw == NULL) {
+ set_int_val(curr, &i);
+ config.c_ctdluid = i;
}
- else if (atoi(ctdluidname) > 0) {
- config.c_ctdluid = atoi(ctdluidname);
+ else {
+ strcpy(ctdluidname, pw->pw_name);
+ set_str_val(curr, ctdluidname);
+ pw = getpwnam(ctdluidname);
+ if (pw != NULL) {
+ config.c_ctdluid = pw->pw_uid;
+ }
+ else if (atoi(ctdluidname) > 0) {
+ config.c_ctdluid = atoi(ctdluidname);
+ }
}
}
#endif
break;
case 3:
- set_str_val(curr, config.c_ip_addr);
+ if (setup_type == UI_SILENT)
+ {
+ if (getenv("IP_ADDR")) {
+ strcpy(config.c_ip_addr, getenv("IP_ADDR"));
+ }
+ }
+ else {
+ set_str_val(curr, config.c_ip_addr);
+ }
break;
case 4:
- set_int_val(curr, &config.c_port_number);
+ if (setup_type == UI_SILENT)
+ {
+ if (getenv("CITADEL_PORT")) {
+ config.c_port_number = atoi(getenv("CITADEL_PORT"));
+ }
+ }
+ else
+ {
+ set_int_val(curr, &config.c_port_number);
+ }
break;
+ case 5:
+ if (setup_type == UI_SILENT)
+ {
+ if (getenv("ENABLE_UNIX_AUTH")) {
+ if (!strcasecmp(getenv("ENABLE_UNIX_AUTH"), "yes")) {
+ config.c_auth_mode = 1;
+ }
+ else {
+ config.c_auth_mode = 0;
+ }
+ }
+ }
+ else {
+ set_bool_val(curr, &config.c_auth_mode);
+ }
+ break;
}
}
return UI_DIALOG;
}
-
-#ifdef HAVE_NEWT
- newtInit();
- newtCls();
- newtDrawRootText(0, 0, "Citadel Setup");
- return UI_NEWT;
-#endif
return UI_TEXT;
}
"\n"
);
- if (yesno(question)) {
+ if (yesno(question, 1)) {
sprintf(buf, "/bin/mv -f %s %s", new_filename, NSSCONF);
system(buf);
}
}
/* Get started in a valid setup directory. */
- strcpy(setup_directory,
-#ifdef HAVE_RUN_DIR
- ""
-#else
- CTDLDIR
-#endif
- );
+ strcpy(setup_directory, ctdl_run_dir);
if ( (using_web_installer) && (getenv("CITADEL") != NULL) ) {
strcpy(setup_directory, getenv("CITADEL"));
}
/* Determine our host name, in case we need to use it as a default */
uname(&my_utsname);
+ /* Try to stop Citadel if we can */
+ if (!access("/etc/init.d/citadel", X_OK)) {
+ system("/etc/init.d/citadel stop");
+ }
+
/* Make sure Citadel is not running. */
if (test_server() == 0) {
important_message("Citadel Setup",
if (config.c_managesieve_port == 0) config.c_managesieve_port = 2020;
/* Go through a series of dialogs prompting for config info */
- if (setup_type != UI_SILENT) {
- for (curr = 1; curr <= MAXSETUP; ++curr) {
- edit_value(curr);
- }
+ for (curr = 1; curr <= MAXSETUP; ++curr) {
+ edit_value(curr);
}
/***** begin version update section ***** */
chmod(ctdl_netcfg_dir, 0700);
chown(ctdl_netcfg_dir, config.c_ctdluid, -1);
- /* TODO: where to put this? */
- mkdir("netconfigs", 0700);
- chmod("netconfigs", 0700);
- chown("netconfigs", config.c_ctdluid, -1);
-
/* Delete files and directories used by older Citadel versions */
system("exec /bin/rm -fr ./rooms ./chatpipes ./expressmsgs ./sessions 2>/dev/null");
unlink("citadel.log");
gid = pw->pw_gid;
progress("Setting file permissions", 0, 4);
- chown(".", config.c_ctdluid, gid);
- sleep(1);
+ chown(ctdl_run_dir, config.c_ctdluid, gid);
progress("Setting file permissions", 1, 4);
chown(file_citadel_config, config.c_ctdluid, gid);
- sleep(1);
progress("Setting file permissions", 2, 4);
snprintf(aaa, sizeof aaa,
"%schkpwd",
ctdl_sbin_dir);
chown(aaa,0,0); /* config.c_ctdluid, gid); chkpwd needs to be root owned*/
- sleep(1);
progress("Setting file permissions", 3, 4);
chmod(aaa, 04755);
- sleep(1);
progress("Setting file permissions", 3, 4);
chmod(file_citadel_config, S_IRUSR | S_IWUSR);
- sleep(1);
progress("Setting file permissions", 4, 4);
- /* See if we can start the Citadel service. */
- /* FIXME do this */
+ /*
+ * If we're running on SysV, install init scripts.
+ */
+ if (!access("/var/run", W_OK)) {
+
+ if (getenv("NO_INIT_SCRIPTS") == NULL) {
+ install_init_scripts();
+ }
+
+ if (!access("/etc/init.d/citadel", X_OK)) {
+ system("/etc/init.d/citadel start");
+ sleep(3);
+ }
+
+ if (test_server() == 0) {
+ important_message("Setup finished",
+ "Setup of the Citadel server is complete.\n"
+ "If you will be using WebCit, please run its\n"
+ "setup program now; otherwise, run './citadel'\n"
+ "to log in.\n");
+ }
+ else {
+ important_message("Setup failed",
+ "Setup is finished, but the Citadel server failed to start.\n"
+ "Go back and check your configuration.\n"
+ );
+ }
- if (test_server() == 0) {
- important_message("Setup finished",
- "Setup of the Citadel server is complete.\n"
- "If you will be using WebCit, please run its\n"
- "setup program now; otherwise, run './citadel'\n"
- "to log in.\n");
}
+
else {
important_message("Setup finished",
"Setup is finished. You may now start the server.");