]> code.citadel.org Git - citadel.git/blobdiff - citadel/setup.c
Create some directories to hold the source files for the utility
[citadel.git] / citadel / setup.c
index b1c6487db1bec58e7a1260110d2490b81a5d7c8e..38c8be06c9ff9a5ead5fa0c04938ca71a727d059 100644 (file)
 #include <limits.h>
 #include <pwd.h>
 #include <time.h>
-
+#include <libcitadel.h>
 #include "citadel.h"
 #include "axdefs.h"
 #include "sysdep.h"
 #include "config.h"
-#include "tools.h"
 #include "citadel_dirs.h"
+#if HAVE_BACKTRACE
+#include <execinfo.h>
+#endif
+
 
-#define MAXSETUP     /* How many setup questions to ask */
+#define MAXSETUP 11    /* How many setup questions to ask */
 
 #define UI_TEXT                0       /* Default setup type -- text only */
 #define UI_DIALOG      2       /* Use the 'dialog' program */
@@ -43,17 +46,47 @@ int setup_type;
 char setup_directory[PATH_MAX];
 int using_web_installer = 0;
 int enable_home = 1;
+char admin_pass[SIZ];
+char admin_cmd[SIZ];
 
 char *setup_titles[] =
 {
        "Citadel Home Directory",
        "System Administrator",
+       "Administrator Password",
        "Citadel User ID",
        "Server IP address",
        "Server port number",
-       "Authentication mode"
+       "Authentication mode",
+       "LDAP host",
+       "LDAP port number",
+       "LDAP base DN",
+       "LDAP bind DN",
+       "LDAP bind password"
 };
 
+/**
+ * \brief print the actual stack frame.
+ */
+void cit_backtrace(void)
+{
+#ifdef HAVE_BACKTRACE
+       void *stack_frames[50];
+       size_t size, i;
+       char **strings;
+
+
+       size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
+       strings = backtrace_symbols(stack_frames, size);
+       for (i = 0; i < size; i++) {
+               if (strings != NULL)
+                       fprintf(stderr, "%s\n", strings[i]);
+               else
+                       fprintf(stderr, "%p\n", stack_frames[i]);
+       }
+       free(strings);
+#endif
+}
 
 struct config config;
 
@@ -79,6 +112,10 @@ char *setup_text[] = {
 "you).  When an account is created with this name, it will\n"
 "automatically be given administrator-level access.\n",
 
+"Enter a password for the system administrator. When setup\n"
+"completes it will attempt to create the administrator user\n"
+"and set the password specified here.\n",
+
 "Citadel needs to run under its own user ID.  This would\n"
 "typically be called \"citadel\", but if you are running Citadel\n"
 "as a public BBS, you might also call it \"bbs\" or \"guest\".\n"
@@ -98,15 +135,34 @@ char *setup_text[] = {
 "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"
+
+
+"Specify which authentication mode you wish to use.\n"
+"\n"
+" 0. Self contained authentication\n"
+" 1. Host system integrated authentication\n"
+" 2. External LDAP - RFC 2307 compliant directory\n"
+" 3. External LDAP - nonstandard MS Active Directory\n"
+"\n"
+"For help: http://www.citadel.org/doku.php/faq:installation:authmodes\n"
 "\n"
-"(Answer \"no\" unless you completely understand this option)\n"
-"Do you want to enable host based authentication mode?\n"
+"ANSWER \"0\" UNLESS YOU COMPLETELY UNDERSTAND THIS OPTION.\n",
+
+"Please enter the host name or IP address of your LDAP server.\n",
+
+"Please enter the port number of the LDAP service (usually 389).\n",
+
+"Please enter the Base DN to search for authentication\n"
+"(for example: dc=example,dc=com)\n",
+
+"Please enter the DN of an account to use for binding to the LDAP server\n"
+"for performing queries.  The account does not require any other\n"
+"privileges.  If your LDAP server allows anonymous queries, you can.\n"
+"leave this blank.\n",
+
+"If you entered a Bind DN in the previous question, you must now enter\n"
+"the password associated with that account.  Otherwise, you can leave this\n"
+"blank.\n"
 
 };
 
@@ -116,6 +172,8 @@ int direction;
 
 void cleanup(int exitcode)
 {
+//     printf("Exitcode: %d\n", exitcode);
+//     cit_backtrace();
        exit(exitcode);
 }
 
@@ -144,14 +202,16 @@ int yesno(char *question, int default_value)
                                question,
                                ( default_value ? "Yes" : "No" )
                        );
