mexp_h * mexp_spawnlf (unsigned flags, const char *file, const char *arg, ...) { char **argv, **new_argv; size_t i; va_list args; mexp_h *h; argv = malloc (sizeof (char *)); if (argv == NULL) return NULL; argv[0] = (char *) arg; va_start (args, arg); for (i = 1; arg != NULL; ++i) { arg = va_arg (args, const char *); new_argv = realloc (argv, sizeof (char *) * (i+1)); if (new_argv == NULL) { free (argv); va_end (args); return NULL; } argv = new_argv; argv[i] = (char *) arg; } h = mexp_spawnvf (flags, file, argv); free (argv); va_end (args); return h; }
/** * Start ssh subprocess with the standard arguments and possibly some * optional arguments. Also handles authentication. */ static mexp_h * start_ssh (unsigned spawn_flags, struct config *config, char **extra_args, int wait_prompt) { size_t i, j, nr_args, count; char port_str[64]; char connect_timeout_str[128]; CLEANUP_FREE /* [sic] */ const char **args = NULL; mexp_h *h; const int ovecsize = 12; int ovector[ovecsize]; int saved_timeout; int using_password_auth; if (cache_ssh_identity (config) == -1) return NULL; /* Are we using password or identity authentication? */ using_password_auth = config->identity_file == NULL; /* Create the ssh argument array. */ nr_args = 0; if (extra_args != NULL) nr_args = guestfs_int_count_strings (extra_args); if (using_password_auth) nr_args += 13; else nr_args += 15; args = malloc (sizeof (char *) * nr_args); if (args == NULL) error (EXIT_FAILURE, errno, "malloc"); j = 0; args[j++] = "ssh"; args[j++] = "-p"; /* Port. */ snprintf (port_str, sizeof port_str, "%d", config->port); args[j++] = port_str; args[j++] = "-l"; /* Username. */ args[j++] = config->username ? config->username : "******"; args[j++] = "-o"; /* Host key will always be novel. */ args[j++] = "StrictHostKeyChecking=no"; args[j++] = "-o"; /* ConnectTimeout */ snprintf (connect_timeout_str, sizeof connect_timeout_str, "ConnectTimeout=%d", SSH_TIMEOUT); args[j++] = connect_timeout_str; if (using_password_auth) { /* Only use password authentication. */ args[j++] = "-o"; args[j++] = "PreferredAuthentications=keyboard-interactive,password"; } else { /* Use identity file (private key). */ args[j++] = "-o"; args[j++] = "PreferredAuthentications=publickey"; args[j++] = "-i"; args[j++] = config->identity_file; } if (extra_args != NULL) { for (i = 0; extra_args[i] != NULL; ++i) args[j++] = extra_args[i]; } args[j++] = config->server; /* Conversion server. */ args[j++] = NULL; assert (j == nr_args); #if DEBUG_STDERR fputs ("ssh command: ", stderr); for (i = 0; i < nr_args - 1; ++i) { if (i > 0) fputc (' ', stderr); fputs (args[i], stderr); } fputc ('\n', stderr); #endif /* Create the miniexpect handle. */ h = mexp_spawnvf (spawn_flags, "ssh", (char **) args); if (h == NULL) { set_ssh_internal_error ("ssh: mexp_spawnvf: %m"); return NULL; } /* We want the ssh ConnectTimeout to be less than the miniexpect * timeout, so that if the server is completely unresponsive we * still see the error from ssh, not a timeout from miniexpect. The * obvious solution to this is to set ConnectTimeout (above) and to * set the miniexpect timeout to be a little bit larger. */ mexp_set_timeout (h, SSH_TIMEOUT + 20); if (using_password_auth && config->password && strlen (config->password) > 0) { CLEANUP_FREE char *ssh_message = NULL; /* Wait for the password prompt. */ wait_password_again: switch (mexp_expect (h, (mexp_regexp[]) { { 100, .re = password_re },