[PATCH] pinentry-curses: Handle SETREPEAT.

Ben Kibbey bjk at luxsci.net
Wed Aug 17 02:51:35 CEST 2016


* pinentry/pinentry-curses.c (DIALOG_POS_REPEAT_PIN): New.
(dialog_t): Separate members for repeat.
(dialog_create): Create passphrase repeat field.
(dialog_switch_pos): Handle DIALOG_POS_REPEAT_PIN.
(dialog_input): Modify to handle the repeat field.
(test_repeat): New.
(dialog_run): Skip OK when changing fields and passphrases do not match.

Signed-off-by: Ben Kibbey <bjk at luxsci.net>
---
 pinentry/pinentry-curses.c | 287 +++++++++++++++++++++++++++++++++++----------
 1 file changed, 227 insertions(+), 60 deletions(-)

diff --git a/pinentry/pinentry-curses.c b/pinentry/pinentry-curses.c
index 659fa47..267d5be 100644
--- a/pinentry/pinentry-curses.c
+++ b/pinentry/pinentry-curses.c
@@ -70,6 +70,7 @@ typedef enum
   {
     DIALOG_POS_NONE,
     DIALOG_POS_PIN,
+    DIALOG_POS_REPEAT_PIN,
     DIALOG_POS_OK,
     DIALOG_POS_NOTOK,
     DIALOG_POS_CANCEL
@@ -79,15 +80,21 @@ dialog_pos_t;
 struct dialog
 {
   dialog_pos_t pos;
+  char *repeat_pin;
   int pin_y;
   int pin_x;
+  int repeat_pin_y;
+  int repeat_pin_x;
   /* Width of the PIN field.  */
   int pin_size;
+  int repeat_pin_size;
   /* Cursor location in PIN field.  */
   int pin_loc;
+  int repeat_pin_loc;
   int pin_max;
   /* Length of PIN.  */
   int pin_len;
+  int repeat_pin_len;
 
   int ok_y;
   int ok_x;
@@ -236,6 +243,7 @@ dialog_create (pinentry_t pinentry, dialog_t dialog)
   CH *description = NULL;
   CH *error = NULL;
   CH *prompt = NULL;
+  CH *repeat_passphrase = NULL;
 
   dialog->pinentry = pinentry;
 
@@ -256,6 +264,7 @@ dialog_create (pinentry_t pinentry, dialog_t dialog)
   COPY_OUT (description);
   COPY_OUT (error);
   COPY_OUT (prompt);
+  COPY_OUT (repeat_passphrase);
 
   /* There is no pinentry->default_notok.  Map it to
      pinentry->notok.  */
@@ -364,6 +373,9 @@ dialog_create (pinentry_t pinentry, dialog_t dialog)
 	  y += 2;	/* Error message.  */
 	}
       y += 2;		/* Pin entry field.  */
+
+      if (pinentry->repeat_passphrase)
+        y += 2;
     }
   y += 2;		/* OK/Cancel and bottom frame.  */
 
@@ -401,8 +413,12 @@ dialog_create (pinentry_t pinentry, dialog_t dialog)
       new_x = MIN_PINENTRY_LENGTH;
       if (prompt)
 	{
-	  new_x += STRLEN (prompt) + 1;	/* One space after prompt.  */
+          int n  = repeat_passphrase ? STRLEN (repeat_passphrase) : 0;
+	  new_x += STRLEN (prompt) + n + 1; /* One space after prompt.  */
 	}
+      else if (repeat_passphrase)
+        new_x += STRLEN (repeat_passphrase) + 1;
+
       if (new_x > size_x - 4)
 	new_x = size_x - 4;
       if (new_x > x)
@@ -431,8 +447,8 @@ dialog_create (pinentry_t pinentry, dialog_t dialog)
 
   dialog->pos = DIALOG_POS_NONE;
   dialog->pin_max = pinentry->pin_len;
-  dialog->pin_loc = 0;
-  dialog->pin_len = 0;
+  dialog->pin_loc = dialog->repeat_pin_loc = 0;
+  dialog->pin_len = dialog->repeat_pin_len = 0;
   ypos = (size_y - y) / 2;
   xpos = (size_x - x) / 2;
   move (ypos, xpos);