-                       fgets(buf, sizeof buf, stdin);
-                       answer = tolower(buf[0]);
-                       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;
+                       if (fgets(buf, sizeof buf, stdin))
+                       {
+                               answer = tolower(buf[0]);
+                               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;
+                       }
                } while ((answer < 0) || (answer > 1));
                break;
 
@@ -168,6 +228,8 @@ int yesno(char *question, int default_value)
                        answer = 0;
                }
                break;
+       case UI_SILENT:
+               break;
 
        }
        return (answer);
@@ -184,7 +246,7 @@ void important_message(char *title, char *msgtext)
                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");
                printf("       %s \n\n%s\n\n", title, msgtext);
                printf("Press return to continue...");
-               fgets(buf, sizeof buf, stdin);
+               if (fgets(buf, sizeof buf, stdin));
                break;
 
        case UI_DIALOG:
@@ -193,6 +255,9 @@ void important_message(char *title, char *msgtext)
                        msgtext);
                system(buf);
                break;
+       case UI_SILENT:
+               fprintf(stderr, "%s\n", msgtext);
+               break;
        }
 }
 
@@ -263,6 +328,8 @@ void progress(char *text, long int curr, long int cmax)
                        }
                }
                break;
+       case UI_SILENT:
+               break;
 
        }
 }
@@ -292,7 +359,6 @@ void check_services_entry(void)
                                        fclose(sfp);
                                }
                        }
-                       sleep(1);
                }
        }
 }
@@ -315,14 +381,10 @@ void delete_inittab_entry(void)
 
        /* 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");
@@ -379,61 +441,103 @@ void delete_inittab_entry(void)
  */
 void install_init_scripts(void)
 {
+       struct stat etcinitd;
        FILE *fp;
+       char *initfile = "/etc/init.d/citadel";
+       char command[SIZ];
+
+       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, "r");
+       if (fp != NULL) {
+               if (yesno("Citadel already appears to be configured to start at boot.\n"
+                         "Would you like to keep your boot configuration as is?\n", 1) == 1) {
+                       return;
+               }
+               fclose(fp);
+               
+       }
 
        if (yesno("Would you like to automatically start Citadel at boot?\n", 1) == 0) {
                return;
        }
 
-       fp = fopen("/etc/init.d/citadel", "w");
+       fp = fopen(initfile, "w");
        if (fp == NULL) {
                display_error("Cannot create /etc/init.d/citadel");
                return;
        }
 
        fprintf(fp,     "#!/bin/sh\n"
-                       "\n"
-                       "CITADEL_DIR=%s\n", setup_directory);
+               "#\n"
+               "# Init file for Citadel\n"
+               "#\n"
+               "# chkconfig: - 79 30\n"
+               "# description: Citadel service\n"
+               "# processname: citserver\n"
+               "# pidfile: %s/citadel.pid\n\n"
+               "# uncomment this to create coredumps as described in\n"
+               "# http://www.citadel.org/doku.php/faq:mastering_your_os:gdb#how.do.i.make.my.system.produce.core-files\n"
+               "# ulimit -c unlimited\n"
+               "\n"
+               "CITADEL_DIR=%s\n"
+               ,
+               setup_directory,
+               setup_directory
+               );
        fprintf(fp,     "\n"
-                       "test -x $CITADEL_DIR/ctdlsvc || exit 0\n"
-                       "test -d /var/run || exit 0\n"
-                       "\n"
-                       "case \"$1\" in\n"
-                       "\n"
-                       "start)         echo -n \"Starting Citadel... \"\n"
-                       "               if $CITADEL_DIR/ctdlsvc /var/run/citadel.pid "
-                                                       "$CITADEL_DIR/citserver "
-                                                       "-t/dev/null\n"
-                       "               then\n"
-                       "                       echo \"ok\"\n"
-                       "               else\n"
-                       "                       echo \"failed\"\n"
-                       "               fi\n");
+               "test -d /var/run || exit 0\n"
+               "\n"
+               "case \"$1\" in\n"
+               "\n"
+               "start)         echo -n \"Starting Citadel... \"\n"
+               "               if $CITADEL_DIR/citserver -lmail -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 /var/run/citadel.pid 2>/dev/null\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"
-       );
+               "restart)       if $CITADEL_DIR/sendcommand DOWN 1 >/dev/null 2>&1 ; then\n"
+               "                       echo \"ok\"\n"
+               "               else\n"
+               "                       echo \"failed\"\n"
+               "               fi\n"
+               "               ;;\n"
+               "*)             echo \"Usage: $0 {start|stop|restart}\"\n"
+               "               exit 1\n"
+               "               ;;\n"
+               "esac\n"
+               );
 
        fclose(fp);
