Debugging can now be enabled at runtime.
* The remaining arguments are passed to the ssh subprocess.
*
* For example:
- * sshpass 123456 ssh remote.example.com
- * sshpass 123456 ssh -l root remote.example.com
+ * sshpass [-d] 123456 ssh remote.example.com
+ * sshpass [-d] 123456 ssh -l root remote.example.com
+ *
+ * Use the -d flag to enable debugging to stderr.
*/
#include <config.h>
static pcre *compile_re (const char *rex);
+static void
+usage (void)
+{
+ fprintf (stderr, "usage: sshpass [-d] PASSWORD ssh [SSH-ARGS...] HOST\n");
+ exit (EXIT_FAILURE);
+}
+
int
main (int argc, char *argv[])
{
+ int opt;
+ int debug = 0;
mexp_h *h;
const char *password;
int status;
const int ovecsize = 12;
int ovector[ovecsize];
- if (argc <= 3) {
- fprintf (stderr, "usage: sshpass PASSWORD ssh [SSH-ARGS...] HOST\n");
- exit (EXIT_FAILURE);
+ while ((opt = getopt (argc, argv, "d")) != -1) {
+ switch (opt) {
+ case 'd':
+ debug = 1;
+ break;
+ default:
+ usage ();
+ }
}
- password = argv[1];
+ if (argc-optind <= 2)
+ usage ();
+
+ password = argv[optind];
+ optind++;
printf ("starting ssh command ...\n");
- h = mexp_spawnv (argv[2], &argv[2]);
+ h = mexp_spawnv (argv[optind], &argv[optind]);
if (h == NULL) {
perror ("mexp_spawnv: ssh");
exit (EXIT_FAILURE);
}
+ if (debug)
+ mexp_set_debug_file (h, stderr);
/* Wait for the password prompt. */
password_re = compile_re ("assword");
goto error;
}
- /* Got the password prompt, so send a password. */
+ /* Got the password prompt, so send a password.
+ *
+ * Note use of mexp_printf_password here which is identical to
+ * mexp_printf except that it hides the password in debugging
+ * output.
+ */
printf ("sending the password ...\n");
- if (mexp_printf (h, "%s\n", password) == -1) {
+ if (mexp_printf_password (h, "%s", password) == -1 ||
+ mexp_printf (h, "\n") == -1) {
perror ("mexp_printf");
goto error;
}
#include "miniexpect.h"
-#define DEBUG 0
-
-#if DEBUG
static void debug_buffer (FILE *, const char *);
-#endif
static mexp_h *
create_handle (void)
h->buffer = NULL;
h->len = h->alloc = 0;
h->next_match = -1;
+ h->debug_fp = NULL;
h->user1 = h->user2 = h->user3 = NULL;
return h;
pfds[0].events = POLLIN;
pfds[0].revents = 0;
r = poll (pfds, 1, timeout);
-#if DEBUG
- fprintf (stderr, "DEBUG: poll returned %d\n", r);
-#endif
+ if (h->debug_fp)
+ fprintf (h->debug_fp, "DEBUG: poll returned %d\n", r);
if (r == -1)
return MEXP_ERROR;
h->alloc += h->read_size;
}
rs = read (h->fd, h->buffer + h->len, h->read_size);
-#if DEBUG
- fprintf (stderr, "DEBUG: read returned %zd\n", rs);
-#endif
+ if (h->debug_fp)
+ fprintf (h->debug_fp, "DEBUG: read returned %zd\n", rs);
if (rs == -1) {
/* Annoyingly on Linux (I'm fairly sure this is a bug) if the
* writer closes the connection, the entire pty is destroyed,
/* We read something. */
h->len += rs;
h->buffer[h->len] = '\0';
-#if DEBUG
- fprintf (stderr, "DEBUG: read %zd bytes from pty\n", rs);
- fprintf (stderr, "DEBUG: buffer content: ");
- debug_buffer (stderr, h->buffer);
- fprintf (stderr, "\n");
-#endif
+ if (h->debug_fp) {
+ fprintf (h->debug_fp, "DEBUG: read %zd bytes from pty\n", rs);
+ fprintf (h->debug_fp, "DEBUG: buffer content: ");
+ debug_buffer (h->debug_fp, h->buffer);
+ fprintf (h->debug_fp, "\n");
+ }
try_match:
/* See if there is a full or partial match against any regexp. */
}
}
-int
-mexp_printf (mexp_h *h, const char *fs, ...)
+static int mexp_vprintf (mexp_h *h, int password, const char *fs, va_list args)
+ __attribute__((format(printf,3,0)));
+
+static int
+mexp_vprintf (mexp_h *h, int password, const char *fs, va_list args)
{
- va_list args;
char *msg;
int len;
size_t n;
ssize_t r;
char *p;
- va_start (args, fs);
len = vasprintf (&msg, fs, args);
- va_end (args);
if (len < 0)
return -1;
-#if DEBUG
- fprintf (stderr, "DEBUG: writing: ");
- debug_buffer (stderr, msg);
- fprintf (stderr, "\n");
-#endif
+ if (h->debug_fp) {
+ if (!password) {
+ fprintf (h->debug_fp, "DEBUG: writing: ");
+ debug_buffer (h->debug_fp, msg);
+ fprintf (h->debug_fp, "\n");
+ }
+ else
+ fprintf (h->debug_fp, "DEBUG: writing the password\n");
+ }
n = len;
p = msg;
}
int
+mexp_printf (mexp_h *h, const char *fs, ...)
+{
+ int r;
+ va_list args;
+
+ va_start (args, fs);
+ r = mexp_vprintf (h, 0, fs, args);
+ va_end (args);
+ return r;
+}
+
+int
+mexp_printf_password (mexp_h *h, const char *fs, ...)
+{
+ int r;
+ va_list args;
+
+ va_start (args, fs);
+ r = mexp_vprintf (h, 1, fs, args);
+ va_end (args);
+ return r;
+}
+
+int
mexp_send_interrupt (mexp_h *h)
{
return write (h->fd, "\003", 1);
}
-#if DEBUG
/* Print escaped buffer to fp. */
static void
debug_buffer (FILE *fp, const char *buf)
buf++;
}
}
-#endif
-
#ifndef MINIEXPECT_H_
#define MINIEXPECT_H_
+#include <stdio.h>
#include <unistd.h>
#include <pcre.h>
ssize_t next_match;
size_t read_size;
int pcre_error;
+ FILE *debug_fp;
void *user1;
void *user2;
void *user3;
#define mexp_get_read_size(h) ((h)->read_size)
#define mexp_set_read_size(h, size) ((h)->read_size = (size))
#define mexp_get_pcre_error(h) ((h)->pcre_error)
+#define mexp_set_debug_file(h, fp) ((h)->debug_fp = (fp))
+#define mexp_get_debug_file(h) ((h)->debug_fp)
/* Spawn a subprocess. */
extern mexp_h *mexp_spawnvf (unsigned flags, const char *file, char **argv);
/* Sending commands, keypresses. */
extern int mexp_printf (mexp_h *h, const char *fs, ...)
__attribute__((format(printf,2,3)));
+extern int mexp_printf_password (mexp_h *h, const char *fs, ...)
+ __attribute__((format(printf,2,3)));
extern int mexp_send_interrupt (mexp_h *h);
#endif /* MINIEXPECT_H_ */
=back
+B<void mexp_set_debug_file (mexp *h, FILE *fp);>
+
+B<FILE *mexp_get_debug_file (mexp *h);>
+
+Set or get the debug file of the handle. To enable debugging, pass a
+non-C<NULL> file handle, eg. C<stderr>. To disable debugging, pass
+C<NULL>. Debugging messages are printed on the file handle.
+
+Note that all output and input gets printed, including passwords. To
+prevent passwords from being printed, modify your code to call
+C<mexp_printf_password> instead of C<mexp_printf>.
+
The following fields in the handle do not have methods, but can be
accessed directly instead:
B<int mexp_printf (mexp_h *h, const char *fs, ...);>
+B<int mexp_printf_password (mexp_h *h, const char *fs, ...);>
+
This returns the number of bytes, if the whole message was written OK.
If there was an error, -1 is returned and the error is available in
C<errno>.
mexp_printf (h, "exit\n");
+=item *
+
+C<mexp_printf_password> works identically to C<mexp_printf> except
+that the output is I<not> sent to the debugging file if debugging is
+enabled. As the name suggests, use this for passwords so that they
+don't appear in debugging output.
+
=back
B<int mexp_send_interrupt (mexp_h *h);>