#include <errno.h>
#include <limits.h>
#include <pwd.h>
+#include <time.h>
#include "citadel.h"
#include "axdefs.h"
#include "sysdep.h"
#include "config.h"
#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;
-
-#ifdef HAVE_LDAP
-void contemplate_ldap(void);
-#endif
+int enable_home = 1;
char *setup_titles[] =
{
"Citadel User ID",
"Server IP address",
"Server port number",
+ "Authentication mode"
};
+struct config config;
+
+ /* calculate all our path on a central place */
+ /* where to keep our config */
+
+
char *setup_text[] = {
+#ifndef HAVE_RUN_DIR
"Enter the full pathname of the directory in which the Citadel\n"
"installation you are creating or updating resides. If you\n"
"specify a directory other than the default, you will need to\n"
"specify the -h flag to the server when you start it up.\n",
+#else
+"Enter the subdirectory name for an alternate installation of "
+"Citadel. To do a default installation just leave it blank."
+"If you specify a directory other than the default, you will need to\n"
+"specify the -h flag to the server when you start it up.\n"
+"note that it may not have a leading /",
+#endif
"Enter the name of the system administrator (which is probably\n"
"you). When an account is created with this name, it will\n"
-"automatically be assigned the highest access level.\n",
+"automatically be given administrator-level access.\n",
"Citadel needs to run under its own user ID. This would\n"
"typically be called \"citadel\", but if you are running Citadel\n"
"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;
int direction;
-/*
- * Set an entry in inittab to the desired state
- */
-void set_init_entry(char *which_entry, char *new_state) {
- char *inittab = NULL;
- FILE *fp;
- char buf[SIZ];
- char entry[SIZ];
- char levels[SIZ];
- char state[SIZ];
- char prog[SIZ];
-
- if (which_entry == NULL) return;
- if (strlen(which_entry) == 0) return;
-
- inittab = strdup("");
- if (inittab == NULL) return;
-
- fp = fopen("/etc/inittab", "r");
- if (fp == NULL) return;
-
- while(fgets(buf, sizeof buf, fp) != NULL) {
-
- if (num_tokens(buf, ':') == 4) {
- extract_token(entry, buf, 0, ':');
- extract_token(levels, buf, 1, ':');
- extract_token(state, buf, 2, ':');
- extract_token(prog, buf, 3, ':'); /* includes 0x0a LF */
-
- if (!strcmp(entry, which_entry)) {
- strcpy(state, new_state);
- sprintf(buf, "%s:%s:%s:%s",
- entry, levels, state, prog);
- }
- }
-
- inittab = realloc(inittab, strlen(inittab) + strlen(buf) + 2);
- if (inittab == NULL) {
- fclose(fp);
- return;
- }
-
- strcat(inittab, buf);
- }
- fclose(fp);
- fp = fopen("/etc/inittab", "w");
- if (fp != NULL) {
- fwrite(inittab, strlen(inittab), 1, fp);
- fclose(fp);
- kill(1, SIGHUP); /* Tell init to re-read /etc/inittab */
- }
- free(inittab);
-}
-
-
-/*
- * Locate the name of an inittab entry for a specific program
- */
-void locate_init_entry(char *init_entry, char *looking_for) {
-
- FILE *infp;
- char buf[SIZ];
- int have_entry = 0;
- char entry[SIZ];
- char prog[SIZ];
-
- strcpy(init_entry, "");
-
- /* Pound through /etc/inittab line by line. Set have_entry to 1 if
- * an entry is found which we believe starts the specified program.
- */
- infp = fopen("/etc/inittab", "r");
- if (infp == NULL) {
- return;
- } else {
- while (fgets(buf, sizeof buf, infp) != NULL) {
- buf[strlen(buf) - 1] = 0;
- extract_token(entry, buf, 0, ':');
- extract_token(prog, buf, 3, ':');
- if (!strncasecmp(prog, looking_for,
- strlen(looking_for))) {
- ++have_entry;
- strcpy(init_entry, entry);
- }
- }
- fclose(infp);
- }
-
-}
-
-
-/*
- * Shut down the Citadel service if necessary, during setup.
- */
-void shutdown_citserver(void) {
- char looking_for[SIZ];
-
- snprintf(looking_for, sizeof looking_for, "%s/citserver", setup_directory);
- locate_init_entry(citserver_init_entry, looking_for);
- if (strlen(citserver_init_entry) > 0) {
- set_init_entry(citserver_init_entry, "off");
- }
-}
-
-
-/*
- * Start the Citadel service.
- */
-void start_citserver(void) {
- if (strlen(citserver_init_entry) > 0) {
- set_init_entry(citserver_init_entry, "respawn");
- }
-}
-
-
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');
- 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) {
break;
case UI_DIALOG:
- sprintf(buf, "exec %s --backtitle '%s' --msgbox '%s' 19 72",
+ sprintf(buf, "exec %s --msgbox '%s' 19 72",
getenv("CTDL_DIALOG"),
- title,
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');
- 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);
}
}
}
+
+
/*
- * Generate a unique entry name for a new inittab entry
+ * delete_inittab_entry() -- Remove obsolete /etc/inittab entry for Citadel
+ *
*/
-void generate_entry_name(char *entryname) {
- char buf[SIZ];
+void delete_inittab_entry(void)
+{
+ FILE *infp;
+ FILE *outfp;
+ char looking_for[256];
+ char buf[1024];
+ char outfilename[32];
+ int changes_made = 0;
- snprintf(entryname, sizeof entryname, "c0");
- do {
- ++entryname[1];
- if (entryname[1] > '9') {
- entryname[1] = 0;
- ++entryname[0];
- if (entryname[0] > 'z') {
- display_error(
- "Can't generate a unique entry name");
- return;
- }
+ /* Determine the fully qualified path name of citserver */
+ snprintf(looking_for,
+ sizeof looking_for,
+ "%s/citserver",
+ ctdl_sbin_dir
+ );
+
+ /* Now tweak /etc/inittab */
+ infp = fopen("/etc/inittab", "r");
+ if (infp == NULL) {
+
+ /* If /etc/inittab does not exist, return quietly.
+ * Not all host platforms have it.
+ */
+ if (errno == ENOENT) {
+ return;
}
- snprintf(buf, sizeof buf,
- "grep %s: /etc/inittab >/dev/null 2>&1", entryname);
- } while (system(buf) == 0);
-}
+ /* 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) {
+ 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("#", 1, 1, outfp);
+ ++changes_made;
+ }
+ fwrite(buf, strlen(buf), 1, outfp);
+ }
+
+ fclose(infp);
+ fclose(outfp);
+
+ if (changes_made) {
+ sprintf(buf, "/bin/mv -f %s /etc/inittab 2>/dev/null", outfilename);
+ system(buf);
+ system("/sbin/init q 2>/dev/null");
+ }
+ else {
+ unlink(outfilename);
+ }
+}
/*
- * check_inittab_entry() -- Make sure "citadel" is in /etc/inittab
+ * install_init_scripts() -- Try to configure to start Citadel at boot
*
*/
-void check_inittab_entry(void)
+void install_init_scripts(void)
{
- FILE *infp;
- char looking_for[SIZ];
- char question[SIZ];
- char entryname[5];
-
- /* Determine the fully qualified path name of citserver */
- snprintf(looking_for, sizeof looking_for, "%s/citserver", setup_directory);
- locate_init_entry(citserver_init_entry, looking_for);
+ struct stat etcinitd;
+ FILE *fp;
+ char *initfile = "/etc/init.d/citadel";
+ char command[SIZ];
- /* If there's already an entry, then we have nothing left to do. */
- if (strlen(citserver_init_entry) > 0) {
+ if (yesno("Would you like to automatically start Citadel at boot?\n", 1) == 0) {
return;
}
- /* Otherwise, prompt the user to create an entry. */
- snprintf(question, sizeof question,
- "Do you want this computer configured to start the Citadel\n"
- "service automatically? (If you answer yes, an entry in\n"
- "/etc/inittab pointing to %s will be added.)\n",
- looking_for);
- if (yesno(question) == 0)
+ 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;
+ }
- /* Generate a unique entry name for /etc/inittab */
- generate_entry_name(entryname);
+ 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);
- /* Now write it out to /etc/inittab */
- infp = fopen("/etc/inittab", "a");
- if (infp == NULL) {
- display_error(strerror(errno));
- } else {
- fprintf(infp, "# Start the Citadel server...\n");
- fprintf(infp, "%s:2345:respawn:%s -h%s -x3 -llocal4\n",
- entryname, looking_for, setup_directory);
- fclose(infp);
- strcpy(citserver_init_entry, entryname);
- }
}
+
+
+
+
/*
* On systems which use xinetd, see if we can offer to install Citadel as
* the default telnet target.
if (already_citadel) return; /* Already set up this way. */
/* Otherwise, prompt the user to create an entry. */
- snprintf(buf, sizeof buf,
- "Setup can configure the \"xinetd\" service to automatically\n"
- "connect incoming telnet sessions to Citadel, bypassing the\n"
- "host system login: prompt. Would you like to do this?\n"
- );
- if (yesno(buf) == 0)
- return;
+ if (getenv("CREATE_XINETD_ENTRY") != NULL) {
+ if (strcasecmp(getenv("CREATE_XINETD_ENTRY"), "yes")) {
+ return;
+ }
+ }
+ else {
+ snprintf(buf, sizeof buf,
+ "Setup can configure the \"xinetd\" service to automatically\n"
+ "connect incoming telnet sessions to Citadel, bypassing the\n"
+ "host system login: prompt. Would you like to do this?\n"
+ );
+ if (yesno(buf, 1) == 0) {
+ return;
+ }
+ }
fp = fopen(filename, "w");
fprintf(fp,
" server_args = -h -L %s/citadel\n"
" log_on_failure += USERID\n"
"}\n",
- setup_directory
- );
+ ctdl_bin_dir);
fclose(fp);
/* Now try to restart the service */
fclose(fp);
if (lines == 0) return; /* Nothing to do. */
+
/* Offer to replace other MTA with the vastly superior Citadel :) */
- snprintf(buf, sizeof buf,
- "You appear to have the \"%s\" email program\n"
- "running on your system. Would you like to disable it,\n"
- "allowing Citadel to handle your Internet mail instead?\n",
- mta
- );
- if (yesno(buf) == 0)
- return;
+
+ if (getenv("ACT_AS_MTA")) {
+ if (strcasecmp(getenv("ACT_AS_MTA"), "yes")) {
+ return;
+ }
+ }
+ else {
+ snprintf(buf, sizeof buf,
+ "You appear to have the \"%s\" email program\n"
+ "running on your system. If you want Citadel mail\n"
+ "connected with %s, you will have to manually integrate\n"
+ "them. It is preferable to disable %s, and use Citadel's\n"
+ "SMTP, POP3, and IMAP services.\n\n"
+ "May we disable %s so that Citadel has access to ports\n"
+ "25, 110, and 143?\n",
+ mta, mta, mta, mta
+ );
+ if (yesno(buf, 1) == 0) {
+ return;
+ }
+ }
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);
system(buf);
* to the server and try to get it back. The cookie does not
* have to be secret ... just unique.
*/
- sprintf(cookie, "%ld.%d", time(NULL), getpid());
+ sprintf(cookie, "--test--%d--", getpid());
- sprintf(cmd, "%s/sendcommand -h%s ECHO %s 2>&1",
- setup_directory,
- setup_directory,
+ sprintf(cmd, "%s/sendcommand %s%s ECHO %s 2>&1",
+ ctdl_sbin_dir,
+ (enable_home)?"-h":"",
+ (enable_home)?ctdl_run_dir:"",
cookie);
fp = popen(cmd, "r");
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;
+ char dialog_result[PATH_MAX];
FILE *fp = NULL;
strcpy(setupmsg, "");
break;
case UI_DIALOG:
- dialog_result = tmpnam(NULL);
- sprintf(buf, "exec %s --backtitle '%s' --inputbox '%s' 19 72 '%s' 2>%s",
+ CtdlMakeTempFileName(dialog_result, sizeof dialog_result);
+ sprintf(buf, "exec %s --inputbox '%s' 19 72 '%s' 2>%s",
getenv("CTDL_DIALOG"),
- prompt_title,
prompt_text,
str,
dialog_result);
}
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');
- newtFormAddComponent(form, newtLabel(1, 1+i, buf));
- }
- newtFormAddComponent(form,
- newtEntry(1,
- (prompt_window_height - 2),
- str,
- 74,
- &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 bbsuidname[SIZ];
+ char ctdluidname[256];
switch (curr) {
case 1:
- set_str_val(curr, config.c_sysadm);
+ 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_bbsuid = 0; /* XXX Windows hack, prob. insecure */
+ config.c_ctdluid = 0; /* XXX Windows hack, prob. insecure */
#else
- i = config.c_bbsuid;
- pw = getpwuid(i);
- if (pw == NULL) {
- set_int_val(curr, &i);
- config.c_bbsuid = i;
- }
- else {
- strcpy(bbsuidname, pw->pw_name);
- set_str_val(curr, bbsuidname);
- pw = getpwnam(bbsuidname);
- if (pw != NULL) {
- config.c_bbsuid = 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(bbsuidname) > 0) {
- config.c_bbsuid = atoi(bbsuidname);
+ 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;
}
}
FILE *fp;
int fd;
- if ((fd = creat("citadel.config", S_IRUSR | S_IWUSR)) == -1) {
+ if ((fd = creat(file_citadel_config, S_IRUSR | S_IWUSR)) == -1) {
display_error("setup: cannot open citadel.config");
cleanup(1);
}
return UI_DIALOG;
}
-
-#ifdef HAVE_NEWT
- newtInit();
- newtCls();
- newtDrawRootText(0, 0, "Citadel Setup");
- return UI_NEWT;
-#endif
return UI_TEXT;
}
+/*
+ * Strip "db" entries out of /etc/nsswitch.conf
+ */
+void fixnss(void) {
+ FILE *fp_read;
+ int fd_write;
+ char buf[256];
+ char buf_nc[256];
+ char question[512];
+ int i;
+ int changed = 0;
+ int file_changed = 0;
+ char new_filename[64];
+
+ fp_read = fopen(NSSCONF, "r");
+ if (fp_read == NULL) {
+ return;
+ }
+
+ strcpy(new_filename, "/tmp/ctdl_fixnss_XXXXXX");
+ fd_write = mkstemp(new_filename);
+ if (fd_write < 0) {
+ fclose(fp_read);
+ return;
+ }
+
+ while (fgets(buf, sizeof buf, fp_read) != NULL) {
+ changed = 0;
+ strcpy(buf_nc, buf);
+ for (i=0; i<strlen(buf_nc); ++i) {
+ if (buf_nc[i] == '#') {
+ buf_nc[i] = 0;
+ }
+ }
+ for (i=0; i<strlen(buf_nc); ++i) {
+ if (!strncasecmp(&buf_nc[i], "db", 2)) {
+ if (i > 0) {
+ if ((isspace(buf_nc[i+2])) || (buf_nc[i+2]==0)) {
+ changed = 1;
+ file_changed = 1;
+ strcpy(&buf_nc[i], &buf_nc[i+2]);
+ strcpy(&buf[i], &buf[i+2]);
+ if (buf[i]==32) {
+ strcpy(&buf_nc[i], &buf_nc[i+1]);
+ strcpy(&buf[i], &buf[i+1]);
+ }
+ }
+ }
+ }
+ }
+ if (write(fd_write, buf, strlen(buf)) != strlen(buf)) {
+ fclose(fp_read);
+ close(fd_write);
+ unlink(new_filename);
+ return;
+ }
+ }
+
+ fclose(fp_read);
+
+ if (!file_changed) {
+ unlink(new_filename);
+ return;
+ }
+
+ snprintf(question, sizeof question,
+ "\n"
+ "/etc/nsswitch.conf is configured to use the 'db' module for\n"
+ "one or more services. This is not necessary on most systems,\n"
+ "and it is known to crash the Citadel server when delivering\n"
+ "mail to the Internet.\n"
+ "\n"
+ "Do you want this module to be automatically disabled?\n"
+ "\n"
+ );
+
+ if (yesno(question, 1)) {
+ sprintf(buf, "/bin/mv -f %s %s", new_filename, NSSCONF);
+ system(buf);
+ }
+ unlink(new_filename);
+}
+
+
+
+
+
+
+
+
int main(int argc, char *argv[])
{
int a;
- int curr;
+ int curr;
char aaa[128];
FILE *fp;
int old_setup_level = 0;
struct passwd *pw;
struct hostent *he;
gid_t gid;
-
+ int relh=0;
+ int home=0;
+ char relhome[PATH_MAX]="";
+ char ctdldir[PATH_MAX]=CTDLDIR;
+
/* set an invalid setup type */
setup_type = (-1);
- /* Check to see if we're running the web installer */
+ /* Check to see if we're running the web installer */
if (getenv("CITADEL_INSTALLER") != NULL) {
using_web_installer = 1;
}
}
/* Get started in a valid setup directory. */
- strcpy(setup_directory, BBSDIR);
+ strcpy(setup_directory, ctdl_run_dir);
if ( (using_web_installer) && (getenv("CITADEL") != NULL) ) {
strcpy(setup_directory, getenv("CITADEL"));
}
set_str_val(0, setup_directory);
}
- if (chdir(setup_directory) != 0) {
- important_message("Citadel Setup",
- "The directory you specified does not exist.");
- cleanup(errno);
+ home=(setup_directory[1]!='\0');
+ relh=home&(setup_directory[1]!='/');
+ if (!relh) {
+ safestrncpy(ctdl_home_directory, setup_directory, sizeof ctdl_home_directory);
+ }
+ else {
+ safestrncpy(relhome, ctdl_home_directory, sizeof relhome);
+ }
+
+ calc_dirs_n_files(relh, home, relhome, ctdldir);
+
+ enable_home=(relh|home);
+
+ if (home) {
+ if (chdir(setup_directory) == 0) {
+ strcpy(file_citadel_config, "./citadel.config");
+ }
+ else {
+ important_message("Citadel Setup",
+ "The directory you specified does not exist.");
+ cleanup(errno);
+ }
}
/* Determine our host name, in case we need to use it as a default */
uname(&my_utsname);
- /* See if we need to shut down the Citadel service. */
- for (a=0; a<=3; ++a) {
- progress("Shutting down the Citadel service...", a, 3);
- if (a == 0) shutdown_citserver();
- sleep(1);
+ /* Try to stop Citadel if we can */
+ if (!access("/etc/init.d/citadel", X_OK)) {
+ system("/etc/init.d/citadel stop");
}
- /* Make sure it's stopped. */
+ /* Make sure Citadel is not running. */
if (test_server() == 0) {
important_message("Citadel Setup",
"The Citadel service is still running.\n"
case UI_TEXT:
printf("\n\n\n"
- " *** Citadel setup program ***\n\n");
+ " *** Citadel setup program ***\n\n");
break;
}
* to be when we rewrite it, because we replace the old file with a
* completely new copy.
*/
-
- if ((a = open("citadel.config", O_WRONLY | O_CREAT | O_APPEND,
+ if ((a = open(file_citadel_config, O_WRONLY | O_CREAT | O_APPEND,
S_IRUSR | S_IWUSR)) == -1) {
display_error("setup: cannot append citadel.config");
cleanup(errno);
fclose(fp);
/* now we re-open it, and read the old or blank configuration */
- fp = fopen("citadel.config", "rb");
+ fp = fopen(file_citadel_config, "rb");
if (fp == NULL) {
display_error("setup: cannot open citadel.config");
cleanup(errno);
if (strlen(config.c_twitroom) == 0)
strcpy(config.c_twitroom, "Trashcan");
if (strlen(config.c_baseroom) == 0)
- strcpy(config.c_baseroom, "Lobby");
+ strcpy(config.c_baseroom, BASEROOM);
if (strlen(config.c_aideroom) == 0)
strcpy(config.c_aideroom, "Aide");
if (config.c_port_number == 0) {
if (config.c_sleeping == 0) {
config.c_sleeping = 900;
}
- if (config.c_bbsuid == 0) {
+ if (config.c_ctdluid == 0) {
pw = getpwnam("citadel");
if (pw != NULL)
- config.c_bbsuid = pw->pw_uid;
+ config.c_ctdluid = pw->pw_uid;
}
- if (config.c_bbsuid == 0) {
+ if (config.c_ctdluid == 0) {
pw = getpwnam("bbs");
if (pw != NULL)
- config.c_bbsuid = pw->pw_uid;
+ config.c_ctdluid = pw->pw_uid;
}
- if (config.c_bbsuid == 0) {
+ if (config.c_ctdluid == 0) {
pw = getpwnam("guest");
if (pw != NULL)
- config.c_bbsuid = pw->pw_uid;
+ config.c_ctdluid = pw->pw_uid;
}
if (config.c_createax == 0) {
config.c_createax = 3;
}
/* We need a system default message expiry policy, because this is
* the top level and there's no 'higher' policy to fall back on.
+ * By default, do not expire messages at all.
*/
if (config.c_ep.expire_mode == 0) {
- config.c_ep.expire_mode = EXPIRE_NUMMSGS;
- config.c_ep.expire_value = 150;
+ config.c_ep.expire_mode = EXPIRE_MANUAL;
+ config.c_ep.expire_value = 0;
}
/*
if (config.c_smtps_port == 0) config.c_smtps_port = 465;
if (config.c_pop3s_port == 0) config.c_pop3s_port = 995;
if (config.c_imaps_port == 0) config.c_imaps_port = 993;
+ if (config.c_pftcpdict_port == 0) config.c_pftcpdict_port = -1;
+ 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);
}
- /*
- if (setuid(config.c_bbsuid) != 0) {
- important_message("Citadel Setup",
- "Failed to change the user ID to your Citadel user.");
- cleanup(errno);
- }
- */
-
/***** begin version update section ***** */
/* take care of any updating that is necessary */
write_config_to_disk();
- mkdir("info", 0700);
- chmod("info", 0700);
- mkdir("bio", 0700);
- chmod("bio", 0700);
- mkdir("userpics", 0700);
- chmod("userpics", 0700);
- mkdir("messages", 0700);
- chmod("messages", 0700);
- mkdir("help", 0700);
- chmod("help", 0700);
- mkdir("images", 0700);
- chmod("images", 0700);
- mkdir("netconfigs", 0700);
- chmod("netconfigs", 0700);
+ mkdir(ctdl_info_dir, 0700);
+ chmod(ctdl_info_dir, 0700);
+ chown(ctdl_info_dir, config.c_ctdluid, -1);
+
+ mkdir(ctdl_bio_dir, 0700);
+ chmod(ctdl_bio_dir, 0700);
+ chown(ctdl_bio_dir, config.c_ctdluid, -1);
+
+ mkdir(ctdl_usrpic_dir, 0700);
+ chmod(ctdl_usrpic_dir, 0700);
+ chown(ctdl_usrpic_dir, config.c_ctdluid, -1);
+
+ mkdir(ctdl_message_dir, 0700);
+ chmod(ctdl_message_dir, 0700);
+ chown(ctdl_message_dir, config.c_ctdluid, -1);
+
+ mkdir(ctdl_hlp_dir, 0700);
+ chmod(ctdl_hlp_dir, 0700);
+ chown(ctdl_hlp_dir, config.c_ctdluid, -1);
+
+ mkdir(ctdl_image_dir, 0700);
+ chmod(ctdl_image_dir, 0700);
+ chown(ctdl_image_dir, config.c_ctdluid, -1);
+
+ mkdir(ctdl_bb_dir, 0700);
+ chmod(ctdl_bb_dir, 0700);
+ chown(ctdl_bb_dir, config.c_ctdluid, -1);
+
+ mkdir(ctdl_file_dir, 0700);
+ chmod(ctdl_file_dir, 0700);
+ chown(ctdl_file_dir, config.c_ctdluid, -1);
+
+ mkdir(ctdl_netcfg_dir, 0700);
+ chmod(ctdl_netcfg_dir, 0700);
+ chown(ctdl_netcfg_dir, 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");
check_services_entry(); /* Check /etc/services */
#ifndef __CYGWIN__
- check_inittab_entry(); /* Check /etc/inittab */
+ delete_inittab_entry(); /* Remove obsolete /etc/inittab entry */
check_xinetd_entry(); /* Check /etc/xinetd.d/telnet */
/* Offer to disable other MTA's on the system. */
- disable_other_mta("sendmail");
- disable_other_mta("postfix");
- disable_other_mta("qmail");
- disable_other_mta("cyrus");
- disable_other_mta("cyrmaster");
- disable_other_mta("saslauthd");
- disable_other_mta("mta");
+ disable_other_mta("courier-authdaemon");
disable_other_mta("courier-imap");
disable_other_mta("courier-imap-ssl");
- disable_other_mta("courier-authdaemon");
+ disable_other_mta("courier-pop");
disable_other_mta("courier-pop3");
disable_other_mta("courier-pop3d");
- disable_other_mta("courier-pop");
- disable_other_mta("vmailmgrd");
+ disable_other_mta("cyrmaster");
+ disable_other_mta("cyrus");
+ disable_other_mta("dovecot");
+ disable_other_mta("exim");
+ disable_other_mta("exim4");
+ disable_other_mta("hula");
disable_other_mta("imapd");
- disable_other_mta("popd");
+ disable_other_mta("mta");
disable_other_mta("pop3d");
- disable_other_mta("exim");
- disable_other_mta("dovecot");
+ disable_other_mta("popd");
+ disable_other_mta("postfix");
+ disable_other_mta("qmail");
+ disable_other_mta("saslauthd");
+ disable_other_mta("sendmail");
+ disable_other_mta("vmailmgrd");
+ disable_other_mta("zimbra");
#endif
- if ((pw = getpwuid(config.c_bbsuid)) == NULL)
+ /* Check for the 'db' nss and offer to disable it */
+ fixnss();
+
+ if ((pw = getpwuid(config.c_ctdluid)) == NULL)
gid = getgid();
else
gid = pw->pw_gid;
progress("Setting file permissions", 0, 4);
- chown(".", config.c_bbsuid, gid);
- sleep(1);
+ chown(ctdl_run_dir, config.c_ctdluid, gid);
progress("Setting file permissions", 1, 4);
- chown("citadel.config", config.c_bbsuid, gid);
- sleep(1);
+ chown(file_citadel_config, config.c_ctdluid, gid);
progress("Setting file permissions", 2, 4);
+
snprintf(aaa, sizeof aaa,
- "find . | grep -v chkpwd | xargs chown %ld:%ld 2>/dev/null",
- (long)config.c_bbsuid, (long)gid);
- system(aaa);
- sleep(1);
+ "%schkpwd",
+ ctdl_sbin_dir);
+ chown(aaa,0,0); /* config.c_ctdluid, gid); chkpwd needs to be root owned*/
progress("Setting file permissions", 3, 4);
- chmod("citadel.config", S_IRUSR | S_IWUSR);
- sleep(1);
+ chmod(aaa, 04755);
+
+ progress("Setting file permissions", 3, 4);
+ chmod(file_citadel_config, S_IRUSR | S_IWUSR);
progress("Setting file permissions", 4, 4);
-#ifdef HAVE_LDAP
- /* Contemplate the possibility of auto-configuring OpenLDAP */
- contemplate_ldap();
-#endif
+ /*
+ * If we're running on SysV, install init scripts.
+ */
+ if (!access("/var/run", W_OK)) {
+
+ if (getenv("NO_INIT_SCRIPTS") == NULL) {
+ install_init_scripts();
+ }
- /* See if we can start the Citadel service. */
- if (strlen(citserver_init_entry) > 0) {
- for (a=0; a<=3; ++a) {
- progress("Starting the Citadel service...", a, 3);
- if (a == 0) start_citserver();
- sleep(1);
+ 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 is finished. You may now log in.");
+ "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, but the Citadel service "
- "failed to start.\n"
- "Go back and check your configuration.");
+ important_message("Setup failed",
+ "Setup is finished, but the Citadel server failed to start.\n"
+ "Go back and check your configuration.\n"
+ );
}
+
}
+
else {
important_message("Setup finished",
"Setup is finished. You may now start the server.");
}
-#ifdef HAVE_LDAP
-/*
- * If we're in the middle of an Easy Install, we might just be able to
- * auto-configure a standalone OpenLDAP server.
- */
-void contemplate_ldap(void) {
- char question[SIZ];
- char slapd_init_entry[SIZ];
- FILE *fp;
-
- /* If conditions are not ideal, give up on this idea... */
- if (using_web_installer == 0) return;
- if (getenv("LDAP_CONFIG") == NULL) return;
- if (getenv("SUPPORT") == NULL) return;
- if (getenv("SLAPD_BINARY") == NULL) return;
- if (getenv("CITADEL") == NULL) return;
-
- /* And if inittab is already starting slapd, bail out... */
- locate_init_entry(slapd_init_entry, getenv("SLAPD_BINARY"));
- if (strlen(slapd_init_entry) > 0) {
- important_message("Citadel Setup",
- "You appear to already have a standalone LDAP "
- "service\nconfigured for use with Citadel. No "
- "changes will be made.\n");
- /* set_init_entry(slapd_init_entry, "off"); */
- return;
- }
-
- /* Generate a unique entry name for slapd if we don't have one. */
- else {
- generate_entry_name(slapd_init_entry);
- }
-
- /* Ask the user if it's ok to set up slapd automatically. */
- snprintf(question, sizeof question,
- "\n"
- "Do you want this computer configured to start a standalone\n"
- "LDAP service automatically? (If you answer yes, a new\n"
- "slapd.conf will be written, and an /etc/inittab entry\n"
- "pointing to %s will be added.)\n"
- "\n",
- getenv("SLAPD_BINARY")
- );
- if (yesno(question) == 0)
- return;
-
- strcpy(config.c_ldap_base_dn, "dc=example,dc=com");
- strprompt("Base DN",
- "\n"
- "Please enter the Base DN for your directory. This will\n"
- "generally be something based on the primary DNS domain in\n"
- "which you receive mail, but it does not have to be. Your\n"
- "LDAP tree will be built using this Distinguished Name.\n"
- "\n",
- config.c_ldap_base_dn
- );
-
- strcpy(config.c_ldap_host, "localhost");
- config.c_ldap_port = 389;
- sprintf(config.c_ldap_bind_dn, "cn=manager,%s", config.c_ldap_base_dn);
-
- /*
- * Generate a bind password. If you're some grey hat hacker who
- * is just dying to get some street cred on Bugtraq, and you think
- * this password generation scheme is too weak, please submit a patch
- * instead of just whining about it, ok?
- */
- sprintf(config.c_ldap_bind_pw, "%d%ld", getpid(), time(NULL));
-
- write_config_to_disk();
-
- fp = fopen(getenv("LDAP_CONFIG"), "w");
- if (fp == NULL) {
- sprintf(question, "\nCannot create %s:\n%s\n\n"
- "Citadel will still function, but you will "
- "not have an LDAP service.\n\n",
- getenv("LDAP_CONFIG"),
- strerror(errno)
- );
- important_message("Error", question);
- return;
- }
-
- fprintf(fp, "include %s/citadel-openldap.schema\n",
- getenv("CITADEL"));
- fprintf(fp, "pidfile %s/openldap-data/slapd.pid\n",
- getenv("CITADEL"));
- fprintf(fp, "argsfile %s/openldap-data/slapd.args\n",
- getenv("CITADEL"));
- fprintf(fp, "allow bind_v2\n"
- "database bdb\n"
- "schemacheck off\n"
- );
- fprintf(fp, "suffix \"%s\"\n", config.c_ldap_base_dn);
- fprintf(fp, "rootdn \"%s\"\n", config.c_ldap_bind_dn);
- fprintf(fp, "rootpw %s\n", config.c_ldap_bind_pw);
- fprintf(fp, "directory %s/openldap-data\n",
- getenv("CITADEL"));
- fprintf(fp, "index objectClass eq\n");
-
- fclose(fp);
-
- /* This is where our OpenLDAP server will keep its data. */
- mkdir("openldap-data", 0700);
-
- /* Now write it out to /etc/inittab.
- * FIXME make it run as some non-root user.
- * The "-d 0" seems superfluous, but it's actually a way to make
- * slapd run in the foreground without spewing messages to the console.
- */
- fp = fopen("/etc/inittab", "a");
- if (fp == NULL) {
- display_error(strerror(errno));
- } else {
- fprintf(fp, "# Start the OpenLDAP server for Citadel...\n");
- fprintf(fp, "%s:2345:respawn:%s -d 0 -f %s\n",
- slapd_init_entry,
- getenv("SLAPD_BINARY"),
- getenv("LDAP_CONFIG")
- );
- fclose(fp);
- }
-
-}
-#endif /* HAVE_LDAP */