-       chmod("/etc/init.d/citadel", 0755);
+       chmod(initfile, 0755);
 
        /* Set up the run levels. */
        system("/bin/rm -f /etc/rc?.d/[SK]??citadel 2>/dev/null");
-       system("for x in 2 3 4 5 ; do [ -d /etc/rc$x.d ] && ln -s /etc/init.d/citadel /etc/rc$x.d/S79citadel ; done 2>/dev/null");
-       system("for x in 0 6 S; do [ -d /etc/rc$x.d ] && ln -s /etc/init.d/citadel /etc/rc$x.d/K30citadel ; done 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);
 
 }
 
@@ -469,10 +573,10 @@ void check_xinetd_entry(void) {
        }
        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"
-               );
+                        "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;
                }
@@ -492,12 +596,7 @@ void check_xinetd_entry(void) {
                "       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 */
@@ -529,26 +628,20 @@ void disable_other_mta(char *mta) {
 
        /* Offer to replace other MTA with the vastly superior Citadel :)  */
 
-       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
+       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;
-               }
+       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);
@@ -562,7 +655,7 @@ void disable_other_mta(char *mta) {
 /* 
  * Check to see if our server really works.  Returns 0 on success.
  */
-int test_server(void) {
+int test_server(char *setup_directory, char *relhomestr, int relhome) {
        char cmd[256];
        char cookie[256];
        FILE *fp;
@@ -575,14 +668,14 @@ int test_server(void) {
         */
        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:"",
+       if (relhome)
+               sprintf(cmd, "%s/sendcommand -h%s ECHO %s 2>&1",
+                       ctdl_sbin_dir,
+                       relhomestr,
+                       cookie);
+       else
+               sprintf(cmd, "%s/sendcommand ECHO %s 2>&1",
+                       ctdl_sbin_dir,
                        cookie);
 
        fp = popen(cmd, "r");
@@ -590,7 +683,7 @@ int test_server(void) {
 
        while (fgets(buf, sizeof buf, fp) != NULL) {
                if ( (buf[0]=='2')
-                  && (strstr(buf, cookie) != NULL) ) {
+                    && (strstr(buf, cookie) != NULL) ) {
                        ++found_it;
                }
        }
@@ -604,7 +697,7 @@ int test_server(void) {
 
 void strprompt(char *prompt_title, char *prompt_text, char *str)
 {
-       char buf[SIZ];
+       char buf[SIZ] = "";
        char setupmsg[SIZ];
        char dialog_result[PATH_MAX];
        FILE *fp = NULL;
@@ -617,9 +710,10 @@ void strprompt(char *prompt_title, char *prompt_text, char *str)
                printf("\n%s\n", prompt_text);
                printf("This is currently set to:\n%s\n", str);
                printf("Enter new value or press return to leave unchanged:\n");
-               fgets(buf, sizeof buf, stdin);
-               buf[strlen(buf) - 1] = 0;
-               if (strlen(buf) != 0)
+               if (fgets(buf, sizeof buf, stdin)){
+                       buf[strlen(buf) - 1] = 0;
+               }
+               if (!IsEmptyStr(buf))
                        strcpy(str, buf);
                break;
 
@@ -633,15 +727,17 @@ void strprompt(char *prompt_title, char *prompt_text, char *str)
                system(buf);
                fp = fopen(dialog_result, "r");
                if (fp != NULL) {
-                       fgets(str, sizeof buf, fp);
-                       if (str[strlen(str)-1] == 10) {
-                               str[strlen(str)-1] = 0;
+                       if (fgets(str, sizeof buf, fp)) {
+                               if (str[strlen(str)-1] == 10) {
+                                       str[strlen(str)-1] = 0;
+                               }
                        }
                        fclose(fp);
                        unlink(dialog_result);
                }
                break;
-
+       case UI_SILENT:
+               break;
        }
 }
 
@@ -690,8 +786,11 @@ void edit_value(int curr)
        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);
@@ -699,42 +798,169 @@ void edit_value(int curr)
                break;
 
        case 2:
+               if (setup_type == UI_SILENT)
+               {
+                       if (getenv("SYSADMIN_PW")) {
+                               strcpy(admin_pass, getenv("SYSADMIN_PW"));
+                       }
+               }
+               else {
+                       set_str_val(curr, admin_pass);
+               }
+               break;
+       
+       case 3:
+               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;
+                       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;
+                               }
+                               else if (atoi(ctdluidname) > 0) {
+                                       config.c_ctdluid = atoi(ctdluidname);
+                               }
+                       }
+#endif
+               }
+               break;
+
+       case 4:
+               if (setup_type == UI_SILENT)
+               {
+                       if (getenv("IP_ADDR")) {
+                               strcpy(config.c_ip_addr, getenv("IP_ADDR"));
+                       }
                }
                else {
-                       strcpy(ctdluidname, pw->pw_name);
-                       set_str_val(curr, ctdluidname);
-                       pw = getpwnam(ctdluidname);
-                       if (pw != NULL) {
-                               config.c_ctdluid = pw->pw_uid;
+                       set_str_val(curr, config.c_ip_addr);
+               }
+               break;
+
+       case 5:
+               if (setup_type == UI_SILENT)
+               {
+                       if (getenv("CITADEL_PORT")) {
+                               config.c_port_number = atoi(getenv("CITADEL_PORT"));
                        }
-                       else if (atoi(ctdluidname) > 0) {
-                               config.c_ctdluid = atoi(ctdluidname);
+               }
+               else
+               {
+                       set_int_val(curr, &config.c_port_number);
+               }
+               break;
+
+       case 6:
+               if (setup_type == UI_SILENT)
+               {
+                       const char *auth;
+                       config.c_auth_mode = AUTHMODE_NATIVE;
+                       auth = getenv("ENABLE_UNIX_AUTH");
+                       if (auth != NULL)
+                       {
+                               if ((strcasecmp(auth, "yes") == 0) ||
+                                   (strcasecmp(auth, "host") == 0))
+                               {
+                                       config.c_auth_mode = AUTHMODE_HOST;
+                               }
+                               else if (strcasecmp(auth, "ldap") == 0){
+                                       config.c_auth_mode = AUTHMODE_LDAP;
+                               }
+                               else if ((strcasecmp(auth, "ldap_ad") == 0) ||
+                                        (strcasecmp(auth, "active directory") == 0)){
+                                       config.c_auth_mode = AUTHMODE_LDAP_AD;
+                               }
                        }
                }
-#endif
+               else {
+                       set_int_val(curr, &config.c_auth_mode);
+               }
                break;
 
-       case 3:
-               set_str_val(curr, config.c_ip_addr);
+       case 7:
+               if (setup_type == UI_SILENT)
+               {
+                       if (getenv("LDAP_HOST")) {
+                               strcpy(config.c_ldap_host, getenv("LDAP_HOST"));
+                       }
+               }
+               else
+               {
+                       set_str_val(curr, config.c_ldap_host);
+               }
                break;
 
-       case 4:
-               set_int_val(curr, &config.c_port_number);
+       case 8:
+               if (setup_type == UI_SILENT)
+               {
+                       if (getenv("LDAP_PORT")) {
+                               config.c_ldap_port = atoi(getenv("LDAP_PORT"));
+                       }
+               }
+               else
+               {
+                       set_int_val(curr, &config.c_ldap_port);
+               }
                break;
 
-       case 5:
-               set_bool_val(curr, &config.c_auth_mode);
+       case 9:
+               if (setup_type == UI_SILENT)
+               {
+                       if (getenv("LDAP_BASE_DN")) {
+                               strcpy(config.c_ldap_base_dn, getenv("LDAP_BASE_DN"));
+                       }
+               }
+               else
+               {
+                       set_str_val(curr, config.c_ldap_base_dn);
+               }
+               break;
+
+       case 10:
+               if (setup_type == UI_SILENT)
+               {
+                       if (getenv("LDAP_BIND_DN")) {
+                               strcpy(config.c_ldap_bind_dn, getenv("LDAP_BIND_DN"));
+                       }
+               }
+               else
+               {
+                       set_str_val(curr, config.c_ldap_bind_dn);
+               }
+               break;
+
+       case 11:
+               if (setup_type == UI_SILENT)
+               {
+                       if (getenv("LDAP_BIND_PW")) {
+                               strcpy(config.c_ldap_bind_pw, getenv("LDAP_BIND_PW"));
+                       }
+               }
+               else
+               {
+                       set_str_val(curr, config.c_ldap_bind_pw);
+               }
                break;
 
        }
+
 }
 
 /*
@@ -858,6 +1084,7 @@ void fixnss(void) {
        if (yesno(question, 1)) {
                sprintf(buf, "/bin/mv -f %s %s", new_filename, NSSCONF);
                system(buf);
+               chmod(NSSCONF, 0644);
        }
        unlink(new_filename);
 }
@@ -885,6 +1112,7 @@ int main(int argc, char *argv[])
        int home=0;
        char relhome[PATH_MAX]="";
        char ctdldir[PATH_MAX]=CTDLDIR;
+       int rv;
        
        /* set an invalid setup type */
        setup_type = (-1);
@@ -901,14 +1129,25 @@ int main(int argc, char *argv[])
                        strcpy(aaa, &aaa[2]);
                        setup_type = atoi(aaa);
                }
-               if (!strcmp(argv[a], "-i")) {
+               else if (!strcmp(argv[a], "-i")) {
                        info_only = 1;
                }
-               if (!strcmp(argv[a], "-q")) {
+               else if (!strcmp(argv[a], "-q")) {
                        setup_type = UI_SILENT;
                }
+               else if (!strncmp(argv[a], "-h", 2)) {
+                       relh=argv[a][2]!='/';
+                       if (!relh) {
+                               safestrncpy(ctdl_home_directory, &argv[a][2], sizeof ctdl_home_directory);
+                       } else {
+                               safestrncpy(relhome, &argv[a][2], sizeof relhome);
+                       }
+                       home = 1;
+               }
+
        }
 
+       calc_dirs_n_files(relh, home, relhome, ctdldir, 0);
 
        /* If a setup type was not specified, try to determine automatically
         * the best one to use out of all available types.
@@ -922,13 +1161,7 @@ int main(int argc, char *argv[])
        }
 
        /* 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"));
        }
@@ -936,28 +1169,14 @@ int main(int argc, char *argv[])
                set_str_val(0, setup_directory);
        }
 
-       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);
+       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);
-               }
+       if (chdir(setup_directory) != 0) {
+               char errmsg[SIZ];
+               sprintf(errmsg, "The directory you specified does not exist: [%s]\n", setup_directory);
+               
+               important_message("Citadel Setup", errmsg);
+               cleanup(errno);
        }
 
        /* Determine our host name, in case we need to use it as a default */
@@ -965,11 +1184,11 @@ int main(int argc, char *argv[])
 
        /* Try to stop Citadel if we can */
        if (!access("/etc/init.d/citadel", X_OK)) {
-               system("/etc/init.d/citadel stop");
+               rv = system("/etc/init.d/citadel stop");
        }
 
        /* Make sure Citadel is not running. */
-       if (test_server() == 0) {
+       if (test_server(setup_directory, relhome, enable_home) == 0) {
                important_message("Citadel Setup",
                        "The Citadel service is still running.\n"
                        "Please stop the service manually and run "
@@ -1007,8 +1226,9 @@ int main(int argc, char *argv[])
                display_error("setup: cannot append citadel.config");
                cleanup(errno);
        }
-       for (a = 0; a < sizeof(struct config); ++a)
+       for (a = 0; a < sizeof(struct config); ++a) {
                putc(0, fp);
+       }
        fclose(fp);
 
        /* now we re-open it, and read the old or blank configuration */
@@ -1017,37 +1237,34 @@ int main(int argc, char *argv[])
                display_error("setup: cannot open citadel.config");
                cleanup(errno);
        }
-       fread((char *) &config, sizeof(struct config), 1, fp);
+       rv = fread((char *) &config, sizeof(struct config), 1, fp);
        fclose(fp);
 
        /* set some sample/default values in place of blanks... */
-       if (strlen(config.c_nodename) == 0)
+       if (IsEmptyStr(config.c_nodename))
                safestrncpy(config.c_nodename, my_utsname.nodename,
                            sizeof config.c_nodename);
        strtok(config.c_nodename, ".");
-       if (strlen(config.c_fqdn) == 0) {
-               if ((he = gethostbyname(my_utsname.nodename)) != NULL)
-                       safestrncpy(config.c_fqdn, he->h_name,
-                                   sizeof config.c_fqdn);
-               else
-                       safestrncpy(config.c_fqdn, my_utsname.nodename,
-                                   sizeof config.c_fqdn);
+       if (IsEmptyStr(config.c_fqdn) ) {
+               if ((he = gethostbyname(my_utsname.nodename)) != NULL) {
+                       safestrncpy(config.c_fqdn, he->h_name, sizeof config.c_fqdn);
+               } else {
+                       safestrncpy(config.c_fqdn, my_utsname.nodename, sizeof config.c_fqdn);
+               }
        }
-       if (strlen(config.c_humannode) == 0)
+       if (IsEmptyStr(config.c_humannode)) {
                strcpy(config.c_humannode, "My System");
-       if (strlen(config.c_phonenum) == 0)
+       }
+       if (IsEmptyStr(config.c_phonenum)) {
                strcpy(config.c_phonenum, "US 800 555 1212");
+       }
        if (config.c_initax == 0) {
                config.c_initax = 4;
        }
-       if (strlen(config.c_moreprompt) == 0)
-               strcpy(config.c_moreprompt, "<more>");
-       if (strlen(config.c_twitroom) == 0)
-               strcpy(config.c_twitroom, "Trashcan");
-       if (strlen(config.c_baseroom) == 0)
-               strcpy(config.c_baseroom, BASEROOM);
-       if (strlen(config.c_aideroom) == 0)
-               strcpy(config.c_aideroom, "Aide");
+       if (IsEmptyStr(config.c_moreprompt)) strcpy(config.c_moreprompt, "<more>");
+       if (IsEmptyStr(config.c_twitroom)) strcpy(config.c_twitroom, "Trashcan");
+       if (IsEmptyStr(config.c_baseroom)) strcpy(config.c_baseroom, BASEROOM);
+       if (IsEmptyStr(config.c_aideroom)) strcpy(config.c_aideroom, "Aide");
        if (config.c_port_number == 0) {
                config.c_port_number = 504;
        }
@@ -1056,18 +1273,21 @@ int main(int argc, char *argv[])
        }
        if (config.c_ctdluid == 0) {
                pw = getpwnam("citadel");
-               if (pw != NULL)
+               if (pw != NULL) {
                        config.c_ctdluid = pw->pw_uid;
+               }
        }
        if (config.c_ctdluid == 0) {
                pw = getpwnam("bbs");
-               if (pw != NULL)
+               if (pw != NULL) {
                        config.c_ctdluid = pw->pw_uid;
+               }
        }
        if (config.c_ctdluid == 0) {
                pw = getpwnam("guest");
-               if (pw != NULL)
+               if (pw != NULL) {
                        config.c_ctdluid = pw->pw_uid;
+               }
        }
        if (config.c_createax == 0) {
                config.c_createax = 3;
@@ -1099,11 +1319,14 @@ int main(int argc, char *argv[])
        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;
+       if (config.c_xmpp_c2s_port == 0) config.c_xmpp_c2s_port = 5222;
+       if (config.c_xmpp_s2s_port == 0) config.c_xmpp_s2s_port = 5269;
 
        /* 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 ((curr == 6) && (config.c_auth_mode != AUTHMODE_LDAP) && (config.c_auth_mode != AUTHMODE_LDAP_AD)) {
+                       curr += 5;      /* skip LDAP questions if we're not authenticating against LDAP */
                }
        }
 
@@ -1135,111 +1358,97 @@ NEW_INST:
 
        write_config_to_disk();
 
-       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);
+       rv = mkdir(ctdl_info_dir, 0700);
+       rv = chmod(ctdl_info_dir, 0700);
+       rv = chown(ctdl_info_dir, config.c_ctdluid, -1);
 
-       mkdir(ctdl_usrpic_dir, 0700);
-       chmod(ctdl_usrpic_dir, 0700);
-       chown(ctdl_usrpic_dir, config.c_ctdluid, -1);
+       rv = mkdir(ctdl_bio_dir, 0700);
+       rv = chmod(ctdl_bio_dir, 0700);
+       rv = chown(ctdl_bio_dir, config.c_ctdluid, -1);
 
-       mkdir(ctdl_message_dir, 0700);
-       chmod(ctdl_message_dir, 0700);
-       chown(ctdl_message_dir, config.c_ctdluid, -1);
+       rv = mkdir(ctdl_usrpic_dir, 0700);
+       rv = chmod(ctdl_usrpic_dir, 0700);
+       rv = chown(ctdl_usrpic_dir, config.c_ctdluid, -1);
 
-       mkdir(ctdl_hlp_dir, 0700);
-       chmod(ctdl_hlp_dir, 0700);
-       chown(ctdl_hlp_dir, config.c_ctdluid, -1);
+       rv = mkdir(ctdl_message_dir, 0700);
+       rv = chmod(ctdl_message_dir, 0700);
+       rv = chown(ctdl_message_dir, config.c_ctdluid, -1);
 
-       mkdir(ctdl_image_dir, 0700);
-       chmod(ctdl_image_dir, 0700);
-       chown(ctdl_image_dir, config.c_ctdluid, -1);
+       rv = mkdir(ctdl_hlp_dir, 0700);
+       rv = chmod(ctdl_hlp_dir, 0700);
+       rv = chown(ctdl_hlp_dir, config.c_ctdluid, -1);
 
-       mkdir(ctdl_bb_dir, 0700);
-       chmod(ctdl_bb_dir, 0700);
-       chown(ctdl_bb_dir, config.c_ctdluid, -1);
+       rv = mkdir(ctdl_image_dir, 0700);
+       rv = chmod(ctdl_image_dir, 0700);
+       rv = chown(ctdl_image_dir, config.c_ctdluid, -1);
 
-       mkdir(ctdl_file_dir, 0700);
-       chmod(ctdl_file_dir, 0700);
-       chown(ctdl_file_dir, config.c_ctdluid, -1);
+       rv = mkdir(ctdl_bb_dir, 0700);
+       rv = chmod(ctdl_bb_dir, 0700);
+       rv = chown(ctdl_bb_dir, config.c_ctdluid, -1);
 
-       mkdir(ctdl_netcfg_dir, 0700);
-       chmod(ctdl_netcfg_dir, 0700);
-       chown(ctdl_netcfg_dir, config.c_ctdluid, -1);
+       rv = mkdir(ctdl_file_dir, 0700);
+       rv = chmod(ctdl_file_dir, 0700);
+       rv = chown(ctdl_file_dir, config.c_ctdluid, -1);
 
-       /* TODO: where to put this? */
-       mkdir("netconfigs", 0700);
-       chmod("netconfigs", 0700);
-       chown("netconfigs", config.c_ctdluid, -1);
+       rv = mkdir(ctdl_netcfg_dir, 0700);
+       rv = chmod(ctdl_netcfg_dir, 0700);
+       rv = 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");
+       rv = system("exec /bin/rm -fr ./rooms ./chatpipes ./expressmsgs ./sessions 2>/dev/null");
        unlink("citadel.log");
        unlink("weekly");
 
-       check_services_entry(); /* Check /etc/services */
+       if (((setup_type == UI_SILENT) && (getenv("ALTER_ETC_SERVICES")!=NULL)) || 
+           (setup_type != UI_SILENT))
+               check_services_entry(); /* Check /etc/services */
 #ifndef __CYGWIN__
        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("courier-authdaemon");
-       disable_other_mta("courier-imap");
-       disable_other_mta("courier-imap-ssl");
-       disable_other_mta("courier-pop");
-       disable_other_mta("courier-pop3");
-       disable_other_mta("courier-pop3d");
-       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("mta");
-       disable_other_mta("pop3d");
-       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");
+       if ((getenv("ACT_AS_MTA") == NULL) || 
+           (getenv("ACT_AS_MTA") &&
+            strcasecmp(getenv("ACT_AS_MTA"), "yes") == 0)) {
+               /* Offer to disable other MTA's on the system. */
+               disable_other_mta("courier-authdaemon");
+               disable_other_mta("courier-imap");
+               disable_other_mta("courier-imap-ssl");
+               disable_other_mta("courier-pop");
+               disable_other_mta("courier-pop3");
+               disable_other_mta("courier-pop3d");
+               disable_other_mta("cyrmaster");
+               disable_other_mta("cyrus");
+               disable_other_mta("dovecot");
+               disable_other_mta("exim");
+               disable_other_mta("exim4");
+               disable_other_mta("imapd");
+               disable_other_mta("mta");
+               disable_other_mta("pop3d");
+               disable_other_mta("popd");
+               disable_other_mta("postfix");
+               disable_other_mta("qmail");
+               disable_other_mta("saslauthd");
+               disable_other_mta("sendmail");
+               disable_other_mta("vmailmgrd");
+       }
 #endif
 
        /* Check for the 'db' nss and offer to disable it */
        fixnss();
 
-       if ((pw = getpwuid(config.c_ctdluid)) == NULL)
+       if ((pw = getpwuid(config.c_ctdluid)) == NULL) {
                gid = getgid();
-       else
+       } else {
                gid = pw->pw_gid;
+       }
 
-       progress("Setting file permissions", 0, 4);
-       chown(".", config.c_ctdluid, gid);
-       sleep(1);
-       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);
+       progress("Setting file permissions", 0, 3);
+       rv = chown(ctdl_run_dir, config.c_ctdluid, gid);
+       progress("Setting file permissions", 1, 3);
+       rv = chown(file_citadel_config, config.c_ctdluid, gid);
+       progress("Setting file permissions", 2, 3);
+       rv = chmod(file_citadel_config, S_IRUSR | S_IWUSR);
+       progress("Setting file permissions", 3, 3);
 
        /* 
         * If we're running on SysV, install init scripts.
@@ -1251,16 +1460,38 @@ NEW_INST:
                }
 
                if (!access("/etc/init.d/citadel", X_OK)) {
-                       system("/etc/init.d/citadel start");
+                       rv = 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");
+               if (test_server(setup_directory, relhome, enable_home) == 0) {
+                       char buf[SIZ];
+                       int found_it = 0;
+
+                       if (config.c_auth_mode == AUTHMODE_NATIVE) {
+                               snprintf (admin_cmd, sizeof(admin_cmd), "%s/sendcommand \"CREU %s|%s\" 2>&1", 
+                                       ctdl_sbin_dir, config.c_sysadm, admin_pass);
+                               fp = popen(admin_cmd, "r");
+                               if (fp != NULL) {
+                                       while (fgets(buf, sizeof buf, fp) != NULL) 
+                                       {
+                                               if ((atol(buf) == 574) || (atol(buf) == 200))
+                                                       ++found_it;
+                                       }
+                                       pclose(fp);
+                               }
+                       
+                               if (found_it == 0) {
+                                       important_message("Error","Setup failed to create your admin user");
+                               }
+                       }
+
+                       if (setup_type != UI_SILENT)
+                               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",