* Backed out r7276 through r7278. This is too large a change to make during a featur...
[citadel.git] / citadel / setup.c
index 9f4bf5dc7ef8d3a36d1a2e48bb77b1740ab4ae79..05e6eacb1cad17aa975cccdf7034a16e57a6feb7 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 5     /* How many setup questions to ask */
+#define MAXSETUP 6     /* 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,42 @@ 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"
 };
 
+/**
+ * \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 +107,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"
@@ -116,6 +148,8 @@ int direction;
 
 void cleanup(int exitcode)
 {
+//     printf("Exitcode: %d\n", exitcode);
+//     cit_backtrace();
        exit(exitcode);
 }
 
@@ -168,6 +202,8 @@ int yesno(char *question, int default_value)
                        answer = 0;
                }
                break;
+       case UI_SILENT:
+               break;
 
        }
        return (answer);
@@ -193,6 +229,9 @@ void important_message(char *title, char *msgtext)
                        msgtext);
                system(buf);
                break;
+       case UI_SILENT:
+               fprintf(stderr, "%s\n", msgtext);
+               break;
        }
 }
 
@@ -263,6 +302,8 @@ void progress(char *text, long int curr, long int cmax)
                        }
                }
                break;
+       case UI_SILENT:
+               break;
 
        }
 }
@@ -379,10 +420,6 @@ void install_init_scripts(void)
        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))
        {
@@ -393,6 +430,20 @@ void install_init_scripts(void)
                        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(initfile, "w");
        if (fp == NULL) {
                display_error("Cannot create /etc/init.d/citadel");
@@ -437,9 +488,12 @@ void install_init_scripts(void)
                                setup_directory
                        );
        fprintf(fp,     "               ;;\n"
-                       "restart)       $0 stop\n"
-                       "               $0 start\n"
-                       "               ;;\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"
@@ -545,26 +599,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);
@@ -578,7 +626,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;
@@ -591,11 +639,15 @@ int test_server(void) {
         */
        sprintf(cookie, "--test--%d--", getpid());
 
-       sprintf(cmd, "%s/sendcommand %s%s ECHO %s 2>&1",
-               ctdl_sbin_dir,
-               (enable_home)?"-h":"", 
-               (enable_home)?ctdl_run_dir:"",
-               cookie);
+       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");
        if (fp == NULL) return(errno);
@@ -631,7 +683,7 @@ void strprompt(char *prompt_title, char *prompt_text, char *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 (!IsEmptyStr(buf))
                        strcpy(str, buf);
                break;
 
@@ -653,7 +705,8 @@ void strprompt(char *prompt_title, char *prompt_text, char *str)
                        unlink(dialog_result);
                }
                break;
-
+       case UI_SILENT:
+               break;
        }
 }
 
@@ -714,6 +767,18 @@ 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")) {
@@ -742,11 +807,11 @@ void edit_value(int curr)
                                        config.c_ctdluid = atoi(ctdluidname);
                                }
                        }
-               }
 #endif
+               }
                break;
 
-       case 3:
+       case 4:
                if (setup_type == UI_SILENT)
                {
                        if (getenv("IP_ADDR")) {
@@ -758,7 +823,7 @@ void edit_value(int curr)
                }
                break;
 
-       case 4:
+       case 5:
                if (setup_type == UI_SILENT)
                {
                        if (getenv("CITADEL_PORT")) {
@@ -771,15 +836,15 @@ void edit_value(int curr)
                }
                break;
 
-       case 5:
+       case 6:
                if (setup_type == UI_SILENT)
                {
                        if (getenv("ENABLE_UNIX_AUTH")) {
                                if (!strcasecmp(getenv("ENABLE_UNIX_AUTH"), "yes")) {
-                                       config.c_auth_mode = 1;
+                                       config.c_auth_mode = AUTHMODE_HOST;
                                }
                                else {
-                                       config.c_auth_mode = 0;
+                                       config.c_auth_mode = AUTHMODE_NATIVE;
                                }
                        }
                }
@@ -912,6 +977,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);
 }
@@ -955,14 +1021,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.
@@ -984,28 +1061,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 */
@@ -1017,7 +1080,7 @@ int main(int argc, char *argv[])
        }
 
        /* 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 "
@@ -1069,11 +1132,11 @@ int main(int argc, char *argv[])
        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 (IsEmptyStr(config.c_fqdn) ) {
                if ((he = gethostbyname(my_utsname.nodename)) != NULL)
                        safestrncpy(config.c_fqdn, he->h_name,
                                    sizeof config.c_fqdn);
@@ -1081,20 +1144,20 @@ int main(int argc, char *argv[])
                        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)
+       if (IsEmptyStr(config.c_moreprompt))
                strcpy(config.c_moreprompt, "<more>");
-       if (strlen(config.c_twitroom) == 0)
+       if (IsEmptyStr(config.c_twitroom))
                strcpy(config.c_twitroom, "Trashcan");
-       if (strlen(config.c_baseroom) == 0)
+       if (IsEmptyStr(config.c_baseroom))
                strcpy(config.c_baseroom, BASEROOM);
-       if (strlen(config.c_aideroom) == 0)
+       if (IsEmptyStr(config.c_aideroom))
                strcpy(config.c_aideroom, "Aide");
        if (config.c_port_number == 0) {
                config.c_port_number = 504;
@@ -1147,6 +1210,8 @@ 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 */
        for (curr = 1; curr <= MAXSETUP; ++curr) {
@@ -1222,34 +1287,38 @@ NEW_INST:
        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 */
@@ -1260,22 +1329,13 @@ NEW_INST:
        else
                gid = pw->pw_gid;
 
-       progress("Setting file permissions", 0, 4);
+       progress("Setting file permissions", 0, 3);
        chown(ctdl_run_dir, config.c_ctdluid, gid);
-       progress("Setting file permissions", 1, 4);
+       progress("Setting file permissions", 1, 3);
        chown(file_citadel_config, config.c_ctdluid, gid);
-       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*/
-       progress("Setting file permissions", 3, 4);
-       chmod(aaa, 04755); 
-
-       progress("Setting file permissions", 3, 4);
+       progress("Setting file permissions", 2, 3);
        chmod(file_citadel_config, S_IRUSR | S_IWUSR);
-       progress("Setting file permissions", 4, 4);
+       progress("Setting file permissions", 3, 3);
 
        /* 
         * If we're running on SysV, install init scripts.
@@ -1291,12 +1351,31 @@ NEW_INST:
                        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;
+
+                       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",