mirror of
https://github.com/kasmtech/KasmVNC.git
synced 2025-02-16 18:31:50 +01:00
Resolve KASM-2238 "Feature/ freeze session"
This commit is contained in:
parent
13331295ac
commit
42d7ff015d
@ -53,18 +53,21 @@ namespace network {
|
|||||||
uint8_t *netGetScreenshot(uint16_t w, uint16_t h,
|
uint8_t *netGetScreenshot(uint16_t w, uint16_t h,
|
||||||
const uint8_t q, const bool dedup,
|
const uint8_t q, const bool dedup,
|
||||||
uint32_t &len, uint8_t *staging);
|
uint32_t &len, uint8_t *staging);
|
||||||
uint8_t netAddUser(const char name[], const char pw[], const bool write, const bool owner);
|
uint8_t netAddUser(const char name[], const char pw[],
|
||||||
|
const bool read, const bool write, const bool owner);
|
||||||
uint8_t netRemoveUser(const char name[]);
|
uint8_t netRemoveUser(const char name[]);
|
||||||
uint8_t netUpdateUser(const char name[], const uint64_t mask,
|
uint8_t netUpdateUser(const char name[], const uint64_t mask,
|
||||||
const char password[],
|
const char password[],
|
||||||
const bool write, const bool owner);
|
const bool read, const bool write, const bool owner);
|
||||||
uint8_t netAddOrUpdateUser(const struct kasmpasswd_entry_t *entry);
|
uint8_t netAddOrUpdateUser(const struct kasmpasswd_entry_t *entry);
|
||||||
void netGetUsers(const char **ptr);
|
void netGetUsers(const char **ptr);
|
||||||
void netGetBottleneckStats(char *buf, uint32_t len);
|
void netGetBottleneckStats(char *buf, uint32_t len);
|
||||||
void netGetFrameStats(char *buf, uint32_t len);
|
void netGetFrameStats(char *buf, uint32_t len);
|
||||||
|
void netResetFrameStatsCall();
|
||||||
uint8_t netServerFrameStatsReady();
|
uint8_t netServerFrameStatsReady();
|
||||||
|
|
||||||
enum USER_ACTION {
|
enum USER_ACTION {
|
||||||
|
NONE,
|
||||||
WANT_FRAME_STATS_SERVERONLY,
|
WANT_FRAME_STATS_SERVERONLY,
|
||||||
WANT_FRAME_STATS_ALL,
|
WANT_FRAME_STATS_ALL,
|
||||||
WANT_FRAME_STATS_OWNER,
|
WANT_FRAME_STATS_OWNER,
|
||||||
|
@ -24,6 +24,7 @@ enum USER_UPDATE_MASK {
|
|||||||
USER_UPDATE_WRITE_MASK = 1 << 0,
|
USER_UPDATE_WRITE_MASK = 1 << 0,
|
||||||
USER_UPDATE_OWNER_MASK = 1 << 1,
|
USER_UPDATE_OWNER_MASK = 1 << 1,
|
||||||
USER_UPDATE_PASSWORD_MASK = 1 << 2,
|
USER_UPDATE_PASSWORD_MASK = 1 << 2,
|
||||||
|
USER_UPDATE_READ_MASK = 1 << 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -264,7 +264,8 @@ uint8_t *GetAPIMessager::netGetScreenshot(uint16_t w, uint16_t h,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t GetAPIMessager::netAddUser(const char name[], const char pw[], const bool write,
|
uint8_t GetAPIMessager::netAddUser(const char name[], const char pw[],
|
||||||
|
const bool read, const bool write,
|
||||||
const bool owner) {
|
const bool owner) {
|
||||||
if (strlen(name) >= USERNAME_LEN) {
|
if (strlen(name) >= USERNAME_LEN) {
|
||||||
vlog.error("Username too long");
|
vlog.error("Username too long");
|
||||||
@ -289,6 +290,7 @@ uint8_t GetAPIMessager::netAddUser(const char name[], const char pw[], const boo
|
|||||||
act.data.password[PASSWORD_LEN - 1] = '\0';
|
act.data.password[PASSWORD_LEN - 1] = '\0';
|
||||||
act.data.owner = owner;
|
act.data.owner = owner;
|
||||||
act.data.write = write;
|
act.data.write = write;
|
||||||
|
act.data.read = read;
|
||||||
|
|
||||||
if (pthread_mutex_lock(&userMutex))
|
if (pthread_mutex_lock(&userMutex))
|
||||||
return 0;
|
return 0;
|
||||||
@ -367,7 +369,7 @@ uint8_t GetAPIMessager::netRemoveUser(const char name[]) {
|
|||||||
|
|
||||||
uint8_t GetAPIMessager::netUpdateUser(const char name[], const uint64_t mask,
|
uint8_t GetAPIMessager::netUpdateUser(const char name[], const uint64_t mask,
|
||||||
const char password[],
|
const char password[],
|
||||||
const bool write, const bool owner) {
|
const bool read, const bool write, const bool owner) {
|
||||||
if (strlen(name) >= USERNAME_LEN) {
|
if (strlen(name) >= USERNAME_LEN) {
|
||||||
vlog.error("Username too long");
|
vlog.error("Username too long");
|
||||||
return 0;
|
return 0;
|
||||||
@ -391,6 +393,8 @@ uint8_t GetAPIMessager::netUpdateUser(const char name[], const uint64_t mask,
|
|||||||
unsigned s;
|
unsigned s;
|
||||||
for (s = 0; s < set->num; s++) {
|
for (s = 0; s < set->num; s++) {
|
||||||
if (!strcmp(set->entries[s].user, name)) {
|
if (!strcmp(set->entries[s].user, name)) {
|
||||||
|
if (mask & USER_UPDATE_READ_MASK)
|
||||||
|
set->entries[s].read = read;
|
||||||
if (mask & USER_UPDATE_WRITE_MASK)
|
if (mask & USER_UPDATE_WRITE_MASK)
|
||||||
set->entries[s].write = write;
|
set->entries[s].write = write;
|
||||||
if (mask & USER_UPDATE_OWNER_MASK)
|
if (mask & USER_UPDATE_OWNER_MASK)
|
||||||
@ -487,8 +491,9 @@ void GetAPIMessager::netGetUsers(const char **outptr) {
|
|||||||
for (s = 0; s < set->num; s++) {
|
for (s = 0; s < set->num; s++) {
|
||||||
JSON_escape(set->entries[s].user, escapeduser);
|
JSON_escape(set->entries[s].user, escapeduser);
|
||||||
|
|
||||||
fprintf(f, " { \"user\": \"%s\", \"write\": %s, \"owner\": %s }",
|
fprintf(f, " { \"user\": \"%s\", \"read\": %s, \"write\": %s, \"owner\": %s }",
|
||||||
escapeduser,
|
escapeduser,
|
||||||
|
set->entries[s].read ? "true" : "false",
|
||||||
set->entries[s].write ? "true" : "false",
|
set->entries[s].write ? "true" : "false",
|
||||||
set->entries[s].owner ? "true" : "false");
|
set->entries[s].owner ? "true" : "false");
|
||||||
|
|
||||||
@ -687,6 +692,15 @@ out:
|
|||||||
pthread_mutex_unlock(&frameStatMutex);
|
pthread_mutex_unlock(&frameStatMutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GetAPIMessager::netResetFrameStatsCall() {
|
||||||
|
if (pthread_mutex_lock(&frameStatMutex))
|
||||||
|
return;
|
||||||
|
|
||||||
|
serverFrameStats.inprogress = 0;
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&frameStatMutex);
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t GetAPIMessager::netRequestFrameStats(USER_ACTION what, const char *client) {
|
uint8_t GetAPIMessager::netRequestFrameStats(USER_ACTION what, const char *client) {
|
||||||
// Return 1 for success
|
// Return 1 for success
|
||||||
action_data act;
|
action_data act;
|
||||||
|
@ -443,10 +443,10 @@ static uint8_t *screenshotCb(void *messager, uint16_t w, uint16_t h, const uint8
|
|||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t adduserCb(void *messager, const char name[], const char pw[],
|
static uint8_t adduserCb(void *messager, const char name[], const char pw[],
|
||||||
const uint8_t write, const uint8_t owner)
|
const uint8_t read, const uint8_t write, const uint8_t owner)
|
||||||
{
|
{
|
||||||
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
||||||
return msgr->netAddUser(name, pw, write, owner);
|
return msgr->netAddUser(name, pw, read, write, owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t removeCb(void *messager, const char name[])
|
static uint8_t removeCb(void *messager, const char name[])
|
||||||
@ -457,10 +457,10 @@ static uint8_t removeCb(void *messager, const char name[])
|
|||||||
|
|
||||||
static uint8_t updateUserCb(void *messager, const char name[], const uint64_t mask,
|
static uint8_t updateUserCb(void *messager, const char name[], const uint64_t mask,
|
||||||
const char password[],
|
const char password[],
|
||||||
const uint8_t write, const uint8_t owner)
|
const uint8_t read, const uint8_t write, const uint8_t owner)
|
||||||
{
|
{
|
||||||
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
||||||
return msgr->netUpdateUser(name, mask, password, write, owner);
|
return msgr->netUpdateUser(name, mask, password, read, write, owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t addOrUpdateUserCb(void *messager, const struct kasmpasswd_entry_t *entry)
|
static uint8_t addOrUpdateUserCb(void *messager, const struct kasmpasswd_entry_t *entry)
|
||||||
@ -487,6 +487,12 @@ static void frameStatsCb(void *messager, char *buf, uint32_t len)
|
|||||||
msgr->netGetFrameStats(buf, len);
|
msgr->netGetFrameStats(buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void resetFrameStatsCb(void *messager)
|
||||||
|
{
|
||||||
|
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
||||||
|
msgr->netResetFrameStatsCall();
|
||||||
|
}
|
||||||
|
|
||||||
static uint8_t requestFrameStatsNoneCb(void *messager)
|
static uint8_t requestFrameStatsNoneCb(void *messager)
|
||||||
{
|
{
|
||||||
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
||||||
@ -632,6 +638,7 @@ WebsocketListener::WebsocketListener(const struct sockaddr *listenaddr,
|
|||||||
settings.getUsersCb = getUsersCb;
|
settings.getUsersCb = getUsersCb;
|
||||||
settings.bottleneckStatsCb = bottleneckStatsCb;
|
settings.bottleneckStatsCb = bottleneckStatsCb;
|
||||||
settings.frameStatsCb = frameStatsCb;
|
settings.frameStatsCb = frameStatsCb;
|
||||||
|
settings.resetFrameStatsCb = resetFrameStatsCb;
|
||||||
|
|
||||||
settings.requestFrameStatsNoneCb = requestFrameStatsNoneCb;
|
settings.requestFrameStatsNoneCb = requestFrameStatsNoneCb;
|
||||||
settings.requestFrameStatsOwnerCb = requestFrameStatsOwnerCb;
|
settings.requestFrameStatsOwnerCb = requestFrameStatsOwnerCb;
|
||||||
|
@ -150,14 +150,13 @@ struct kasmpasswd_t *parseJsonUsers(const char *data) {
|
|||||||
|
|
||||||
if (e->type & cJSON_True)
|
if (e->type & cJSON_True)
|
||||||
entry->owner = 1;
|
entry->owner = 1;
|
||||||
/* } else field("read") {
|
} else field("read") {
|
||||||
start = end + 3;
|
|
||||||
if (!(e->type & (cJSON_False | cJSON_True)))
|
if (!(e->type & (cJSON_False | cJSON_True)))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (e->type & cJSON_True)
|
if (e->type & cJSON_True)
|
||||||
entry->read = 1;
|
entry->read = 1;
|
||||||
*/
|
|
||||||
} else {
|
} else {
|
||||||
//printf("Unknown field '%.*s'\n", len, start);
|
//printf("Unknown field '%.*s'\n", len, start);
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -216,10 +216,10 @@ ws_ctx_t *ws_socket(ws_ctx_t *ctx, int socket) {
|
|||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
ws_ctx_t *ws_socket_ssl(ws_ctx_t *ctx, int socket, char * certfile, char * keyfile) {
|
ws_ctx_t *ws_socket_ssl(ws_ctx_t *ctx, int socket, const char * certfile, const char * keyfile) {
|
||||||
int ret;
|
int ret;
|
||||||
char msg[1024];
|
char msg[1024];
|
||||||
char * use_keyfile;
|
const char * use_keyfile;
|
||||||
ws_socket(ctx, socket);
|
ws_socket(ctx, socket);
|
||||||
|
|
||||||
if (keyfile && (keyfile[0] != '\0')) {
|
if (keyfile && (keyfile[0] != '\0')) {
|
||||||
@ -292,7 +292,7 @@ void ws_socket_free(ws_ctx_t *ctx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int ws_b64_ntop(const unsigned char const * src, size_t srclen, char * dst, size_t dstlen) {
|
int ws_b64_ntop(const unsigned char * const src, size_t srclen, char * dst, size_t dstlen) {
|
||||||
int len = 0;
|
int len = 0;
|
||||||
int total_len = 0;
|
int total_len = 0;
|
||||||
|
|
||||||
@ -327,7 +327,7 @@ int ws_b64_ntop(const unsigned char const * src, size_t srclen, char * dst, size
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ws_b64_pton(const char const * src, unsigned char * dst, size_t dstlen) {
|
int ws_b64_pton(const char * const src, unsigned char * dst, size_t dstlen) {
|
||||||
int len = 0;
|
int len = 0;
|
||||||
int total_len = 0;
|
int total_len = 0;
|
||||||
int pending = 0;
|
int pending = 0;
|
||||||
@ -724,14 +724,14 @@ int gen_md5(headers_t *headers, char *target) {
|
|||||||
static void gen_sha1(headers_t *headers, char *target) {
|
static void gen_sha1(headers_t *headers, char *target) {
|
||||||
SHA_CTX c;
|
SHA_CTX c;
|
||||||
unsigned char hash[SHA_DIGEST_LENGTH];
|
unsigned char hash[SHA_DIGEST_LENGTH];
|
||||||
int r;
|
//int r;
|
||||||
|
|
||||||
SHA1_Init(&c);
|
SHA1_Init(&c);
|
||||||
SHA1_Update(&c, headers->key1, strlen(headers->key1));
|
SHA1_Update(&c, headers->key1, strlen(headers->key1));
|
||||||
SHA1_Update(&c, HYBI_GUID, 36);
|
SHA1_Update(&c, HYBI_GUID, 36);
|
||||||
SHA1_Final(hash, &c);
|
SHA1_Final(hash, &c);
|
||||||
|
|
||||||
r = ws_b64_ntop(hash, sizeof hash, target, HYBI10_ACCEPTHDRLEN);
|
/*r =*/ ws_b64_ntop(hash, sizeof hash, target, HYBI10_ACCEPTHDRLEN);
|
||||||
//assert(r == HYBI10_ACCEPTHDRLEN - 1);
|
//assert(r == HYBI10_ACCEPTHDRLEN - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1021,7 +1021,8 @@ static uint8_t ownerapi_post(ws_ctx_t *ws_ctx, const char *in) {
|
|||||||
goto nope;
|
goto nope;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t mask = USER_UPDATE_WRITE_MASK | USER_UPDATE_OWNER_MASK;
|
uint64_t mask = USER_UPDATE_READ_MASK | USER_UPDATE_WRITE_MASK |
|
||||||
|
USER_UPDATE_OWNER_MASK;
|
||||||
|
|
||||||
if (set->entries[s].password[0]) {
|
if (set->entries[s].password[0]) {
|
||||||
struct crypt_data cdata;
|
struct crypt_data cdata;
|
||||||
@ -1035,6 +1036,7 @@ static uint8_t ownerapi_post(ws_ctx_t *ws_ctx, const char *in) {
|
|||||||
|
|
||||||
if (!settings.updateUserCb(settings.messager, set->entries[s].user, mask,
|
if (!settings.updateUserCb(settings.messager, set->entries[s].user, mask,
|
||||||
set->entries[s].password,
|
set->entries[s].password,
|
||||||
|
set->entries[s].read,
|
||||||
set->entries[s].write, set->entries[s].owner)) {
|
set->entries[s].write, set->entries[s].owner)) {
|
||||||
wserr("Invalid params to update_user\n");
|
wserr("Invalid params to update_user\n");
|
||||||
goto nope;
|
goto nope;
|
||||||
@ -1173,7 +1175,7 @@ static uint8_t ownerapi(ws_ctx_t *ws_ctx, const char *in) {
|
|||||||
}
|
}
|
||||||
} else entry("/api/create_user") {
|
} else entry("/api/create_user") {
|
||||||
char decname[1024] = "", decpw[1024] = "";
|
char decname[1024] = "", decpw[1024] = "";
|
||||||
uint8_t write = 0, owner = 0;
|
uint8_t read = 0, write = 0, owner = 0;
|
||||||
|
|
||||||
param = parse_get(args, "name", &len);
|
param = parse_get(args, "name", &len);
|
||||||
if (len) {
|
if (len) {
|
||||||
@ -1195,6 +1197,12 @@ static uint8_t ownerapi(ws_ctx_t *ws_ctx, const char *in) {
|
|||||||
strcpy(decpw, encrypted);
|
strcpy(decpw, encrypted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
param = parse_get(args, "read", &len);
|
||||||
|
if (len && isalpha(param[0])) {
|
||||||
|
if (!strncmp(param, "true", len))
|
||||||
|
read = 1;
|
||||||
|
}
|
||||||
|
|
||||||
param = parse_get(args, "write", &len);
|
param = parse_get(args, "write", &len);
|
||||||
if (len && isalpha(param[0])) {
|
if (len && isalpha(param[0])) {
|
||||||
if (!strncmp(param, "true", len))
|
if (!strncmp(param, "true", len))
|
||||||
@ -1210,7 +1218,7 @@ static uint8_t ownerapi(ws_ctx_t *ws_ctx, const char *in) {
|
|||||||
if (!decname[0] || !decpw[0])
|
if (!decname[0] || !decpw[0])
|
||||||
goto nope;
|
goto nope;
|
||||||
|
|
||||||
if (!settings.adduserCb(settings.messager, decname, decpw, write, owner)) {
|
if (!settings.adduserCb(settings.messager, decname, decpw, read, write, owner)) {
|
||||||
wserr("Invalid params to create_user\n");
|
wserr("Invalid params to create_user\n");
|
||||||
goto nope;
|
goto nope;
|
||||||
}
|
}
|
||||||
@ -1267,6 +1275,14 @@ static uint8_t ownerapi(ws_ctx_t *ws_ctx, const char *in) {
|
|||||||
goto nope;
|
goto nope;
|
||||||
|
|
||||||
uint64_t mask = 0;
|
uint64_t mask = 0;
|
||||||
|
uint8_t myread = 0;
|
||||||
|
param = parse_get(args, "read", &len);
|
||||||
|
if (len && isalpha(param[0])) {
|
||||||
|
mask |= USER_UPDATE_READ_MASK;
|
||||||
|
if (!strncmp(param, "true", len))
|
||||||
|
myread = 1;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t mywrite = 0;
|
uint8_t mywrite = 0;
|
||||||
param = parse_get(args, "write", &len);
|
param = parse_get(args, "write", &len);
|
||||||
if (len && isalpha(param[0])) {
|
if (len && isalpha(param[0])) {
|
||||||
@ -1283,7 +1299,8 @@ static uint8_t ownerapi(ws_ctx_t *ws_ctx, const char *in) {
|
|||||||
myowner = 1;
|
myowner = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!settings.updateUserCb(settings.messager, decname, mask, "", mywrite, myowner)) {
|
if (!settings.updateUserCb(settings.messager, decname, mask, "",
|
||||||
|
myread, mywrite, myowner)) {
|
||||||
wserr("Invalid params to update_user\n");
|
wserr("Invalid params to update_user\n");
|
||||||
goto nope;
|
goto nope;
|
||||||
}
|
}
|
||||||
@ -1370,14 +1387,25 @@ static uint8_t ownerapi(ws_ctx_t *ws_ctx, const char *in) {
|
|||||||
goto nope;
|
goto nope;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (1) {
|
unsigned waits;
|
||||||
usleep(10 * 1000);
|
{
|
||||||
if (settings.serverFrameStatsReadyCb(settings.messager))
|
uint8_t failed = 1;
|
||||||
|
for (waits = 0; waits < 500; waits++) { // wait up to 10s
|
||||||
|
usleep(20 * 1000);
|
||||||
|
if (settings.serverFrameStatsReadyCb(settings.messager)) {
|
||||||
|
failed = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (failed) {
|
||||||
|
wserr("Main thread didn't respond, aborting (bug!)\n");
|
||||||
|
settings.resetFrameStatsCb(settings.messager);
|
||||||
|
goto timeout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (waitfor) {
|
if (waitfor) {
|
||||||
unsigned waits;
|
|
||||||
for (waits = 0; waits < 20; waits++) { // wait up to 2s
|
for (waits = 0; waits < 20; waits++) { // wait up to 2s
|
||||||
if (settings.getClientFrameStatsNumCb(settings.messager) >= waitfor)
|
if (settings.getClientFrameStatsNumCb(settings.messager) >= waitfor)
|
||||||
break;
|
break;
|
||||||
@ -1403,6 +1431,7 @@ static uint8_t ownerapi(ws_ctx_t *ws_ctx, const char *in) {
|
|||||||
#undef entry
|
#undef entry
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
nope:
|
nope:
|
||||||
sprintf(buf, "HTTP/1.1 400 Bad Request\r\n"
|
sprintf(buf, "HTTP/1.1 400 Bad Request\r\n"
|
||||||
"Server: KasmVNC/4.0\r\n"
|
"Server: KasmVNC/4.0\r\n"
|
||||||
@ -1412,6 +1441,16 @@ nope:
|
|||||||
"400 Bad Request");
|
"400 Bad Request");
|
||||||
ws_send(ws_ctx, buf, strlen(buf));
|
ws_send(ws_ctx, buf, strlen(buf));
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
timeout:
|
||||||
|
sprintf(buf, "HTTP/1.1 503 Service Unavailable\r\n"
|
||||||
|
"Server: KasmVNC/4.0\r\n"
|
||||||
|
"Connection: close\r\n"
|
||||||
|
"Content-type: text/plain\r\n"
|
||||||
|
"\r\n"
|
||||||
|
"503 Service Unavailable");
|
||||||
|
ws_send(ws_ctx, buf, strlen(buf));
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ws_ctx_t *do_handshake(int sock, const char *ip) {
|
ws_ctx_t *do_handshake(int sock, const char *ip) {
|
||||||
@ -1696,7 +1735,7 @@ out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void *start_server(void *unused) {
|
void *start_server(void *unused) {
|
||||||
int csock, pid;
|
int csock;
|
||||||
struct sockaddr_in cli_addr;
|
struct sockaddr_in cli_addr;
|
||||||
socklen_t clilen;
|
socklen_t clilen;
|
||||||
|
|
||||||
@ -1706,7 +1745,6 @@ void *start_server(void *unused) {
|
|||||||
while (1) {
|
while (1) {
|
||||||
clilen = sizeof(cli_addr);
|
clilen = sizeof(cli_addr);
|
||||||
pipe_error = 0;
|
pipe_error = 0;
|
||||||
pid = 0;
|
|
||||||
do {
|
do {
|
||||||
csock = accept(settings.listen_sock,
|
csock = accept(settings.listen_sock,
|
||||||
(struct sockaddr *) &cli_addr,
|
(struct sockaddr *) &cli_addr,
|
||||||
|
@ -84,14 +84,15 @@ typedef struct {
|
|||||||
const uint8_t dedup,
|
const uint8_t dedup,
|
||||||
uint32_t *len, uint8_t *staging);
|
uint32_t *len, uint8_t *staging);
|
||||||
uint8_t (*adduserCb)(void *messager, const char name[], const char pw[],
|
uint8_t (*adduserCb)(void *messager, const char name[], const char pw[],
|
||||||
const uint8_t write, const uint8_t owner);
|
const uint8_t read, const uint8_t write, const uint8_t owner);
|
||||||
uint8_t (*removeCb)(void *messager, const char name[]);
|
uint8_t (*removeCb)(void *messager, const char name[]);
|
||||||
uint8_t (*updateUserCb)(void *messager, const char name[], const uint64_t mask,
|
uint8_t (*updateUserCb)(void *messager, const char name[], const uint64_t mask,
|
||||||
const char password[],
|
const char password[],
|
||||||
const uint8_t write, const uint8_t owner);
|
const uint8_t read, const uint8_t write, const uint8_t owner);
|
||||||
uint8_t (*addOrUpdateUserCb)(void *messager, const struct kasmpasswd_entry_t *entry);
|
uint8_t (*addOrUpdateUserCb)(void *messager, const struct kasmpasswd_entry_t *entry);
|
||||||
void (*bottleneckStatsCb)(void *messager, char *buf, uint32_t len);
|
void (*bottleneckStatsCb)(void *messager, char *buf, uint32_t len);
|
||||||
void (*frameStatsCb)(void *messager, char *buf, uint32_t len);
|
void (*frameStatsCb)(void *messager, char *buf, uint32_t len);
|
||||||
|
void (*resetFrameStatsCb)(void *messager);
|
||||||
|
|
||||||
uint8_t (*requestFrameStatsNoneCb)(void *messager);
|
uint8_t (*requestFrameStatsNoneCb)(void *messager);
|
||||||
uint8_t (*requestFrameStatsOwnerCb)(void *messager);
|
uint8_t (*requestFrameStatsOwnerCb)(void *messager);
|
||||||
|
@ -216,7 +216,7 @@ void SConnection::processSecurityMsg()
|
|||||||
bool done = ssecurity->processMsg(this);
|
bool done = ssecurity->processMsg(this);
|
||||||
if (done) {
|
if (done) {
|
||||||
state_ = RFBSTATE_QUERYING;
|
state_ = RFBSTATE_QUERYING;
|
||||||
setAccessRights(ssecurity->getAccessRights());
|
//setAccessRights(ssecurity->getAccessRights());
|
||||||
queryConnection(ssecurity->getUserName());
|
queryConnection(ssecurity->getUserName());
|
||||||
}
|
}
|
||||||
} catch (AuthFailureException& e) {
|
} catch (AuthFailureException& e) {
|
||||||
|
@ -144,7 +144,6 @@ namespace rfb {
|
|||||||
static const AccessRights AccessDefault; // The default rights, INCLUDING FUTURE ONES
|
static const AccessRights AccessDefault; // The default rights, INCLUDING FUTURE ONES
|
||||||
static const AccessRights AccessNoQuery; // Connect without local user accepting
|
static const AccessRights AccessNoQuery; // Connect without local user accepting
|
||||||
static const AccessRights AccessFull; // All of the available AND FUTURE rights
|
static const AccessRights AccessFull; // All of the available AND FUTURE rights
|
||||||
virtual void setAccessRights(AccessRights ar) = 0;
|
|
||||||
|
|
||||||
// Other methods
|
// Other methods
|
||||||
|
|
||||||
|
@ -87,10 +87,16 @@ VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
|
|||||||
user[at - peerEndpoint.buf] = '\0';
|
user[at - peerEndpoint.buf] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
bool write, owner;
|
bool read, write, owner;
|
||||||
if (!getPerms(write, owner) || !write) {
|
if (!getPerms(read, write, owner)) {
|
||||||
|
accessRights &= ~(WRITER_PERMS | AccessView);
|
||||||
|
}
|
||||||
|
if (!write) {
|
||||||
accessRights &= ~WRITER_PERMS;
|
accessRights &= ~WRITER_PERMS;
|
||||||
}
|
}
|
||||||
|
if (!read) {
|
||||||
|
accessRights &= ~AccessView;
|
||||||
|
}
|
||||||
|
|
||||||
// Configure the socket
|
// Configure the socket
|
||||||
setSocketTimeouts();
|
setSocketTimeouts();
|
||||||
@ -707,7 +713,13 @@ void VNCSConnectionST::pointerEvent(const Point& pos, int buttonMask, const bool
|
|||||||
{
|
{
|
||||||
pointerEventTime = lastEventTime = time(0);
|
pointerEventTime = lastEventTime = time(0);
|
||||||
server->lastUserInputTime = lastEventTime;
|
server->lastUserInputTime = lastEventTime;
|
||||||
if (!(accessRights & AccessPtrEvents)) return;
|
if (!(accessRights & AccessPtrEvents)) {
|
||||||
|
// This particular event is lost, but it's a corner case - you removed write access
|
||||||
|
// from yourself, then added it back. The intended use is for multiple clients,
|
||||||
|
// where the leader removes and adds back access for others, not himself.
|
||||||
|
recheckPerms();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!rfb::Server::acceptPointerEvents) return;
|
if (!rfb::Server::acceptPointerEvents) return;
|
||||||
if (!server->pointerClient || server->pointerClient == this) {
|
if (!server->pointerClient || server->pointerClient == this) {
|
||||||
pointerEventPos = pos;
|
pointerEventPos = pos;
|
||||||
@ -1105,11 +1117,12 @@ bool VNCSConnectionST::isShiftPressed()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VNCSConnectionST::getPerms(bool &write, bool &owner) const
|
bool VNCSConnectionST::getPerms(bool &read, bool &write, bool &owner) const
|
||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
if (disablebasicauth) {
|
if (disablebasicauth) {
|
||||||
// We're running without basicauth
|
// We're running without basicauth
|
||||||
|
read = true;
|
||||||
write = true;
|
write = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1118,8 +1131,14 @@ bool VNCSConnectionST::getPerms(bool &write, bool &owner) const
|
|||||||
unsigned i;
|
unsigned i;
|
||||||
for (i = 0; i < set->num; i++) {
|
for (i = 0; i < set->num; i++) {
|
||||||
if (!strcmp(set->entries[i].user, user)) {
|
if (!strcmp(set->entries[i].user, user)) {
|
||||||
|
read = set->entries[i].read;
|
||||||
write = set->entries[i].write;
|
write = set->entries[i].write;
|
||||||
owner = set->entries[i].owner;
|
owner = set->entries[i].owner;
|
||||||
|
|
||||||
|
// Writer can always read
|
||||||
|
if (write)
|
||||||
|
read = true;
|
||||||
|
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1217,17 +1236,28 @@ void VNCSConnectionST::writeFramebufferUpdate()
|
|||||||
if (needsPermCheck) {
|
if (needsPermCheck) {
|
||||||
needsPermCheck = false;
|
needsPermCheck = false;
|
||||||
|
|
||||||
bool write, owner, ret;
|
bool read, write, owner, ret;
|
||||||
ret = getPerms(write, owner);
|
ret = getPerms(read, write, owner);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
close("User was deleted");
|
close("User was deleted");
|
||||||
return;
|
return;
|
||||||
} else if (!write) {
|
}
|
||||||
|
|
||||||
|
if (!write) {
|
||||||
accessRights &= ~WRITER_PERMS;
|
accessRights &= ~WRITER_PERMS;
|
||||||
} else {
|
} else {
|
||||||
accessRights |= WRITER_PERMS;
|
accessRights |= WRITER_PERMS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!read) {
|
||||||
|
accessRights &= ~AccessView;
|
||||||
|
} else {
|
||||||
|
accessRights |= AccessView;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(accessRights & AccessView))
|
||||||
|
return;
|
||||||
|
|
||||||
// Updates often consists of many small writes, and in continuous
|
// Updates often consists of many small writes, and in continuous
|
||||||
// mode, we will also have small fence messages around the update. We
|
// mode, we will also have small fence messages around the update. We
|
||||||
@ -1659,8 +1689,8 @@ bool VNCSConnectionST::checkOwnerConn() const
|
|||||||
std::list<VNCSConnectionST*>::const_iterator it;
|
std::list<VNCSConnectionST*>::const_iterator it;
|
||||||
|
|
||||||
for (it = server->clients.begin(); it != server->clients.end(); it++) {
|
for (it = server->clients.begin(); it != server->clients.end(); it++) {
|
||||||
bool write, owner;
|
bool read, write, owner;
|
||||||
if ((*it)->getPerms(write, owner) && owner)
|
if ((*it)->getPerms(read, write, owner) && owner)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,8 +171,8 @@ namespace rfb {
|
|||||||
virtual void handleFrameStats(rdr::U32 all, rdr::U32 render);
|
virtual void handleFrameStats(rdr::U32 all, rdr::U32 render);
|
||||||
|
|
||||||
bool is_owner() const {
|
bool is_owner() const {
|
||||||
bool write, owner;
|
bool read, write, owner;
|
||||||
if (getPerms(write, owner) && owner)
|
if (getPerms(read, write, owner) && owner)
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -227,19 +227,6 @@ namespace rfb {
|
|||||||
(AccessPtrEvents | AccessKeyEvents);
|
(AccessPtrEvents | AccessKeyEvents);
|
||||||
}
|
}
|
||||||
|
|
||||||
// setAccessRights() allows a security package to limit the access rights
|
|
||||||
// of a VNCSConnectioST to the server. These access rights are applied
|
|
||||||
// such that the actual rights granted are the minimum of the server's
|
|
||||||
// default access settings and the connection's access settings.
|
|
||||||
virtual void setAccessRights(AccessRights ar) {
|
|
||||||
accessRights = ar;
|
|
||||||
|
|
||||||
bool write, owner;
|
|
||||||
if (!getPerms(write, owner) || !write)
|
|
||||||
accessRights &= ~WRITER_PERMS;
|
|
||||||
needsPermCheck = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Timer callbacks
|
// Timer callbacks
|
||||||
virtual bool handleTimeout(Timer* t);
|
virtual bool handleTimeout(Timer* t);
|
||||||
|
|
||||||
@ -247,7 +234,7 @@ namespace rfb {
|
|||||||
|
|
||||||
bool isShiftPressed();
|
bool isShiftPressed();
|
||||||
|
|
||||||
bool getPerms(bool &write, bool &owner) const;
|
bool getPerms(bool &read, bool &write, bool &owner) const;
|
||||||
|
|
||||||
bool checkOwnerConn() const;
|
bool checkOwnerConn() const;
|
||||||
|
|
||||||
|
@ -807,6 +807,9 @@ static void checkAPIMessages(network::GetAPIMessager *apimessager,
|
|||||||
const network::GetAPIMessager::action_data &act = apimessager->actionQueue[i];
|
const network::GetAPIMessager::action_data &act = apimessager->actionQueue[i];
|
||||||
|
|
||||||
switch (act.action) {
|
switch (act.action) {
|
||||||
|
case network::GetAPIMessager::NONE:
|
||||||
|
slog.info("Empty request (bug!)");
|
||||||
|
break;
|
||||||
case network::GetAPIMessager::WANT_FRAME_STATS_SERVERONLY:
|
case network::GetAPIMessager::WANT_FRAME_STATS_SERVERONLY:
|
||||||
trackingFrameStats = act.action;
|
trackingFrameStats = act.action;
|
||||||
break;
|
break;
|
||||||
|
@ -60,6 +60,8 @@ struct kasmpasswd_t *readkasmpasswd(const char path[]) {
|
|||||||
strcpy(set->entries[cur].user, buf);
|
strcpy(set->entries[cur].user, buf);
|
||||||
strcpy(set->entries[cur].password, pw);
|
strcpy(set->entries[cur].password, pw);
|
||||||
|
|
||||||
|
if (strchr(perms, 'r'))
|
||||||
|
set->entries[cur].read = 1;
|
||||||
if (strchr(perms, 'w'))
|
if (strchr(perms, 'w'))
|
||||||
set->entries[cur].write = 1;
|
set->entries[cur].write = 1;
|
||||||
if (strchr(perms, 'o'))
|
if (strchr(perms, 'o'))
|
||||||
@ -90,22 +92,17 @@ void writekasmpasswd(const char path[], const struct kasmpasswd_t *set) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char * const perms[] = {
|
|
||||||
"",
|
|
||||||
"w",
|
|
||||||
"o",
|
|
||||||
"ow"
|
|
||||||
};
|
|
||||||
|
|
||||||
unsigned i;
|
unsigned i;
|
||||||
for (i = 0; i < set->num; i++) {
|
for (i = 0; i < set->num; i++) {
|
||||||
if (!set->entries[i].user[0])
|
if (!set->entries[i].user[0])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
fprintf(f, "%s:%s:%s\n",
|
fprintf(f, "%s:%s:%s%s%s\n",
|
||||||
set->entries[i].user,
|
set->entries[i].user,
|
||||||
set->entries[i].password,
|
set->entries[i].password,
|
||||||
perms[set->entries[i].owner * 2 + set->entries[i].write]);
|
set->entries[i].read ? "r" : "",
|
||||||
|
set->entries[i].write ? "w" : "",
|
||||||
|
set->entries[i].owner ? "o" : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
fsync(fileno(f));
|
fsync(fileno(f));
|
||||||
|
@ -8,6 +8,7 @@ extern "C" {
|
|||||||
struct kasmpasswd_entry_t {
|
struct kasmpasswd_entry_t {
|
||||||
char user[32];
|
char user[32];
|
||||||
char password[128];
|
char password[128];
|
||||||
|
unsigned char read : 1;
|
||||||
unsigned char write : 1;
|
unsigned char write : 1;
|
||||||
unsigned char owner : 1;
|
unsigned char owner : 1;
|
||||||
};
|
};
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
static void usage(const char *prog)
|
static void usage(const char *prog)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Usage: %s -u username [-wnod] [file]\n"
|
fprintf(stderr, "Usage: %s -u username [-wnod] [file]\n"
|
||||||
|
"-r Read permission\n"
|
||||||
"-w Write permission\n"
|
"-w Write permission\n"
|
||||||
"-o Owner\n"
|
"-o Owner\n"
|
||||||
"-n Don't change password, change permissions only\n"
|
"-n Don't change password, change permissions only\n"
|
||||||
@ -118,10 +119,10 @@ int main(int argc, char** argv)
|
|||||||
{
|
{
|
||||||
const char *fname = NULL;
|
const char *fname = NULL;
|
||||||
const char *user = NULL;
|
const char *user = NULL;
|
||||||
const char args[] = "u:wnod";
|
const char args[] = "u:rwnod";
|
||||||
int opt;
|
int opt;
|
||||||
|
|
||||||
unsigned char nopass = 0, writer = 0, owner = 0, deleting = 0;
|
unsigned char nopass = 0, reader = 0, writer = 0, owner = 0, deleting = 0;
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, args)) != -1) {
|
while ((opt = getopt(argc, argv, args)) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
@ -135,6 +136,9 @@ int main(int argc, char** argv)
|
|||||||
case 'n':
|
case 'n':
|
||||||
nopass = 1;
|
nopass = 1;
|
||||||
break;
|
break;
|
||||||
|
case 'r':
|
||||||
|
reader = 1;
|
||||||
|
break;
|
||||||
case 'w':
|
case 'w':
|
||||||
writer = 1;
|
writer = 1;
|
||||||
break;
|
break;
|
||||||
@ -150,7 +154,7 @@ int main(int argc, char** argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deleting && (nopass || writer || owner))
|
if (deleting && (nopass || reader || writer || owner))
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
|
|
||||||
if (!user)
|
if (!user)
|
||||||
@ -175,6 +179,7 @@ int main(int argc, char** argv)
|
|||||||
if (nopass) {
|
if (nopass) {
|
||||||
for (i = 0; i < set->num; i++) {
|
for (i = 0; i < set->num; i++) {
|
||||||
if (!strcmp(set->entries[i].user, user)) {
|
if (!strcmp(set->entries[i].user, user)) {
|
||||||
|
set->entries[i].read = reader;
|
||||||
set->entries[i].write = writer;
|
set->entries[i].write = writer;
|
||||||
set->entries[i].owner = owner;
|
set->entries[i].owner = owner;
|
||||||
|
|
||||||
@ -211,6 +216,7 @@ int main(int argc, char** argv)
|
|||||||
|
|
||||||
strcpy(set->entries[i].user, user);
|
strcpy(set->entries[i].user, user);
|
||||||
strcpy(set->entries[i].password, encrypted);
|
strcpy(set->entries[i].password, encrypted);
|
||||||
|
set->entries[i].read = reader;
|
||||||
set->entries[i].write = writer;
|
set->entries[i].write = writer;
|
||||||
set->entries[i].owner = owner;
|
set->entries[i].owner = owner;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user