Imported Upstream version 2.5.1
[debian/amanda] / recover-src / amrecover.c
index a4fe069f59a5a5eddca41749ce97f164481dd65b..cf21c0312ce6553b6ef790a4eac6b6820ead003e 100644 (file)
  * file named AUTHORS, in the root directory of this distribution.
  */
 /*
- * $Id: amrecover.c,v 1.52 2006/01/14 04:37:19 paddy_s Exp $
+ * $Id: amrecover.c,v 1.73 2006/07/25 18:27:57 martinea Exp $
  *
  * an interactive program for recovering backed-up files
  */
 
 #include "amanda.h"
 #include "version.h"
-#ifdef HAVE_NETINET_IN_SYSTM_H
-#include <netinet/in_systm.h>
-#endif
-#include <netinet/in.h>
-#ifdef HAVE_NETINET_IP_H
-#include <netinet/ip.h>
-#endif
 #include "stream.h"
 #include "amfeatures.h"
 #include "amrecover.h"
 #include "getfsent.h"
 #include "dgram.h"
 #include "util.h"
+#include "clientconf.h"
+#include "protocol.h"
+#include "event.h"
+#include "security.h"
 
-#ifdef HAVE_LIBREADLINE
-#  ifdef HAVE_READLINE_READLINE_H
-#    include <readline/readline.h>
-#    ifdef HAVE_READLINE_HISTORY_H
-#      include <readline/history.h>
-#    endif
-#  else
-#    ifdef HAVE_READLINE_H
-#      include <readline.h>
-#      ifdef HAVE_HISTORY_H
-#        include <history.h>
-#      endif
-#    else
-#      undef HAVE_LIBREADLINE
-#    endif
-#  endif
-#endif
-
-extern int process_line P((char *line));
-int guess_disk P((char *cwd, size_t cwd_len, char **dn_guess, char **mpt_guess));
+extern int process_line(char *line);
+int get_line(void);
+int grab_reply(int show);
+void sigint_handler(int signum);
+int main(int argc, char **argv);
 
-#define USAGE "Usage: amrecover [[-C] <config>] [-s <index-server>] [-t <tape-server>] [-d <tape-device>]\n"
+#define USAGE "Usage: amrecover [[-C] <config>] [-s <index-server>] [-t <tape-server>] [-d <tape-device>] [-o <clientconfigoption>]*\n"
 
 char *config = NULL;
 char *server_name = NULL;
@@ -83,80 +65,64 @@ char *tape_server_name = NULL;
 int tape_server_socket;
 char *tape_device_name = NULL;
 am_feature_t *our_features = NULL;
+char *our_features_string = NULL;
 am_feature_t *indexsrv_features = NULL;
 am_feature_t *tapesrv_features = NULL;
-
-
-#ifndef HAVE_LIBREADLINE
-/*
- * simple readline() replacements
- */
-
-char *
-readline(prompt)
-char *prompt;
-{
-    printf("%s",prompt);
-    fflush(stdout); fflush(stderr);
-    return agets(stdin);
-}
-
-#define add_history(x)                /* add_history((x)) */
-
-#endif
-
+static char *errstr = NULL;
+char *authopt;
+int amindexd_alive = 0;
+
+static struct {
+    const char *name;
+    security_stream_t *fd;
+} streams[] = {
+#define MESGFD  0
+    { "MESG", NULL },
+};
+#define NSTREAMS        (int)(sizeof(streams) / sizeof(streams[0]))
+
+static void amindexd_response(void *, pkt_t *, security_handle_t *);
+void stop_amindexd(void);
+char *amindexd_client_get_security_conf(char *, void *);
+
+static char* mesg_buffer = NULL;
 /* gets a "line" from server and put in server_line */
 /* server_line is terminated with \0, \r\n is striped */
 /* returns -1 if error */
 