@@ -545,6 +561,35 @@ dialog_create (pinentry_t pinentry, dialog_t dialog)
       move (ypos, xpos);
       addch (ACS_VLINE);
       ypos++;
+
+      if (repeat_passphrase)
+        {
+	  CH *p = repeat_passphrase;
+
+          move (ypos, xpos);
+          addch (ACS_VLINE);
+          addch (' ');
+
+          dialog->repeat_pin_y = ypos;
+          dialog->repeat_pin_x = xpos + 2;
+          dialog->repeat_pin_size = x - 4;
+	  i = STRLEN (p);
+	  if (i > x - 4 - MIN_PINENTRY_LENGTH)
+	    i = x - 4 - MIN_PINENTRY_LENGTH;
+	  dialog->repeat_pin_x += i + 1;
+          dialog->repeat_pin_size -= i + 1;
+	  while (i-- > 0)
+	    {
+	      ADDCH (*(p++));
+	    }
+	  addch (' ');
+          for (i = 0; i < dialog->repeat_pin_size; i++)
+            addch ('_');
+          ypos++;
+          move (ypos, xpos);
+          addch (ACS_VLINE);
+          ypos++;
+        }
     }
   move (ypos, xpos);
   addch (ACS_VLINE);
@@ -590,6 +635,8 @@ dialog_create (pinentry_t pinentry, dialog_t dialog)
     free (error);
   if (prompt)
     free (prompt);
+  if (repeat_passphrase)
+    free (repeat_passphrase);
   return err;
 }
 
