Merge branch 'readonlypassword' of https://github.com/michalsrb/tigervnc into viewonly
diff --git a/common/rfb/SConnection.cxx b/common/rfb/SConnection.cxx
index eeaeafe..20182a0 100644
--- a/common/rfb/SConnection.cxx
+++ b/common/rfb/SConnection.cxx
@@ -28,6 +28,7 @@
#include <rfb/ServerCore.h>
#include <rfb/encodings.h>
#include <rfb/EncodeManager.h>
+#include <rfb/SSecurity.h>
#include <rfb/LogWriter.h>
@@ -36,13 +37,14 @@
static LogWriter vlog("SConnection");
// AccessRights values
-const SConnection::AccessRights SConnection::AccessView = 0x0001;
-const SConnection::AccessRights SConnection::AccessKeyEvents = 0x0002;
-const SConnection::AccessRights SConnection::AccessPtrEvents = 0x0004;
-const SConnection::AccessRights SConnection::AccessCutText = 0x0008;
-const SConnection::AccessRights SConnection::AccessDefault = 0x03ff;
-const SConnection::AccessRights SConnection::AccessNoQuery = 0x0400;
-const SConnection::AccessRights SConnection::AccessFull = 0xffff;
+const SConnection::AccessRights SConnection::AccessView = 0x0001;
+const SConnection::AccessRights SConnection::AccessKeyEvents = 0x0002;
+const SConnection::AccessRights SConnection::AccessPtrEvents = 0x0004;
+const SConnection::AccessRights SConnection::AccessCutText = 0x0008;
+const SConnection::AccessRights SConnection::AccessSetDesktopSize = 0x0010;
+const SConnection::AccessRights SConnection::AccessDefault = 0x03ff;
+const SConnection::AccessRights SConnection::AccessNoQuery = 0x0400;
+const SConnection::AccessRights SConnection::AccessFull = 0xffff;
SConnection::SConnection(bool reverseConnection_)
@@ -223,6 +225,7 @@
if (done) {
state_ = RFBSTATE_QUERYING;
queryConnection(ssecurity->getUserName());
+ setAccessRights(ssecurity->getAccessRights());
}
} catch (AuthFailureException& e) {
vlog.error("AuthFailureException: %s", e.str());
diff --git a/common/rfb/SConnection.h b/common/rfb/SConnection.h
index 7718f4c..0379b17 100644
--- a/common/rfb/SConnection.h
+++ b/common/rfb/SConnection.h
@@ -28,7 +28,6 @@
#include <rdr/OutStream.h>
#include <rfb/SMsgHandler.h>
#include <rfb/SecurityServer.h>
-#include <rfb/SSecurity.h>
namespace rfb {
@@ -123,13 +122,14 @@
// is up to the derived class.
typedef rdr::U16 AccessRights;
- static const AccessRights AccessView; // View display contents
- static const AccessRights AccessKeyEvents; // Send key events
- static const AccessRights AccessPtrEvents; // Send pointer events
- static const AccessRights AccessCutText; // Send/receive clipboard events
- static const AccessRights AccessDefault; // The default rights, INCLUDING FUTURE ONES
- static const AccessRights AccessNoQuery; // Connect without local user accepting
- static const AccessRights AccessFull; // All of the available AND FUTURE rights
+ static const AccessRights AccessView; // View display contents
+ static const AccessRights AccessKeyEvents; // Send key events
+ static const AccessRights AccessPtrEvents; // Send pointer events
+ static const AccessRights AccessCutText; // Send/receive clipboard events
+ static const AccessRights AccessSetDesktopSize; // Change desktop size
+ static const AccessRights AccessDefault; // The default rights, INCLUDING FUTURE ONES
+ static const AccessRights AccessNoQuery; // Connect without local user accepting
+ static const AccessRights AccessFull; // All of the available AND FUTURE rights
virtual void setAccessRights(AccessRights ar) = 0;
// Other methods
diff --git a/common/rfb/SSecurity.h b/common/rfb/SSecurity.h
index afc744e..6da63c3 100644
--- a/common/rfb/SSecurity.h
+++ b/common/rfb/SSecurity.h
@@ -44,13 +44,12 @@
#define __RFB_SSECURITY_H__
#include <rdr/types.h>
+#include <rfb/SConnection.h>
#include <rfb/util.h>
#include <list>
namespace rfb {
- class SConnection;
-
class SSecurity {
public:
virtual ~SSecurity() {}
@@ -63,6 +62,8 @@
// necessary. Null may be returned to indicate that there is no user name
// for this security type.
virtual const char* getUserName() const = 0;
+
+ virtual SConnection::AccessRights getAccessRights() const { return SConnection::AccessDefault; }
};
}
diff --git a/common/rfb/SSecurityVncAuth.cxx b/common/rfb/SSecurityVncAuth.cxx
index ca81bf3..05488f6 100644
--- a/common/rfb/SSecurityVncAuth.cxx
+++ b/common/rfb/SSecurityVncAuth.cxx
@@ -49,10 +49,27 @@
"access the server", &SSecurityVncAuth::vncAuthPasswdFile);
SSecurityVncAuth::SSecurityVncAuth(void)
- : sentChallenge(false), responsePos(0), pg(&vncAuthPasswd)
+ : sentChallenge(false), responsePos(0), pg(&vncAuthPasswd), accessRights(0)
{
}
+bool SSecurityVncAuth::verifyResponse(const PlainPasswd &password)
+{
+ rdr::U8 expectedResponse[vncAuthChallengeSize];
+
+ // Calculate the expected response
+ rdr::U8 key[8];
+ int pwdLen = strlen(password.buf);
+ for (int i=0; i<8; i++)
+ key[i] = i<pwdLen ? password.buf[i] : 0;
+ deskey(key, EN0);
+ for (int j = 0; j < vncAuthChallengeSize; j += 8)
+ des(challenge+j, expectedResponse+j);
+
+ // Check the actual response
+ return memcmp(response, expectedResponse, vncAuthChallengeSize) == 0;
+}
+
bool SSecurityVncAuth::processMsg(SConnection* sc)
{
rdr::InStream* is = sc->getInStream();
@@ -72,25 +89,23 @@
if (responsePos < vncAuthChallengeSize) return false;
- PlainPasswd passwd(pg->getVncAuthPasswd());
+ PlainPasswd passwd, passwdReadOnly;
+ pg->getVncAuthPasswd(&passwd, &passwdReadOnly);
if (!passwd.buf)
throw AuthFailureException("No password configured for VNC Auth");
- // Calculate the expected response
- rdr::U8 key[8];
- int pwdLen = strlen(passwd.buf);
- for (int i=0; i<8; i++)
- key[i] = i<pwdLen ? passwd.buf[i] : 0;
- deskey(key, EN0);
- for (int j = 0; j < vncAuthChallengeSize; j += 8)
- des(challenge+j, challenge+j);
+ if (verifyResponse(passwd)) {
+ accessRights = SConnection::AccessDefault;
+ return true;
+ }
- // Check the actual response
- if (memcmp(challenge, response, vncAuthChallengeSize) != 0)
- throw AuthFailureException();
+ if (passwdReadOnly.buf && verifyResponse(passwdReadOnly)) {
+ accessRights = SConnection::AccessView;
+ return true;
+ }
- return true;
+ throw AuthFailureException();
}
VncAuthPasswdParameter::VncAuthPasswdParameter(const char* name,
@@ -99,8 +114,8 @@
: BinaryParameter(name, desc, 0, 0, ConfServer), passwdFile(passwdFile_) {
}
-char* VncAuthPasswdParameter::getVncAuthPasswd() {
- ObfuscatedPasswd obfuscated;
+void VncAuthPasswdParameter::getVncAuthPasswd(PlainPasswd *password, PlainPasswd *readOnlyPassword) {
+ ObfuscatedPasswd obfuscated, obfuscatedReadOnly;
getData((void**)&obfuscated.buf, &obfuscated.length);
if (obfuscated.length == 0) {
@@ -108,18 +123,20 @@
CharArray fname(passwdFile->getData());
if (!fname.buf[0]) {
vlog.info("neither %s nor %s params set", getName(), passwdFile->getName());
- return 0;
+ return;
}
FILE* fp = fopen(fname.buf, "r");
if (!fp) {
vlog.error("opening password file '%s' failed",fname.buf);
- return 0;
+ return;
}
vlog.debug("reading password file");
- obfuscated.buf = new char[128];
- obfuscated.length = fread(obfuscated.buf, 1, 128, fp);
+ obfuscated.buf = new char[8];
+ obfuscated.length = fread(obfuscated.buf, 1, 8, fp);
+ obfuscatedReadOnly.buf = new char[8];
+ obfuscatedReadOnly.length = fread(obfuscatedReadOnly.buf, 1, 8, fp);
fclose(fp);
} else {
vlog.info("%s parameter not set", getName());
@@ -127,10 +144,11 @@
}
try {
- PlainPasswd password(obfuscated);
- return password.takeBuf();
+ PlainPasswd plainPassword(obfuscated);
+ password->replaceBuf(plainPassword.takeBuf());
+ PlainPasswd plainPasswordReadOnly(obfuscatedReadOnly);
+ readOnlyPassword->replaceBuf(plainPasswordReadOnly.takeBuf());
} catch (...) {
- return 0;
}
}
diff --git a/common/rfb/SSecurityVncAuth.h b/common/rfb/SSecurityVncAuth.h
index 8a2d0f6..e9f379b 100644
--- a/common/rfb/SSecurityVncAuth.h
+++ b/common/rfb/SSecurityVncAuth.h
@@ -25,6 +25,7 @@
#define __RFB_SSECURITYVNCAUTH_H__
#include <rfb/Configuration.h>
+#include <rfb/Password.h>
#include <rfb/SSecurity.h>
#include <rfb/Security.h>
#include <rdr/types.h>
@@ -33,15 +34,15 @@
class VncAuthPasswdGetter {
public:
- // getPasswd() returns a string or null if unsuccessful. The
- // SSecurityVncAuth object delete[]s the string when done.
- virtual char* getVncAuthPasswd()=0;
+ // getVncAuthPasswd() fills buffer of given password and readOnlyPassword.
+ // If there was no read only password in the file, readOnlyPassword buffer is null.
+ virtual void getVncAuthPasswd(PlainPasswd *password, PlainPasswd *readOnlyPassword)=0;
};
class VncAuthPasswdParameter : public VncAuthPasswdGetter, BinaryParameter {
public:
VncAuthPasswdParameter(const char* name, const char* desc, StringParameter* passwdFile_);
- virtual char* getVncAuthPasswd();
+ virtual void getVncAuthPasswd(PlainPasswd *password, PlainPasswd *readOnlyPassword);
protected:
StringParameter* passwdFile;
};
@@ -52,15 +53,18 @@
virtual bool processMsg(SConnection* sc);
virtual int getType() const {return secTypeVncAuth;}
virtual const char* getUserName() const {return 0;}
+ virtual SConnection::AccessRights getAccessRights() const { return accessRights; }
static StringParameter vncAuthPasswdFile;
static VncAuthPasswdParameter vncAuthPasswd;
private:
+ bool verifyResponse(const PlainPasswd &password);
enum {vncAuthChallengeSize = 16};
rdr::U8 challenge[vncAuthChallengeSize];
rdr::U8 response[vncAuthChallengeSize];
bool sentChallenge;
int responsePos;
VncAuthPasswdGetter* pg;
+ SConnection::AccessRights accessRights;
};
}
#endif
diff --git a/common/rfb/Security.h b/common/rfb/Security.h
index 196eb42..85bc325 100644
--- a/common/rfb/Security.h
+++ b/common/rfb/Security.h
@@ -25,7 +25,6 @@
#include <rdr/types.h>
#include <rfb/Configuration.h>
#include <rfb/CSecurity.h>
-#include <rfb/SSecurity.h>
#include <list>
diff --git a/common/rfb/SecurityServer.h b/common/rfb/SecurityServer.h
index 0986619..019d67f 100644
--- a/common/rfb/SecurityServer.h
+++ b/common/rfb/SecurityServer.h
@@ -22,9 +22,10 @@
#include <rfb/Configuration.h>
#include <rfb/Security.h>
-#include <rfb/SSecurity.h>
namespace rfb {
+
+ class SSecurity;
class SecurityServer : public Security {
public:
diff --git a/common/rfb/ServerCore.cxx b/common/rfb/ServerCore.cxx
index ae2fd24..b11a352 100644
--- a/common/rfb/ServerCore.cxx
+++ b/common/rfb/ServerCore.cxx
@@ -89,6 +89,10 @@
("SendCutText",
"Send clipboard changes to clients.",
true);
+rfb::BoolParameter rfb::Server::acceptSetDesktopSize
+("AcceptSetDesktopSize",
+ "Accept set desktop size events from clients.",
+ true);
rfb::BoolParameter rfb::Server::queryConnect
("QueryConnect",
"Prompt the local user to accept or reject incoming connections.",
diff --git a/common/rfb/ServerCore.h b/common/rfb/ServerCore.h
index e12a8bc..5fc996f 100644
--- a/common/rfb/ServerCore.h
+++ b/common/rfb/ServerCore.h
@@ -46,6 +46,7 @@
static BoolParameter acceptPointerEvents;
static BoolParameter acceptCutText;
static BoolParameter sendCutText;
+ static BoolParameter acceptSetDesktopSize;
static BoolParameter queryConnect;
};
diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx
index 618048a..274c496 100644
--- a/common/rfb/VNCSConnectionST.cxx
+++ b/common/rfb/VNCSConnectionST.cxx
@@ -584,6 +584,9 @@
{
unsigned int result;
+ if (!(accessRights & AccessSetDesktopSize)) return;
+ if (!rfb::Server::acceptSetDesktopSize) return;
+
// Don't bother the desktop with an invalid configuration
if (!layout.validate(fb_width, fb_height)) {
writer()->writeExtendedDesktopSize(reasonClient, resultInvalid,
diff --git a/unix/vncpasswd/vncpasswd.cxx b/unix/vncpasswd/vncpasswd.cxx
index 7ba0b22..16c925e 100644
--- a/unix/vncpasswd/vncpasswd.cxx
+++ b/unix/vncpasswd/vncpasswd.cxx
@@ -81,6 +81,36 @@
else return 1;
}
+static ObfuscatedPasswd* readpassword() {
+ while (true) {
+ PlainPasswd passwd(getpassword("Password:"));
+ if (!passwd.buf) {
+ perror("getpassword error");
+ exit(1);
+ }
+ if (strlen(passwd.buf) < 6) {
+ if (strlen(passwd.buf) == 0) {
+ fprintf(stderr,"Password not changed\n");
+ exit(1);
+ }
+ fprintf(stderr,"Password must be at least 6 characters - try again\n");
+ continue;
+ }
+
+ PlainPasswd passwd2(getpassword("Verify:"));
+ if (!passwd2.buf) {
+ perror("getpass error");
+ exit(1);
+ }
+ if (strcmp(passwd.buf, passwd2.buf) != 0) {
+ fprintf(stderr,"Passwords don't match - try again\n");
+ continue;
+ }
+
+ return new ObfuscatedPasswd(passwd);
+ }
+}
+
int main(int argc, char** argv)
{
prog = argv[0];
@@ -113,28 +143,13 @@
}
while (true) {
- PlainPasswd passwd(getpassword("Password:"));
- if (!passwd.buf) {
- perror("getpassword error");
- exit(1);
- }
- if (strlen(passwd.buf) < 6) {
- if (strlen(passwd.buf) == 0) {
- fprintf(stderr,"Password not changed\n");
- exit(1);
- }
- fprintf(stderr,"Password must be at least 6 characters - try again\n");
- continue;
- }
+ ObfuscatedPasswd* obfuscated = readpassword();
+ ObfuscatedPasswd* obfuscatedReadOnly = 0;
- PlainPasswd passwd2(getpassword("Verify:"));
- if (!passwd2.buf) {
- perror("getpass error");
- exit(1);
- }
- if (strcmp(passwd.buf, passwd2.buf) != 0) {
- fprintf(stderr,"Passwords don't match - try again\n");
- continue;
+ fprintf(stderr, "Would you like to enter a view-only password (y/n)? ");
+ char yesno[3];
+ if (fgets(yesno, 3, stdin) != NULL && (yesno[0] == 'y' || yesno[0] == 'Y')) {
+ obfuscatedReadOnly = readpassword();
}
FILE* fp = fopen(fname,"w");
@@ -144,13 +159,18 @@
}
chmod(fname, S_IRUSR|S_IWUSR);
- ObfuscatedPasswd obfuscated(passwd);
-
- if (fwrite(obfuscated.buf, obfuscated.length, 1, fp) != 1) {
+ if (fwrite(obfuscated->buf, obfuscated->length, 1, fp) != 1) {
fprintf(stderr,"Writing to %s failed\n",fname);
exit(1);
}
+ if (obfuscatedReadOnly) {
+ if (fwrite(obfuscatedReadOnly->buf, obfuscatedReadOnly->length, 1, fp) != 1) {
+ fprintf(stderr,"Writing to %s failed\n",fname);
+ exit(1);
+ }
+ }
+
fclose(fp);
return 0;