[Development] Implement *Plain security types on the server side and use
PAM for credential validation on UNIX.


git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4128 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/common/rfb/Makefile.am b/common/rfb/Makefile.am
index 4e5bbd7..9251e2f 100644
--- a/common/rfb/Makefile.am
+++ b/common/rfb/Makefile.am
@@ -55,6 +55,11 @@
 librfb_la_CPPFLAGS = -I$(top_srcdir)/common -I$(top_srcdir)/win
 librfb_la_LIBADD = @GNUTLS_LIBS@
 
+if HAVE_PAM
+librfb_la_SOURCES += UnixPasswordValidator.cxx UnixPasswordValidator.h pam.c pam.h
+librfb_la_LIBADD += $(PAM_LIBS)
+endif
+
 if INCLUDED_JPEG
 librfb_la_CPPFLAGS += -I$(top_srcdir)/common/jpeg -I$(top_builddir)/common/jpeg
 librfb_la_LIBADD += $(top_builddir)/common/jpeg/libjpeg.la
diff --git a/common/rfb/SSecurityPlain.cxx b/common/rfb/SSecurityPlain.cxx
index 6d0c67e..84ef099 100644
--- a/common/rfb/SSecurityPlain.cxx
+++ b/common/rfb/SSecurityPlain.cxx
@@ -25,6 +25,9 @@
 #include <rfb/SConnection.h>
 #include <rfb/Exception.h>
 #include <rdr/InStream.h>
+#ifdef HAVE_PAM
+#include <rfb/UnixPasswordValidator.h>
+#endif
 
 using namespace rfb;
 
@@ -36,27 +39,33 @@
 bool PasswordValidator::validUser(const char* username)
 {
   CharArray users(strDup(plainUsers.getValueStr())), user;
+
   while (users.buf) {
     strSplit(users.buf, ',', &user.buf, &users.buf);
 #ifdef WIN32
-    if(0==stricmp(user.buf, "*"))
+    if (0 == stricmp(user.buf, "*"))
 	  return true;
-    if(0==stricmp(user.buf, username))
+    if (0 == stricmp(user.buf, username))
 	  return true;
 #else
-    if(!strcmp (user.buf, "*"))
+    if (!strcmp(user.buf, "*"))
 	  return true;
-    if(!strcmp (user.buf, username))
+    if (!strcmp(user.buf, username))
 	  return true;
 #endif
   }
   return false;
 }
 
-SSecurityPlain::SSecurityPlain(PasswordValidator* _valid)
+SSecurityPlain::SSecurityPlain()
 {
-  valid=_valid;
-  state=0;
+#ifdef HAVE_PAM
+  valid = new UnixPasswordValidator();
+#else
+  valid = NULL;
+#endif
+
+  state = 0;
 }
 
 bool SSecurityPlain::processMsg(SConnection* sc)
@@ -66,32 +75,34 @@
   char *uname;
   CharArray password;
 
-  if(state==0)
-  {
-    if(!is->checkNoWait(8))
+  if (!valid)
+    throw AuthFailureException("No password validator configured");
+
+  if (state == 0) {
+    if (!is->checkNoWait(8))
       return false;
-    ulen=is->readU32();
-    plen=is->readU32();
-    state=1;
+    ulen = is->readU32();
+    plen = is->readU32();
+    state = 1;
   }
-  if(state==1)
-  {
-    if(is->checkNoWait(ulen+plen+2))
+
+  if (state == 1) {
+    if (is->checkNoWait(ulen + plen + 2))
       return false;
-    state=2;
-    pw=new char[plen+1];
-    uname=new char[ulen+1];
+    state = 2;
+    pw = new char[plen + 1];
+    uname = new char[ulen + 1];
     username.replaceBuf(uname);
     password.replaceBuf(pw);
-    is->readBytes(uname,ulen);
-    is->readBytes(pw,plen);
-    pw[plen]=0;
-    uname[ulen]=0;
-    plen=0;
-    if(!valid->validate(sc,uname,pw))
-	  throw AuthFailureException("invalid password or username");
-    return true;
+    is->readBytes(uname, ulen);
+    is->readBytes(pw, plen);
+    pw[plen] = 0;
+    uname[ulen] = 0;
+    plen = 0;
+    if (!valid->validate(sc, uname, pw))
+      throw AuthFailureException("invalid password or username");
   }
+
   return true;
 }
 
diff --git a/common/rfb/SSecurityPlain.h b/common/rfb/SSecurityPlain.h
index f170bd5..080fcd5 100644
--- a/common/rfb/SSecurityPlain.h
+++ b/common/rfb/SSecurityPlain.h
@@ -34,24 +34,25 @@
 
   class PasswordValidator {
   public:
-    // validate username / password combination
-	bool validate(SConnection* sc, const char *username, const char *password) { return validUser(username) ? validateInternal(sc, username, password) : false; };
-	static StringParameter plainUsers;
+    bool validate(SConnection* sc, const char *username, const char *password)
+      { return validUser(username) ? validateInternal(sc, username, password) : false; }
+    static StringParameter plainUsers;
+
   protected:
     virtual bool validateInternal(SConnection* sc, const char *username, const char *password)=0;
-	static bool validUser(const char* username);
+    static bool validUser(const char* username);
   };
 
   class SSecurityPlain : public SSecurity {
   public:
-    SSecurityPlain(PasswordValidator* valid);
+    SSecurityPlain();
     virtual bool processMsg(SConnection* sc);
-    virtual int getType() const {return secTypePlain;};
+    virtual int getType() const { return secTypePlain; };
     virtual const char* getUserName() const { return username.buf; }
 
   private:
     PasswordValidator* valid;
-    unsigned int ulen,plen,state;
+    unsigned int ulen, plen, state;
     CharArray username;
   };
 
diff --git a/common/rfb/Security.cxx b/common/rfb/Security.cxx
index 874c346..2ea51fa 100644
--- a/common/rfb/Security.cxx
+++ b/common/rfb/Security.cxx
@@ -37,6 +37,7 @@
 #include <rfb/Security.h>
 #include <rfb/SSecurityNone.h>
 #include <rfb/SSecurityStack.h>
+#include <rfb/SSecurityPlain.h>
 #include <rfb/SSecurityVncAuth.h>
 #include <rfb/SSecurityVeNCrypt.h>
 #ifdef HAVE_GNUTLS
@@ -146,15 +147,20 @@
   case secTypeNone: return new SSecurityNone();
   case secTypeVncAuth: return new SSecurityVncAuth();
   case secTypeVeNCrypt: return new SSecurityVeNCrypt(this);
+  case secTypePlain: return new SSecurityPlain();
 #ifdef HAVE_GNUTLS
   case secTypeTLSNone:
     return new SSecurityStack(secTypeTLSNone, new SSecurityTLS(true));
   case secTypeTLSVnc:
     return new SSecurityStack(secTypeTLSVnc, new SSecurityTLS(true), new SSecurityVncAuth());
+  case secTypeTLSPlain:
+    return new SSecurityStack(secTypeTLSPlain, new SSecurityTLS(true), new SSecurityPlain());
   case secTypeX509None:
     return new SSecurityStack(secTypeX509None, new SSecurityTLS(false));
   case secTypeX509Vnc:
     return new SSecurityStack(secTypeX509None, new SSecurityTLS(false), new SSecurityVncAuth());
+  case secTypeX509Plain:
+    return new SSecurityStack(secTypeX509Plain, new SSecurityTLS(false), new SSecurityPlain());
 #endif
   }