@@ -620,8 +667,8 @@ dialog_switch_pos (dialog_t diag, dialog_pos_t new_pos)
       switch (diag->pos)
 	{
 	case DIALOG_POS_OK:
-	  move (diag->ok_y, diag->ok_x);
-	  addstr (diag->ok);
+          move (diag->ok_y, diag->ok_x);
+          addstr (diag->ok);
 	  break;
 	case DIALOG_POS_NOTOK:
           if (diag->notok)
@@ -647,13 +694,17 @@ dialog_switch_pos (dialog_t diag, dialog_pos_t new_pos)
 	  move (diag->pin_y, diag->pin_x + diag->pin_loc);
 	  set_cursor_state (1);
 	  break;
+	case DIALOG_POS_REPEAT_PIN:
+	  move (diag->repeat_pin_y, diag->repeat_pin_x + diag->repeat_pin_loc);
+	  set_cursor_state (1);
+	  break;
 	case DIALOG_POS_OK:
 	  set_cursor_state (0);
-	  move (diag->ok_y, diag->ok_x);
-	  standout ();
-	  addstr (diag->ok);
-	  standend ();
-	  move (diag->ok_y, diag->ok_x);
+          move (diag->ok_y, diag->ok_x);
+          standout ();
+          addstr (diag->ok);
+          standend ();
+          move (diag->ok_y, diag->ok_x);
 	  break;
 	case DIALOG_POS_NOTOK:
           if (diag->notok)
@@ -690,9 +741,36 @@ dialog_switch_pos (dialog_t diag, dialog_pos_t new_pos)
 static void
 dialog_input (dialog_t diag, int alt, int chr)
 {
-  int old_loc = diag->pin_loc;
+  int old_loc = diag->pos == DIALOG_POS_PIN ? diag->pin_loc
+    : diag->repeat_pin_loc;
+  int *pin_len;
+  int *pin_loc;
+  int *pin_size;
+  int *pin_x, *pin_y;
+  int *pin_max = &diag->pin_max;
+  char *pin;
+
   assert (diag->pinentry->pin);
-  assert (diag->pos == DIALOG_POS_PIN);
+  assert (diag->pos == DIALOG_POS_PIN || diag->pos == DIALOG_POS_REPEAT_PIN);
+
+  if (diag->pos == DIALOG_POS_PIN)
+    {
+      pin_len = &diag->pin_len;
+      pin_loc = &diag->pin_loc;
+      pin_size = &diag->pin_size;
+      pin_x = &diag->pin_x;
+      pin_y = &diag->pin_y;
+      pin = diag->pinentry->pin;
+    }
+  else
+    {
+      pin_len = &diag->repeat_pin_len;
+      pin_loc = &diag->repeat_pin_loc;
+      pin_size = &diag->repeat_pin_size;
+      pin_x = &diag->repeat_pin_x;
+      pin_y = &diag->repeat_pin_y;
+      pin = diag->repeat_pin;
+    }
 
   if (alt && chr == KEY_BACKSPACE)
     /* Remap alt-backspace to control-W.  */
@@ -706,15 +784,15 @@ dialog_input (dialog_t diag, int alt, int chr)
       /* ASCII DEL.  What Mac OS X apparently emits when the "delete"
 	 (backspace) key is pressed.  */
     case 127:
-      if (diag->pin_len > 0)
+      if (*pin_len > 0)
 	{
-	  diag->pin_len--;
-	  diag->pin_loc--;
-	  if (diag->pin_loc == 0 && diag->pin_len > 0)
+	  (*pin_len)--;
+	  (*pin_loc)--;
+	  if (*pin_loc == 0 && *pin_len > 0)
 	    {
-	      diag->pin_loc = diag->pin_size - 5;
-	      if (diag->pin_loc > diag->pin_len)
-		diag->pin_loc = diag->pin_len;
+	      *pin_loc = *pin_size - 5;
+	      if (*pin_loc > *pin_len)
+		*pin_loc = *pin_len;
 	    }
 	}
       break;
@@ -727,47 +805,45 @@ dialog_input (dialog_t diag, int alt, int chr)
 
     case 'u' - 'a' + 1: /* control-u */
       /* Erase the whole line.  */
-      if (diag->pin_len > 0)
+      if (*pin_len > 0)
 	{
-	  diag->pin_len = 0;
-	  diag->pin_loc = 0;
+	  *pin_len = 0;
+	  *pin_loc = 0;
 	}
       break;
 
     case 'w' - 'a' + 1: /* control-w.  */
-      while (diag->pin_len > 0
-	     && diag->pinentry->pin[diag->pin_len - 1] == ' ')
+      while (*pin_len > 0 && pin[*pin_len - 1] == ' ')
 	{
-	  diag->pin_len --;
-	  diag->pin_loc --;
-	  if (diag->pin_loc < 0)
+	  (*pin_len)--;
+	  (*pin_loc)--;
+	  if (*pin_loc < 0)
 	    {
-	      diag->pin_loc += diag->pin_size;
-	      if (diag->pin_loc > diag->pin_len)
-		diag->pin_loc = diag->pin_len;
+	      *pin_loc += *pin_size;
+	      if (*pin_loc > *pin_len)
+		*pin_loc = *pin_len;
 	    }
 	}
-      while (diag->pin_len > 0
-	     && diag->pinentry->pin[diag->pin_len - 1] != ' ')
+      while (*pin_len > 0 && pin[*pin_len - 1] != ' ')
 	{
-	  diag->pin_len --;
-	  diag->pin_loc --;
-	  if (diag->pin_loc < 0)
+	  (*pin_len)--;
+	  (*pin_loc)--;
+	  if (*pin_loc < 0)
 	    {
-	      diag->pin_loc += diag->pin_size;
-	      if (diag->pin_loc > diag->pin_len)
-		diag->pin_loc = diag->pin_len;
+	      *pin_loc += *pin_size;
+	      if (*pin_loc > *pin_len)
+		*pin_loc = *pin_len;
 	    }
 	}
 
       break;
 
     default:
-      if (chr > 0 && chr < 256 && diag->pin_len < diag->pin_max)
+      if (chr > 0 && chr < 256 && *pin_len < *pin_max)
 	{
 	  /* Make sure there is enough room for this character and a
 	     following NUL byte.  */
-	  if (! pinentry_setbufferlen (diag->pinentry, diag->pin_len + 2))
+	  if (! pinentry_setbufferlen (diag->pinentry, *pin_len + 2))
 	    {
 	      /* Bail.  Here we use a simple approach.  It would be
                  better to have a pinentry_bug function.  */
@@ -775,32 +851,85 @@ dialog_input (dialog_t diag, int alt, int chr)
               abort ();
 	    }
 
-	  diag->pinentry->pin[diag->pin_len] = (char) chr;
-	  diag->pin_len++;
-	  diag->pin_loc++;
-	  if (diag->pin_loc == diag->pin_size && diag->pin_len < diag->pin_max)
+          if (diag->pos == DIALOG_POS_REPEAT_PIN)
+            {
+              if (!*pin_len || *pin_len > diag->repeat_pin_len)
+                {
+                  char *newp = secmem_realloc (diag->repeat_pin, *pin_len + 2);
+
+                  if (newp)
+                    pin = diag->repeat_pin = newp;
+                  else
+                    {
+                      secmem_free (diag->pinentry->pin);
+                      diag->pinentry->pin = 0;
+                      diag->pinentry->pin_len = 0;
+                      secmem_free (diag->repeat_pin);
+                      diag->repeat_pin = 0;
+                      *pin_len = 0;
+                      /* Bail.  Here we use a simple approach.  It would be
+                         better to have a pinentry_bug function.  */
+                      assert (!"setbufferlen failed");
+                      abort ();
+                    }
+                }
+            }
+          else
+            pin = diag->pinentry->pin;
+
+	  pin[*pin_len] = (char) chr;
+	  (*pin_len)++;
+	  (*pin_loc)++;
+	  if (*pin_loc == *pin_size && *pin_len < *pin_max)
 	    {
-	      diag->pin_loc = 5;
-	      if (diag->pin_loc < diag->pin_size - (diag->pin_max + 1 - diag->pin_len))
-		diag->pin_loc = diag->pin_size - (diag->pin_max + 1 - diag->pin_len);
+	      *pin_loc = 5;
+	      if (*pin_loc < *pin_size - (*pin_max + 1 - *pin_len))
+		*pin_loc = *pin_size - (*pin_max + 1 - *pin_len);
 	    }
 	}
       break;
     }
 
-  if (old_loc < diag->pin_loc)
+  if (pin)
+    pin[*pin_len] = 0;
+
+  if (old_loc < *pin_loc)
     {
-      move (diag->pin_y, diag->pin_x + old_loc);
-      while (old_loc++ < diag->pin_loc)
+      move (*pin_y, *pin_x + old_loc);
+      while (old_loc++ < *pin_loc)
 	addch ('*');
     }
-  else if (old_loc > diag->pin_loc)
+  else if (old_loc > *pin_loc)
     {
-      move (diag->pin_y, diag->pin_x + diag->pin_loc);
-      while (old_loc-- > diag->pin_loc)
+      move (*pin_y, *pin_x + *pin_loc);
+      while (old_loc-- > *pin_loc)
 	addch ('_');
     }
-  move (diag->pin_y, diag->pin_x + diag->pin_loc);
+  move (*pin_y, *pin_x + *pin_loc);
+}
+
+static int
+test_repeat (dialog_t diag)
+{
+  if (!diag->pinentry->repeat_passphrase)
+    return 1;
+
+  if (!diag->pinentry->pin && !diag->repeat_pin)
+    return 1;
+
+  if ((diag->pinentry->pin && !*diag->pinentry->pin
+          && (!diag->repeat_pin || !*diag->repeat_pin)))
+    return 1;
+
+  if (diag->repeat_pin && !*diag->repeat_pin
+          && (!diag->pinentry->pin || !*diag->pinentry->pin))
+    return 1;
+
+  if (diag->pinentry->pin && diag->repeat_pin
+      && !strcmp (diag->pinentry->pin, diag->repeat_pin))
+    return 1;
+
+  return 0;
 }
 
 static int
