Add debugging capability at runtime.
authorRichard W.M. Jones <rjones@redhat.com>
Wed, 11 Oct 2017 15:12:29 +0000 (16:12 +0100)
committerRichard W.M. Jones <rjones@redhat.com>
Wed, 11 Oct 2017 21:38:18 +0000 (22:38 +0100)
Debugging can now be enabled at runtime.

example-sshpass.c
miniexpect.c
miniexpect.h
miniexpect.pod

index 3449a20..b531496 100644 (file)
  * 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;
@@ -52,20 +63,31 @@ main (int argc, char *argv[])
   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");
@@ -91,10 +113,16 @@ main (int argc, char *argv[])
     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;
   }
index b370cfe..7debc02 100644 (file)
 
 #include "miniexpect.h"
 
-#define DEBUG 0
-
-#if DEBUG
 static void debug_buffer (FILE *, const char *);
-#endif
 
 static mexp_h *
 create_handle (void)
@@ -68,6 +64,7 @@ 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;
@@ -296,9 +293,8 @@ mexp_expect (mexp_h *h, const mexp_regexp *regexps, int *ovector, int ovecsize)
     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;
 
@@ -318,9 +314,8 @@ mexp_expect (mexp_h *h, const mexp_regexp *regexps, int *ovector, int ovecsize)
       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,
@@ -336,12 +331,12 @@ mexp_expect (mexp_h *h, const mexp_regexp *regexps, int *ovector, int ovecsize)
     /* 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. */
@@ -395,28 +390,32 @@ mexp_expect (mexp_h *h, const mexp_regexp *regexps, int *ovector, int ovecsize)
   }
 }
 
-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;
@@ -435,12 +434,35 @@ mexp_printf (mexp_h *h, const char *fs, ...)
 }
 
 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)
@@ -465,5 +487,3 @@ debug_buffer (FILE *fp, const char *buf)
     buf++;
   }
 }
-#endif
-
index e4d6010..14d8236 100644 (file)
@@ -29,6 +29,7 @@
 #ifndef MINIEXPECT_H_
 #define MINIEXPECT_H_
 
+#include <stdio.h>
 #include <unistd.h>
 
 #include <pcre.h>
@@ -44,6 +45,7 @@ struct mexp_h {
   ssize_t next_match;
   size_t read_size;
   int pcre_error;
+  FILE *debug_fp;
   void *user1;
   void *user2;
   void *user3;
@@ -62,6 +64,8 @@ typedef struct mexp_h mexp_h;
 #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);
@@ -99,6 +103,8 @@ extern int mexp_expect (mexp_h *h, const mexp_regexp *regexps,
 /* 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_ */
index cd008fc..fe76979 100644 (file)
@@ -177,6 +177,18 @@ returned by L<pcre_exec(3)>, and so you can call it like this:
 
 =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:
 
@@ -415,6 +427,8 @@ However we also provide a convenience function:
 
 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>.
@@ -435,6 +449,13 @@ send a command followed by a newline you have to do something like:
 
  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);>