-int get_line ()
+int
+get_line(void)
 {
-    char *line = NULL;
-    char *part = NULL;
-    size_t len;
-
-    while(1) {
-       if((part = areads(server_socket)) == NULL) {
-           int save_errno = errno;
-
-           if(server_line) {
-               fputs(server_line, stderr);     /* show the last line read */
-               fputc('\n', stderr);
-           }
-           if(save_errno != 0) {
-               fprintf(stderr, "%s: Error reading line from server: %s\n",
-                               get_pname(),
-                               strerror(save_errno));
-           } else {
-               fprintf(stderr, "%s: Unexpected end of file, check amindexd*debug on server %s\n",
-                       get_pname(),
-                       server_name);
-           }
-           amfree(line);
-           amfree(server_line);
-           errno = save_errno;
+    ssize_t size;
+    char *newbuf, *s;
+    void *buf;
+
+    if (!mesg_buffer)
+       mesg_buffer = stralloc("");
+    while (!strstr(mesg_buffer,"\r\n")) {
+       size = security_stream_read_sync(streams[MESGFD].fd, &buf);
+       if(size < 0) {
            return -1;
        }
-       if(line) {
-           strappend(line, part);
-           amfree(part);
-       } else {
-           line = part;
-           part = NULL;
-       }
-       if((len = strlen(line)) > 0 && line[len-1] == '\r') {
-           line[len-1] = '\0';
-           server_line = newstralloc(server_line, line);
-           amfree(line);
-           return 0;
+       else if(size == 0) {
+           return -1;
        }
-       /*
-        * Hmmm.  We got a "line" from areads(), which means it saw
-        * a '\n' (or EOF, etc), but there was not a '\r' before it.
-        * Put a '\n' back in the buffer and loop for more.
-        */
-       strappend(line, "\n");
+       newbuf = alloc(strlen(mesg_buffer)+size+1);
+       strncpy(newbuf, mesg_buffer, (size_t)(strlen(mesg_buffer) + size));
+       memcpy(newbuf+strlen(mesg_buffer), buf, (size_t)size);
+       newbuf[strlen(mesg_buffer)+size] = '\0';
+       amfree(mesg_buffer);
+       mesg_buffer = newbuf;
     }
+
+    s = strstr(mesg_buffer,"\r\n");
+    *s = '\0';
+    newbuf = stralloc(s+2);
+    server_line = newstralloc(server_line, mesg_buffer);
+    amfree(mesg_buffer);
+    mesg_buffer = newbuf;
+    return 0;
 }
 
 
@@ -165,8 +131,9 @@ int get_line ()
 /* return -1 if error */
 /* return code returned by server always occupies first 3 bytes of global
    variable server_line */
-int grab_reply (show)
-int show;
+int
+grab_reply(
+    int show)
 {
     do {
        if (get_line() == -1) {
@@ -182,7 +149,8 @@ int show;
 
 /* get 1 line of reply */
 /* returns -1 if error, 0 if last (or only) line, 1 if more to follow */
-int get_reply_line ()
+int
+get_reply_line(void)
 {
     if (get_line() == -1)
        return -1;
@@ -191,7 +159,8 @@ int get_reply_line ()
 
 
 /* returns pointer to returned line */
-char *reply_line ()
+char *
+reply_line(void)
 {
     return server_line;
 }
@@ -200,14 +169,16 @@ char *reply_line ()
 
 /* returns 0 if server returned an error code (ie code starting with 5)
    and non-zero otherwise */
-int server_happy ()
+int
+server_happy(void)
 {
     return server_line[0] != '5';
 }
 
 
-int send_command(cmd)
-char *cmd;
+int
+send_command(
+    char *     cmd)
 {
     /*
      * NOTE: this routine is called from sigint_handler, so we must be
@@ -215,25 +186,26 @@ char *cmd;
      * our state at the time the interrupt happened.  For instance,
      * do not use any stdio or malloc routines here.
      */
-    struct iovec msg[2];
-    ssize_t bytes;
+    char *buffer;
 
-    msg[0].iov_base = cmd;
-    msg[0].iov_len = strlen(msg[0].iov_base);
-    msg[1].iov_base = "\r\n";
-    msg[1].iov_len = strlen(msg[1].iov_base);
-    bytes = msg[0].iov_len + msg[1].iov_len;
+    buffer = alloc(strlen(cmd)+3);
+    strncpy(buffer, cmd, strlen(cmd));
+    buffer[strlen(cmd)] = '\r';
+    buffer[strlen(cmd)+1] = '\n';
+    buffer[strlen(cmd)+2] = '\0';
 
-    if (writev(server_socket, msg, 2) < bytes) {
+    if(security_stream_write(streams[MESGFD].fd, buffer, strlen(buffer)) < 0) {
        return -1;
     }
+    amfree(buffer);
     return (0);
 }
 
 
 /* send a command to the server, get reply and print to screen */
-int converse(cmd)
-char *cmd;
+int
+converse(
+    char *     cmd)
 {
     if (send_command(cmd) == -1) return -1;
     if (grab_reply(1) == -1) return -1;
@@ -242,8 +214,9 @@ char *cmd;
 
 
 /* same as converse() but reply not echoed to stdout */
-int exchange(cmd)
-char *cmd;
+int
+exchange(
+    char *     cmd)
 {
     if (send_command(cmd) == -1) return -1;
     if (grab_reply(0) == -1) return -1;
@@ -253,8 +226,9 @@ char *cmd;
 
 /* basic interrupt handler for when user presses ^C */
 /* Bale out, letting server know before doing so */
-void sigint_handler(signum)
-int signum;
+void
+sigint_handler(
+    int        signum)
 {
     /*
      * NOTE: we must be **very** careful about what we do here since there
@@ -263,17 +237,22 @@ int signum;
      * routines.  Also, use _exit() instead of exit() to make sure stdio
      * buffer flushing is not attempted.
      */
+    (void)signum;      /* Quiet unused parameter warning */
+
     if (extract_restore_child_pid != -1)
        (void)kill(extract_restore_child_pid, SIGKILL);
     extract_restore_child_pid = -1;
 
-    (void)send_command("QUIT");
+    if(amindexd_alive) 
+       (void)send_command("QUIT");
+
     _exit(1);
 }
 
 
-void clean_pathname(s)
-char *s;
+void
+clean_pathname(
+    char *     s)
 {
     size_t length;
     length = strlen(s);
@@ -292,132 +271,41 @@ char *s;
 }
 
 
-/* try and guess the disk the user is currently on.
-   Return -1 if error, 0 if disk not local, 1 if disk local,
-   2 if disk local but can't guess name */
-/* do this by looking for the longest mount point which matches the
-   current directory */
-int guess_disk (cwd, cwd_len, dn_guess, mpt_guess)
-     char *cwd, **dn_guess, **mpt_guess;
-     size_t cwd_len;
-{
-    size_t longest_match = 0;
-    size_t current_length;
-    size_t cwd_length;
-    int local_disk = 0;
-    generic_fsent_t fsent;
-    char *fsname = NULL;
-    char *disk_try = NULL;
-
-    *dn_guess = *mpt_guess = NULL;
-
-    if (getcwd(cwd, cwd_len) == NULL)
-       return -1;
-    cwd_length = strlen(cwd);
-    dbprintf(("guess_disk: %d: \"%s\"\n", cwd_length, cwd));
-
-    if (open_fstab() == 0)
-       return -1;
-
-    while (get_fstab_nextentry(&fsent))
-    {
-       current_length = fsent.mntdir ? strlen(fsent.mntdir) : (size_t)0;
-       dbprintf(("guess_disk: %d: %d: \"%s\": \"%s\"\n",
-                 longest_match,
-                 current_length,
-                 fsent.mntdir ? fsent.mntdir : "(mntdir null)",
-                 fsent.fsname ? fsent.fsname : "(fsname null)"));
-       if ((current_length > longest_match)
-           && (current_length <= cwd_length)
-           && (strncmp(fsent.mntdir, cwd, current_length) == 0))
-       {
-           longest_match = current_length;
-           amfree(*mpt_guess);
-           *mpt_guess = stralloc(fsent.mntdir);
-           if(strncmp(fsent.fsname,DEV_PREFIX,(strlen(DEV_PREFIX))))
-           {
-               fsname = newstralloc(fsname, fsent.fsname);
-            }
-           else
-           {
-               fsname = newstralloc(fsname,fsent.fsname+strlen(DEV_PREFIX));
-           }
-           local_disk = is_local_fstype(&fsent);
-           dbprintf(("guess_disk: local_disk = %d, fsname = \"%s\"\n",
-                     local_disk,
-                     fsname));
-       }
-    }
-    close_fstab();
-
-    if (longest_match == 0) {
-       amfree(*mpt_guess);
-       amfree(fsname);
-       return -1;                      /* ? at least / should match */
-    }
-
-    if (!local_disk) {
-       amfree(*mpt_guess);
-       amfree(fsname);
-       return 0;
-    }
-
-    /* have mount point now */
-    /* disk name may be specified by mount point (logical name) or
-       device name, have to determine */
-    printf("Trying disk %s ...\n", *mpt_guess);
-    disk_try = stralloc2("DISK ", *mpt_guess);         /* try logical name */
-    if (exchange(disk_try) == -1)
-       exit(1);
-    amfree(disk_try);
-    if (server_happy())
-    {
-       *dn_guess = stralloc(*mpt_guess);               /* logical is okay */
-       amfree(fsname);
-       return 1;
-    }
-    printf("Trying disk %s ...\n", fsname);
-    disk_try = stralloc2("DISK ", fsname);             /* try device name */
-    if (exchange(disk_try) == -1)
-       exit(1);
-    amfree(disk_try);
-    if (server_happy())
-    {
-       *dn_guess = stralloc(fsname);                   /* dev name is okay */
-       amfree(fsname);
-       return 1;
-    }
-
-    /* neither is okay */
-    amfree(*mpt_guess);
-    amfree(fsname);
-    return 2;
-}
-
-
-void quit ()
+void
+quit(void)
 {
     quit_prog = 1;
     (void)converse("QUIT");
+    stop_amindexd();
 }
 
 char *localhost = NULL;
 
-int main(argc, argv)
-int argc;
-char **argv;
+#ifdef DEFAULT_TAPE_SERVER
+# define DEFAULT_TAPE_SERVER_FAILOVER (DEFAULT_TAPE_SERVER)
+#else
+# define DEFAULT_TAPE_SERVER_FAILOVER (NULL)
+#endif
+
+int
+main(
+    int                argc,
+    char **    argv)
 {
-    int my_port;
-    struct servent *sp;
     int i;
     time_t timer;
     char *lineread = NULL;
     struct sigaction act, oact;
     extern char *optarg;
     extern int optind;
-    char cwd[STR_SIZE], *dn_guess = NULL, *mpt_guess = NULL;
-    char *service_name;
     char *line = NULL;
+    char *conffile;
+    const security_driver_t *secdrv;
+    char *req = NULL;
+    int response_error;
+    int new_argc;
+    char **new_argv;
+    struct tm *tm;
 
     safe_fd(-1, 0);
 
@@ -426,66 +314,64 @@ char **argv;
     /* Don't die when child closes pipe */
     signal(SIGPIPE, SIG_IGN);
 
-    dbopen();
+    dbopen(DBG_SUBDIR_CLIENT);
 
 #ifndef IGNORE_UID_CHECK
     if (geteuid() != 0) {
        erroutput_type |= ERR_SYSLOG;
        error("amrecover must be run by root");
+       /*NOTREACHED*/
     }
 #endif
 
     localhost = alloc(MAX_HOSTNAME_LENGTH+1);
     if (gethostname(localhost, MAX_HOSTNAME_LENGTH) != 0) {
        error("cannot determine local host name\n");
+       /*NOTREACHED*/
     }
     localhost[MAX_HOSTNAME_LENGTH] = '\0';
 
-    config = newstralloc(config, DEFAULT_CONFIG);
-    server_name = newstralloc(server_name, DEFAULT_SERVER);
-#ifdef DEFAULT_TAPE_SERVER
-    tape_server_name = newstralloc(tape_server_name, DEFAULT_TAPE_SERVER);
-#else
-    amfree(tape_server_name);
-#endif
-    if (argc > 1 && argv[1][0] != '-')
-    {
+    parse_client_conf(argc, argv, &new_argc, &new_argv);
+
+    if (new_argc > 1 && new_argv[1][0] != '-') {
        /*
         * If the first argument is not an option flag, then we assume
         * it is a configuration name to match the syntax of the other
         * Amanda utilities.
         */
-       char **new_argv;
+       char **new_argv1;
 
-       new_argv = (char **) alloc ((argc + 1 + 1) * sizeof (*new_argv));
-       new_argv[0] = argv[0];
-       new_argv[1] = "-C";
-       for (i = 1; i < argc; i++)
-       {
-           new_argv[i + 1] = argv[i];
+       new_argv1 = (char **) alloc((size_t)((new_argc + 1 + 1) * sizeof(*new_argv1)));
+       new_argv1[0] = new_argv[0];
+       new_argv1[1] = "-C";
+       for (i = 1; i < new_argc; i++) {
+           new_argv1[i + 1] = new_argv[i];
        }
-       new_argv[i + 1] = NULL;
-       argc++;
-       argv = new_argv;
+       new_argv1[i + 1] = NULL;
+       new_argc++;
+       amfree(new_argv);
+       new_argv = new_argv1;
     }
-    while ((i = getopt(argc, argv, "C:s:t:d:U")) != EOF)
-    {
-       switch (i)
-       {
+    while ((i = getopt(new_argc, new_argv, "C:s:t:d:U")) != EOF) {
+       switch (i) {
            case 'C':
-               config = newstralloc(config, optarg);
+               add_client_conf(CLN_CONF, optarg);
+               //config = newstralloc(config, optarg);
                break;
 
            case 's':
-               server_name = newstralloc(server_name, optarg);
+               add_client_conf(CLN_INDEX_SERVER, optarg);
+               //server_name = newstralloc(server_name, optarg);
                break;
 
            case 't':
-               tape_server_name = newstralloc(tape_server_name, optarg);
+               add_client_conf(CLN_TAPE_SERVER, optarg);
+               //tape_server_name = newstralloc(tape_server_name, optarg);
                break;
 
            case 'd':
-               tape_device_name = newstralloc(tape_device_name, optarg);
+               add_client_conf(CLN_TAPEDEV, optarg);
+               //tape_device_name = newstralloc(tape_device_name, optarg);
                break;
 
            case 'U':
@@ -494,12 +380,53 @@ char **argv;
                return 0;
        }
     }
-    if (optind != argc)
-    {
+    if (optind != new_argc) {
        (void)fprintf(stderr, USAGE);
        exit(1);
     }
 
+    our_features = am_init_feature_set();
+    our_features_string = am_feature_to_string(our_features);
+
+    conffile = vstralloc(CONFIG_DIR, "/", "amanda-client.conf", NULL);
+    if (read_clientconf(conffile) > 0) {
+       error("error reading conffile: %s", conffile);
+       /*NOTREACHED*/
+    }
+    amfree(conffile);
+
+    config = stralloc(client_getconf_str(CLN_CONF));
+
+    conffile = vstralloc(CONFIG_DIR, "/", config, "/", "amanda-client.conf",
+                        NULL);
+    if (read_clientconf(conffile) > 0) {
+       error("error reading conffile: %s", conffile);
+       /*NOTREACHED*/
+    }
+    amfree(conffile);
+
+    dbrename(config, DBG_SUBDIR_CLIENT);
+
+    report_bad_client_arg();
+
+    amfree(server_name);
+    server_name = getenv("AMANDA_SERVER");
+    if(!server_name) server_name = client_getconf_str(CLN_INDEX_SERVER);
+    server_name = stralloc(server_name);
+
+    amfree(tape_server_name);
+    tape_server_name = getenv("AMANDA_TAPESERVER");
+    if(!tape_server_name) tape_server_name = client_getconf_str(CLN_TAPE_SERVER);
+    tape_server_name = stralloc(tape_server_name);
+
+    amfree(tape_device_name);
+    tape_device_name = client_getconf_str(CLN_TAPEDEV);
+    if (tape_device_name)
+       tape_device_name = stralloc(tape_device_name);
+
+    authopt = stralloc(client_getconf_str(CLN_AUTH));
+
+
     amfree(disk_name);
     amfree(mount_point);
     amfree(disk_path);
@@ -512,33 +439,40 @@ char **argv;
     act.sa_handler = sigint_handler;
     sigemptyset(&act.sa_mask);
     act.sa_flags = 0;
-    if (sigaction(SIGINT, &act, &oact) != 0)
-    {
+    if (sigaction(SIGINT, &act, &oact) != 0) {
        error("error setting signal handler: %s", strerror(errno));
+       /*NOTREACHED*/
     }
 
-    service_name = stralloc2("amandaidx", SERVICE_SUFFIX);
+    protocol_init();
+
+    /* We assume that amindexd support fe_amindexd_options_features */
+    /*                             and fe_amindexd_options_auth     */
+    /* We should send a noop to really know                         */
+    req = vstralloc("SERVICE amindexd\n",
+                   "OPTIONS ", "features=", our_features_string, ";",
+                               "auth=", authopt, ";",
+                   "\n", NULL);
+
+    secdrv = security_getdriver(authopt);
+    if (secdrv == NULL) {
+       error("no '%s' security driver available for host '%s'",
+           authopt, server_name);
+       /*NOTREACHED*/
+    }
+
+    protocol_sendreq(server_name, secdrv, amindexd_client_get_security_conf,
+                    req, STARTUP_TIMEOUT, amindexd_response, &response_error);
+
+    amfree(req);
+    protocol_run();
 
     printf("AMRECOVER Version %s. Contacting server on %s ...\n",
-          version(), server_name);  
-    if ((sp = getservbyname(service_name, "tcp")) == NULL)
-    {
-       error("%s/tcp unknown protocol", service_name);
-    }
-    amfree(service_name);
-    server_socket = stream_client_privileged(server_name,
-                                            ntohs(sp->s_port),
-                                            -1,
-                                            -1,
-                                            &my_port,
-                                            0);
-    if (server_socket < 0)
-    {
-       error("cannot connect to %s: %s", server_name, strerror(errno));
-    }
-    if (my_port >= IPPORT_RESERVED)
-    {
-       error("did not get a reserved port: %d", my_port);
+          version(), server_name);
+
+    if(response_error != 0) {
+       fprintf(stderr,"%s\n",errstr);
+       exit(1);
     }
 
 #if 0
@@ -552,32 +486,21 @@ char **argv;
 #endif
 
     /* get server's banner */
-    if (grab_reply(1) == -1)
+    if (grab_reply(1) == -1) {
+        aclose(server_socket);
        exit(1);
-    if (!server_happy())
-    {
+    }
+    if (!server_happy()) {
        dbclose();
        aclose(server_socket);
        exit(1);
     }
 
-    /* do the security thing */
-    line = get_security();
-    if (converse(line) == -1)
-       exit(1);
-    if (!server_happy())
-       exit(1);
-    memset(line, '\0', strlen(line));
-    amfree(line);
-
     /* try to get the features from the server */
     {
-       char *our_feature_string = NULL;
        char *their_feature_string = NULL;
 
-       our_features = am_init_feature_set();
-       our_feature_string = am_feature_to_string(our_features);
-       line = stralloc2("FEATURES ", our_feature_string);
+       line = stralloc2("FEATURES ", our_features_string);
        if(exchange(line) == 0) {
            their_feature_string = stralloc(server_line+13);
            indexsrv_features = am_string_to_feature(their_feature_string);
@@ -585,70 +508,46 @@ char **argv;
        else {
            indexsrv_features = am_set_default_feature_set();
         }
-       amfree(our_feature_string);
        amfree(their_feature_string);
        amfree(line);
     }
 
     /* set the date of extraction to be today */
     (void)time(&timer);
-    strftime(dump_date, sizeof(dump_date), "%Y-%m-%d", localtime(&timer));
+    tm = localtime(&timer);
+    if (tm) 
+       strftime(dump_date, sizeof(dump_date), "%Y-%m-%d", tm);
+    else
+       error("BAD DATE");
+
     printf("Setting restore date to today (%s)\n", dump_date);
     line = stralloc2("DATE ", dump_date);
-    if (converse(line) == -1)
+    if (converse(line) == -1) {
+        aclose(server_socket);
        exit(1);
+    }
     amfree(line);
 
     line = stralloc2("SCNF ", config);
-    if (converse(line) == -1)
+    if (converse(line) == -1) {
+        aclose(server_socket);
        exit(1);
+    }
     amfree(line);
 
-    if (server_happy())
-    {
+    if (server_happy()) {
        /* set host we are restoring to this host by default */
        amfree(dump_hostname);
        set_host(localhost);
        if (dump_hostname)
-       {
-            /* get a starting disk and directory based on where
-              we currently are */
-           switch (guess_disk(cwd, sizeof(cwd), &dn_guess, &mpt_guess))
-           {
-               case 1:
-                   /* okay, got a guess. Set disk accordingly */
-                   printf("$CWD '%s' is on disk '%s' mounted at '%s'.\n",
-                          cwd, dn_guess, mpt_guess);
-                   set_disk(dn_guess, mpt_guess);
-                   set_directory(cwd);
-                   if (server_happy() && strcmp(cwd, mpt_guess) != 0)
-                       printf("WARNING: not on root of selected filesystem, check man-page!\n");
-                   amfree(dn_guess);
-                   amfree(mpt_guess);
-                   break;
-
-               case 0:
-                   printf("$CWD '%s' is on a network mounted disk\n",
-                          cwd);
-                   printf("so you must 'sethost' to the server\n");
-                   /* fake an unhappy server */
-                   server_line[0] = '5';
-                   break;
-
-               case 2:
-               case -1:
-               default:
-                   printf("Can't determine disk and mount point from $CWD '%s'\n", cwd);
-                   /* fake an unhappy server */
-                   server_line[0] = '5';
-                   break;
-           }
-       }
+           printf("Use the setdisk command to choose dump disk to recover\n");
+       else
+           printf("Use the sethost command to choose a host to recover\n");
+
     }
 
     quit_prog = 0;
-    do
-    {
+    do {
        if ((lineread = readline("amrecover> ")) == NULL) {
            clearerr(stdin);
            putchar('\n');
@@ -668,12 +567,245 @@ char **argv;
     return 0;
 }
 
+static void
+amindexd_response(
+    void *datap,
+    pkt_t *pkt,
+    security_handle_t *sech)
+{
+    int ports[NSTREAMS], *response_error = datap, i;
+    char *p;
+    char *tok;
+    char *extra = NULL;
+
+    assert(response_error != NULL);
+    assert(sech != NULL);
+
+    if (pkt == NULL) {
+       errstr = newvstralloc(errstr, "[request failed: ",
+                            security_geterror(sech), "]", NULL);
+       *response_error = 1;
+       return;
+    }
+
+    if (pkt->type == P_NAK) {
+#if defined(PACKET_DEBUG)
+       fprintf(stderr, "got nak response:\n----\n%s\n----\n\n", pkt->body);
+#endif
+
+       tok = strtok(pkt->body, " ");
+       if (tok == NULL || strcmp(tok, "ERROR") != 0)
+           goto bad_nak;
+
+       tok = strtok(NULL, "\n");
+       if (tok != NULL) {
+           errstr = newvstralloc(errstr, "NAK: ", tok, NULL);
+           *response_error = 1;
+       } else {
+bad_nak:
+           errstr = newstralloc(errstr, "request NAK");
+           *response_error = 2;
+       }
+       return;
+    }
+
+    if (pkt->type != P_REP) {
+       errstr = newvstralloc(errstr, "received strange packet type ",
+                             pkt_type2str(pkt->type), ": ", pkt->body, NULL);
+       *response_error = 1;
+       return;
+    }
+
+#if defined(PACKET_DEBUG)
+    fprintf(stderr, "got response:\n----\n%s\n----\n\n", pkt->body);
+#endif
+
+    for(i = 0; i < NSTREAMS; i++) {
+        ports[i] = -1;
+        streams[i].fd = NULL;
+    }
+
+    p = pkt->body;
+    while((tok = strtok(p, " \n")) != NULL) {
+       p = NULL;
+
+       /*
+        * Error response packets have "ERROR" followed by the error message
+        * followed by a newline.
+        */
+       if (strcmp(tok, "ERROR") == 0) {
+           tok = strtok(NULL, "\n");
+           if (tok == NULL)
+               tok = "[bogus error packet]";
+           errstr = newstralloc(errstr, tok);
+           *response_error = 2;
+           return;
+       }
+
+
+        /*
+         * Regular packets have CONNECT followed by three streams
+         */
+        if (strcmp(tok, "CONNECT") == 0) {
+
+           /*
+            * Parse the three stream specifiers out of the packet.
+            */
+           for (i = 0; i < NSTREAMS; i++) {
+               tok = strtok(NULL, " ");
+               if (tok == NULL || strcmp(tok, streams[i].name) != 0) {
+                   extra = vstralloc("CONNECT token is \"",
+                                     tok ? tok : "(null)",
+                                     "\": expected \"",
+                                     streams[i].name,
+                                     "\"",
+                                     NULL);
+                   goto parse_error;
+               }
+               tok = strtok(NULL, " \n");
+               if (tok == NULL || sscanf(tok, "%d", &ports[i]) != 1) {
+                   extra = vstralloc("CONNECT ",
+                                     streams[i].name,
+                                     " token is \"",
+                                     tok ? tok : "(null)",
+                                     "\": expected a port number",
+                                     NULL);
+                   goto parse_error;
+               }
+           }
+           continue;
+       }
+
+       /*
+        * OPTIONS [options string] '\n'
+        */
+       if (strcmp(tok, "OPTIONS") == 0) {
+           tok = strtok(NULL, "\n");
+           if (tok == NULL) {
+               extra = stralloc("OPTIONS token is missing");
+               goto parse_error;
+           }
+/*
+           tok_end = tok + strlen(tok);
+           while((p = strchr(tok, ';')) != NULL) {
+               *p++ = '\0';
+#define sc "features="
+               if(strncmp(tok, sc, sizeof(sc)-1) == 0) {
+                   tok += sizeof(sc) - 1;
+#undef sc
+                   am_release_feature_set(their_features);
+                   if((their_features = am_string_to_feature(tok)) == NULL) {
+                       errstr = newvstralloc(errstr,
+                                             "OPTIONS: bad features value: ",
+                                             tok,
+                                             NULL);
+                       goto parse_error;
+                   }
+               }
+               tok = p;
+           }
+*/
+           continue;
+       }
+/*
+       extra = vstralloc("next token is \"",
+                         tok ? tok : "(null)",
+                         "\": expected \"CONNECT\", \"ERROR\" or \"OPTIONS\"",
+                         NULL);
+       goto parse_error;
+*/
+    }
+
+    /*
+     * Connect the streams to their remote ports
+     */
+    for (i = 0; i < NSTREAMS; i++) {
+/*@i@*/        if (ports[i] == -1)
+           continue;
+       streams[i].fd = security_stream_client(sech, ports[i]);
+       if (streams[i].fd == NULL) {
+           errstr = newvstralloc(errstr,
+                       "[could not connect ", streams[i].name, " stream: ",
+                       security_geterror(sech), "]", NULL);
+           goto connect_error;
+       }
+    }
+    /*
+     * Authenticate the streams
+     */
+    for (i = 0; i < NSTREAMS; i++) {
+       if (streams[i].fd == NULL)
+           continue;
+       if (security_stream_auth(streams[i].fd) < 0) {
+           errstr = newvstralloc(errstr,
+               "[could not authenticate ", streams[i].name, " stream: ",
+               security_stream_geterror(streams[i].fd), "]", NULL);
+           goto connect_error;
+       }
+    }
+
+    /*
+     * The MESGFD and DATAFD streams are mandatory.  If we didn't get
+     * them, complain.
+     */
+    if (streams[MESGFD].fd == NULL) {
+        errstr = newstralloc(errstr, "[couldn't open MESG streams]");
+        goto connect_error;
+    }
+
+    /* everything worked */
+    *response_error = 0;
+    amindexd_alive = 1;
+    return;
+
+parse_error:
+    errstr = newvstralloc(errstr,
+                         "[parse of reply message failed: ",
+                         extra ? extra : "(no additional information)",
+                         "]",
+                         NULL);
+    amfree(extra);
+    *response_error = 2;
+    return;
+
+connect_error:
+    stop_amindexd();
+    *response_error = 1;
+}
+
+/*
+ * This is called when everything needs to shut down so event_loop()
+ * will exit.
+ */
+void
+stop_amindexd(void)
+{
+    int i;
+
+    amindexd_alive = 0;
+    for (i = 0; i < NSTREAMS; i++) {
+        if (streams[i].fd != NULL) {
+            security_stream_close(streams[i].fd);
+            streams[i].fd = NULL;
+        }
+    }
+}
+
 char *
-get_security()
+amindexd_client_get_security_conf(
+    char *     string,
+    void *     arg)
 {
-    struct passwd *pwptr;
+    (void)arg; /* Quiet unused parameter warning */
+
+    if(!string || !*string)
+       return(NULL);
 
-    if((pwptr = getpwuid(getuid())) == NULL)
-       error("can't get login name for my uid %ld", (long)getuid());
-    return stralloc2("SECURITY USER ", pwptr->pw_name);
+    if(strcmp(string, "auth")==0) {
+       return(client_getconf_str(CLN_AUTH));
+    }
+    else if(strcmp(string, "ssh_keys")==0) {
+       return(client_getconf_str(CLN_SSH_KEYS));
+    }
+    return(NULL);
 }