@@ -957,9 +1086,15 @@ dialog_run (pinentry_t pinentry, const char *tty_name, const char *tty_type)
 	  switch (diag.pos)
 	    {
 	    case DIALOG_POS_OK:
-	      if (diag.pinentry->pin)
+	      if (diag.pinentry->repeat_passphrase)
+                dialog_switch_pos (&diag, DIALOG_POS_REPEAT_PIN);
+              else if (diag.pinentry->pin)
 		dialog_switch_pos (&diag, DIALOG_POS_PIN);
 	      break;
+            case DIALOG_POS_REPEAT_PIN:
+              if (diag.pinentry->pin)
+		dialog_switch_pos (&diag, DIALOG_POS_PIN);
+              break;
 	    case DIALOG_POS_NOTOK:
 	      dialog_switch_pos (&diag, DIALOG_POS_OK);
 	      break;
@@ -967,7 +1102,12 @@ dialog_run (pinentry_t pinentry, const char *tty_name, const char *tty_type)
 	      if (diag.notok)
 		dialog_switch_pos (&diag, DIALOG_POS_NOTOK);
 	      else
-		dialog_switch_pos (&diag, DIALOG_POS_OK);
+                {
+                  if (!test_repeat (&diag))
+                    dialog_switch_pos (&diag, DIALOG_POS_REPEAT_PIN);
+                  else
+                    dialog_switch_pos (&diag, DIALOG_POS_OK);
+                }
 	      break;
 	    default:
 	      break;
@@ -979,8 +1119,17 @@ dialog_run (pinentry_t pinentry, const char *tty_name, const char *tty_type)
 	  switch (diag.pos)
 	    {
 	    case DIALOG_POS_PIN:
-	      dialog_switch_pos (&diag, DIALOG_POS_OK);
+	      if (diag.pinentry->repeat_passphrase)
+                dialog_switch_pos (&diag, DIALOG_POS_REPEAT_PIN);
+              else
+                dialog_switch_pos (&diag, DIALOG_POS_OK);
 	      break;
+	    case DIALOG_POS_REPEAT_PIN:
+              if (test_repeat (&diag))
+                dialog_switch_pos (&diag, DIALOG_POS_OK);
+              else
+                dialog_switch_pos (&diag, DIALOG_POS_CANCEL);
+              break;
 	    case DIALOG_POS_OK:
 	      if (diag.notok)
 		dialog_switch_pos (&diag, DIALOG_POS_NOTOK);
@@ -999,8 +1148,17 @@ dialog_run (pinentry_t pinentry, const char *tty_name, const char *tty_type)
 	  switch (diag.pos)
 	    {
 	    case DIALOG_POS_PIN:
-	      dialog_switch_pos (&diag, DIALOG_POS_OK);
+	      if (diag.pinentry->repeat_passphrase)
+                dialog_switch_pos (&diag, DIALOG_POS_REPEAT_PIN);
+              else
+                dialog_switch_pos (&diag, DIALOG_POS_OK);
 	      break;
+	    case DIALOG_POS_REPEAT_PIN:
+              if (test_repeat (&diag))
+                dialog_switch_pos (&diag, DIALOG_POS_OK);
+              else
+                dialog_switch_pos (&diag, DIALOG_POS_CANCEL);
+              break;
 	    case DIALOG_POS_OK:
 	      if (diag.notok)
 		dialog_switch_pos (&diag, DIALOG_POS_NOTOK);
@@ -1029,7 +1187,10 @@ dialog_run (pinentry_t pinentry, const char *tty_name, const char *tty_type)
 	  switch (diag.pos)
 	    {
 	    case DIALOG_POS_PIN:
+	    case DIALOG_POS_REPEAT_PIN:
 	    case DIALOG_POS_OK:
+              if (!test_repeat (&diag))
+                break;
 	      done = 1;
 	      break;
 	    case DIALOG_POS_NOTOK:
@@ -1044,8 +1205,11 @@ dialog_run (pinentry_t pinentry, const char *tty_name, const char *tty_type)
 	  break;
 
 	default:
-	  if (diag.pos == DIALOG_POS_PIN)
-	    dialog_input (&diag, alt, c);
+	  if (diag.pos == DIALOG_POS_PIN || diag.pos == DIALOG_POS_REPEAT_PIN)
+            {
+              dialog_input (&diag, alt, c);
+              diag.pinentry->repeat_okay = test_repeat (&diag);
+            }
 	}
 #ifndef HAVE_DOSISH_SYSTEM
       no_input = 0;
@@ -1097,6 +1261,9 @@ dialog_run (pinentry_t pinentry, const char *tty_name, const char *tty_type)
 	}
     }
 
+  if (diag.repeat_pin)
+    secmem_free (diag.repeat_pin);
+
   if (done == -2)
     pinentry->canceled = 1;
 
-- 
2.8.1




More information about the Gnupg-devel mailing list