Display security state when asking for password

Indicate to the user how secure the transport channel is so they
can avoid entering their password for untrusted sites.
diff --git a/common/rfb/CConnection.h b/common/rfb/CConnection.h
index e0a000f..e29c033 100644
--- a/common/rfb/CConnection.h
+++ b/common/rfb/CConnection.h
@@ -134,6 +134,8 @@
     // Identities, to determine the unique(ish) name of the server.
     const char* getServerName() const { return serverName.buf; }
 
+    bool isSecure() const { return csecurity ? csecurity->isSecure() : false; }
+
     enum stateEnum {
       RFBSTATE_UNINITIALISED,
       RFBSTATE_PROTOCOL_VERSION,
diff --git a/common/rfb/CSecurity.h b/common/rfb/CSecurity.h
index 36da5c7..3fedc50 100644
--- a/common/rfb/CSecurity.h
+++ b/common/rfb/CSecurity.h
@@ -49,6 +49,7 @@
     virtual void destroy() { delete this; }
     virtual int getType() const = 0;
     virtual const char* description() const = 0;
+    virtual bool isSecure() const { return false; }
 
     /*
      * Use variable directly instead of dumb get/set methods.
diff --git a/common/rfb/CSecurityPlain.cxx b/common/rfb/CSecurityPlain.cxx
index 0320ce2..8e383c3 100644
--- a/common/rfb/CSecurityPlain.cxx
+++ b/common/rfb/CSecurityPlain.cxx
@@ -33,7 +33,7 @@
   CharArray username;
   CharArray password;
 
-  (CSecurity::upg)->getUserPasswd(&username.buf, &password.buf);
+  (CSecurity::upg)->getUserPasswd(cc->isSecure(), &username.buf, &password.buf);
 
   // Return the response to the server
   os->writeU32(strlen(username.buf));
diff --git a/common/rfb/CSecurityStack.cxx b/common/rfb/CSecurityStack.cxx
index cfc60fd..47c3f6d 100644
--- a/common/rfb/CSecurityStack.cxx
+++ b/common/rfb/CSecurityStack.cxx
@@ -63,3 +63,12 @@
 
   return res;
 }
+
+bool CSecurityStack::isSecure() const
+{
+  if (state0 && state0->isSecure())
+    return true;
+  if (state == 1 && state1 && state1->isSecure())
+    return true;
+  return false;
+}
diff --git a/common/rfb/CSecurityStack.h b/common/rfb/CSecurityStack.h
index a76b3fe..a16003f 100644
--- a/common/rfb/CSecurityStack.h
+++ b/common/rfb/CSecurityStack.h
@@ -32,6 +32,7 @@
     virtual bool processMsg(CConnection* cc);
     virtual int getType() const {return type;};
     virtual const char* description() const {return name;}
+    virtual bool isSecure() const;
   protected:
     int state;
     CSecurity* state0;
diff --git a/common/rfb/CSecurityTLS.h b/common/rfb/CSecurityTLS.h
index 57d964d..e726d1e 100644
--- a/common/rfb/CSecurityTLS.h
+++ b/common/rfb/CSecurityTLS.h
@@ -48,6 +48,7 @@
     virtual int getType() const { return anon ? secTypeTLSNone : secTypeX509None; }
     virtual const char* description() const
       { return anon ? "TLS Encryption without VncAuth" : "X509 Encryption without VncAuth"; }
+    virtual bool isSecure() const { return !anon; }
     static void setDefaults();
 
     static StringParameter X509CA;
diff --git a/common/rfb/CSecurityVeNCrypt.cxx b/common/rfb/CSecurityVeNCrypt.cxx
index a15da4a..4a25245 100644
--- a/common/rfb/CSecurityVeNCrypt.cxx
+++ b/common/rfb/CSecurityVeNCrypt.cxx
@@ -191,3 +191,9 @@
   return csecurity->processMsg(cc);
 }
 
+bool CSecurityVeNCrypt::isSecure() const
+{
+  if (csecurity && csecurity->isSecure())
+    return true;
+  return false;
+}
diff --git a/common/rfb/CSecurityVeNCrypt.h b/common/rfb/CSecurityVeNCrypt.h
index 55d0744..1ff0c02 100644
--- a/common/rfb/CSecurityVeNCrypt.h
+++ b/common/rfb/CSecurityVeNCrypt.h
@@ -39,6 +39,7 @@
     virtual bool processMsg(CConnection* cc);// { return true; }
     int getType() const {return chosenType;}
     virtual const char* description() const { return secTypeName(chosenType); }
+    virtual bool isSecure() const;
 
   protected:
     CSecurity *csecurity;
diff --git a/common/rfb/CSecurityVncAuth.cxx b/common/rfb/CSecurityVncAuth.cxx
index f44e56e..46463e0 100644
--- a/common/rfb/CSecurityVncAuth.cxx
+++ b/common/rfb/CSecurityVncAuth.cxx
@@ -49,7 +49,7 @@
   rdr::U8 challenge[vncAuthChallengeSize];
   is->readBytes(challenge, vncAuthChallengeSize);
   PlainPasswd passwd;
-  (CSecurity::upg)->getUserPasswd(0, &passwd.buf);
+  (CSecurity::upg)->getUserPasswd(cc->isSecure(), 0, &passwd.buf);
 
   // Calculate the correct response
   rdr::U8 key[8];
diff --git a/common/rfb/UserPasswdGetter.h b/common/rfb/UserPasswdGetter.h
index 18b0bae..13493e4 100644
--- a/common/rfb/UserPasswdGetter.h
+++ b/common/rfb/UserPasswdGetter.h
@@ -24,7 +24,7 @@
     // dialog, getpass(), etc.  The user buffer pointer can be null, in which
     // case no user name will be retrieved.  The caller MUST delete [] the
     // result(s).
-    virtual void getUserPasswd(char** user, char** password)=0;
+    virtual void getUserPasswd(bool secure, char** user, char** password)=0;
   };
 }
 #endif
diff --git a/media/insecure.svg b/media/insecure.svg
new file mode 100644
index 0000000..1c5f6fa
--- /dev/null
+++ b/media/insecure.svg
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="16"
+   height="16"
+   viewBox="0 0 4.2333332 4.2333335"
+   version="1.1"
+   id="svg8"
+   inkscape:version="0.92+devel unknown"
+   sodipodi:docname="insecure.svg">
+  <defs
+     id="defs2" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="16"
+     inkscape:cx="4.5653262"
+     inkscape:cy="11.192284"
+     inkscape:document-units="mm"
+     inkscape:current-layer="layer1"
+     inkscape:document-rotation="0"
+     showgrid="true"
+     units="px"
+     inkscape:window-width="1920"
+     inkscape:window-height="1136"
+     inkscape:window-x="1920"
+     inkscape:window-y="27"
+     inkscape:window-maximized="1">
+    <inkscape:grid
+       type="xygrid"
+       id="grid10" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata5">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-292.76665)">
+    <rect
+       style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.13229166;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:0.26458333, 0.79374999"
+       id="rect878"
+       width="4.2333331"
+       height="4.2333331"
+       x="0"
+       y="292.76666" />
+    <rect
+       style="fill:#ff0000;stroke-width:0.13229166;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:0.26458333, 0.79375"
+       id="rect926"
+       width="4.2333331"
+       height="4.2333331"
+       x="-5.5511151e-17"
+       y="292.76666" />
+    <rect
+       style="fill:#000000;fill-opacity:1;stroke-width:0.10103943;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:0.20207887, 0.60623662"
+       id="rect12-3"
+       width="3.175"
+       height="1.8520833"
+       x="0.52916664"
+       y="294.61874"
+       ry="0.26457277" />
+    <path
+       inkscape:connector-curvature="0"
+       style="fill:#000000;stroke-width:0.13229166;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:0.26458333, 0.79374999"
+       d="m 2.1166667,293.29579 a 1.0583332,1.0583332 0 0 0 -1.0583334,1.05833 v 0.79375 h 0.3601848 a 1.0583332,1.0583332 0 0 0 0.6981486,0.26458 1.0583332,1.0583332 0 0 0 0.6981486,-0.26458 H 3.175 v -0.79375 a 1.0583332,1.0583332 0 0 0 -1.0583333,-1.05833 z m 0,0.52916 a 0.52916664,0.52916664 0 0 1 0.5291666,0.52917 v 0.79375 H 1.5875 v -0.79375 a 0.52916664,0.52916664 0 0 1 0.5291667,-0.52917 z"
+       id="path913" />
+    <rect
+       style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.30752403;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:0.61504807, 1.84514421"
+       id="rect871"
+       width="4.4979167"
+       height="0.52916664"
+       x="-209.4492"
+       y="209.48177"
+       transform="rotate(-45)" />
+    <rect
+       transform="rotate(-45)"
+       y="210.0107"
+       x="-209.26234"
+       height="0.52916664"
+       width="4.6772137"
+       id="rect875"
+       style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.30752403;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:0.61504807, 1.84514421"
+       ry="0" />
+  </g>
+</svg>
diff --git a/media/insecure.xpm b/media/insecure.xpm
new file mode 100644
index 0000000..f5053fe
--- /dev/null
+++ b/media/insecure.xpm
@@ -0,0 +1,71 @@
+/* XPM */
+static char *insecure[] = {
+/* columns rows colors chars-per-pixel */
+"15 15 50 1 ",
+"  c black",
+". c #020000",
+"X c #050000",
+"o c #080000",
+"O c #0A0000",
+"+ c #0C0000",
+"@ c #0D0000",
+"# c #0F0000",
+"$ c #100000",
+"% c #110000",
+"& c #120000",
+"* c #140000",
+"= c #290000",
+"- c #330000",
+"; c #370000",
+": c #430000",
+"> c #560000",
+", c #620000",
+"< c #660000",
+"1 c #6C0000",
+"2 c #7D0000",
+"3 c #800000",
+"4 c #810000",
+"5 c #840000",
+"6 c #870000",
+"7 c #950000",
+"8 c #A20000",
+"9 c #AB0000",
+"0 c #B30000",
+"q c #B40000",
+"w c #C00000",
+"e c #C40000",
+"r c #CD0000",
+"t c #DC0000",
+"y c #DD0000",
+"u c #DF0000",
+"i c #E40000",
+"p c #E50000",
+"a c #E60000",
+"s c #EA0000",
+"d c #EB0000",
+"f c #ED0000",
+"g c #F00000",
+"h c #F40000",
+"j c #F90000",
+"k c #FA0000",
+"l c #FB0000",
+"z c #FC0000",
+"x c #FD0000",
+"c c red",
+/* pixels */
+"ccccccccccccccc",
+"ccccccjpkcr:fcc",
+"ccccz6+ @1$ rcc",
+"cccc2 O-o  wccc",
+"cccdX%tr# 4cccc",
+"ccce >r& 7czccc",
+"ccq< =O 8cg60cc",
+"cs.    3cg;  ac",
+"cu    3cg;   uc",
+"cu   3cg;    uc",
+"c0  3cg;     uc",
+"r$ 3cg;      uc",
+", 5cg;      *hc",
+"l9lxiyyyyyyyhcc",
+"ccccccccccccccc"
+};
diff --git a/media/secure.svg b/media/secure.svg
new file mode 100644
index 0000000..4da1075
--- /dev/null
+++ b/media/secure.svg
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="16"
+   height="16"
+   viewBox="0 0 4.2333332 4.2333335"
+   version="1.1"
+   id="svg8"
+   inkscape:version="0.92+devel unknown"
+   sodipodi:docname="secure.svg">
+  <defs
+     id="defs2" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="32"
+     inkscape:cx="19.34416"
+     inkscape:cy="11.532874"
+     inkscape:document-units="mm"
+     inkscape:current-layer="layer1"
+     inkscape:document-rotation="0"
+     showgrid="true"
+     units="px"
+     inkscape:window-width="1920"
+     inkscape:window-height="1136"
+     inkscape:window-x="1920"
+     inkscape:window-y="27"
+     inkscape:window-maximized="1">
+    <inkscape:grid
+       type="xygrid"
+       id="grid10" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata5">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-292.76665)">
+    <rect
+       style="fill:#00ff00;stroke-width:0.13229166;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:0.26458333, 0.79374999000000002"
+       id="rect926"
+       width="4.2333331"
+       height="4.2333331"
+       x="0"
+       y="292.76666" />
+    <rect
+       style="fill:#000000;fill-opacity:1;stroke-width:0.10103943;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:0.20207887, 0.60623661"
+       id="rect12"
+       width="3.175"
+       height="1.8520833"
+       x="0.52916664"
+       y="294.61874"
+       ry="0.26457277" />
+    <path
+       style="fill:#000000;stroke-width:0.49999997;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:0.99999999, 2.99999996"
+       d="M 8 2 A 3.9999996 3.9999996 0 0 0 4 6 L 4 9 L 5.3613281 9 A 3.9999996 3.9999996 0 0 0 8 10 A 3.9999996 3.9999996 0 0 0 10.638672 9 L 12 9 L 12 6 A 3.9999996 3.9999996 0 0 0 8 2 z M 8 4 A 1.9999999 1.9999999 0 0 1 10 6 L 10 9 L 6 9 L 6 6 A 1.9999999 1.9999999 0 0 1 8 4 z "
+       transform="matrix(0.26458333,0,0,0.26458333,0,292.76665)"
+       id="path913" />
+  </g>
+</svg>
diff --git a/media/secure.xpm b/media/secure.xpm
new file mode 100644
index 0000000..49a3791
--- /dev/null
+++ b/media/secure.xpm
@@ -0,0 +1,56 @@
+/* XPM */
+static char *secure[] = {
+/* columns rows colors chars-per-pixel */
+"15 15 35 1 ",
+"  c black",
+". c #000200",
+"X c #000500",
+"o c #000A00",
+"O c #000C00",
+"+ c #000D00",
+"@ c #001000",
+"# c #001100",
+"$ c #001400",
+"% c #003300",
+"& c #005500",
+"* c #005600",
+"= c #006600",
+"- c #007D00",
+"; c #007E00",
+": c #008700",
+"> c #008800",
+", c #00B300",
+"< c #00B400",
+"1 c #00C400",
+"2 c #00DB00",
+"3 c #00DC00",
+"4 c #00DD00",
+"5 c #00DF00",
+"6 c #00E500",
+"7 c #00E600",
+"8 c #00EA00",
+"9 c #00EB00",
+"0 c #00ED00",
+"q c #00F000",
+"w c #00F400",
+"e c #00F900",
+"r c #00FA00",
+"t c #00FC00",
+"y c green",
+/* pixels */
+"yyyyyyyyyyyyyyy",
+"yyyyyye6ryyyyyy",
+"yyyyt:O +>tyyyy",
+"yyyy- o%o ;yyyy",
+"yyy9X#3y2@X0yyy",
+"yyy1 *yyy& 1yyy",
+"yy<= %>>>% =,yy",
+"y8.          7y",
+"y5           5y",
+"y5           5y",
+"y5           5y",
+"y5           5y",
+"yw#         $wy",
+"yyq444444444wyy",
+"yyyyyyyyyyyyyyy"
+};
diff --git a/vncviewer/UserDialog.cxx b/vncviewer/UserDialog.cxx
index cf6893c..640f2a9 100644
--- a/vncviewer/UserDialog.cxx
+++ b/vncviewer/UserDialog.cxx
@@ -32,6 +32,7 @@
 #include <FL/Fl_Secret_Input.H>
 #include <FL/Fl_Button.H>
 #include <FL/Fl_Return_Button.H>
+#include <FL/Fl_Pixmap.H>
 
 #include <rfb/util.h>
 #include <rfb/Password.h>
@@ -42,8 +43,18 @@
 #include "parameters.h"
 #include "UserDialog.h"
 
+/* xpm:s predate const, so they have invalid definitions */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wwrite-strings"
+#include "../media/secure.xpm"
+#include "../media/insecure.xpm"
+#pragma GCC diagnostic pop
+
 using namespace rfb;
 
+static Fl_Pixmap secure_icon(secure);
+static Fl_Pixmap insecure_icon(insecure);
+
 static int ret_val = 0;
 
 static void button_cb(Fl_Widget *widget, void *val) {
@@ -59,7 +70,7 @@
 {
 }
 
-void UserDialog::getUserPasswd(char** user, char** password)
+void UserDialog::getUserPasswd(bool secure, char** user, char** password)
 {
   CharArray passwordFileStr(passwordFile.getData());
 
@@ -83,6 +94,7 @@
   }
 
   Fl_Window *win;
+  Fl_Box *banner;
   Fl_Input *username;
   Fl_Secret_Input *passwd;
   Fl_Box *icon;
@@ -93,9 +105,22 @@
   win = new Fl_Window(410, 145, _("VNC authentication"));
   win->callback(button_cb,(void *)0);
 
-  y = 10;
+  banner = new Fl_Box(0, 0, win->w(), 20);
+  banner->align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE|FL_ALIGN_IMAGE_NEXT_TO_TEXT);
+  banner->box(FL_FLAT_BOX);
+  if (secure) {
+    banner->label(_("This connection is secure"));
+    banner->color(FL_GREEN);
+    banner->image(secure_icon);
+  } else {
+    banner->label(_("This connection is not secure"));
+    banner->color(FL_RED);
+    banner->image(insecure_icon);
+  }
 
-  icon = new Fl_Box(10, 10, 50, 50, "?");
+  y = 20 + 10;
+
+  icon = new Fl_Box(10, y, 50, 50, "?");
   icon->box(FL_UP_BOX);
   icon->labelfont(FL_TIMES_BOLD);
   icon->labelsize(34);
diff --git a/vncviewer/UserDialog.h b/vncviewer/UserDialog.h
index c6756a8..b62ba7f 100644
--- a/vncviewer/UserDialog.h
+++ b/vncviewer/UserDialog.h
@@ -31,7 +31,7 @@
 
   // UserPasswdGetter callbacks
 
-  void getUserPasswd(char** user, char** password);
+  void getUserPasswd(bool secure, char** user, char** password);
 
   // UserMsgBox callbacks