Merge branch 'users' into packages_and_multiuser_passwd
This commit is contained in:
@@ -1,10 +1,11 @@
|
|||||||
include_directories(${CMAKE_SOURCE_DIR}/common)
|
include_directories(${CMAKE_SOURCE_DIR}/common ${CMAKE_SOURCE_DIR}/unix/kasmvncpasswd)
|
||||||
|
|
||||||
set(NETWORK_SOURCES
|
set(NETWORK_SOURCES
|
||||||
Socket.cxx
|
Socket.cxx
|
||||||
TcpSocket.cxx
|
TcpSocket.cxx
|
||||||
websocket.c
|
websocket.c
|
||||||
websockify.c)
|
websockify.c
|
||||||
|
${CMAKE_SOURCE_DIR}/unix/kasmvncpasswd/kasmpasswd.c)
|
||||||
|
|
||||||
if(NOT WIN32)
|
if(NOT WIN32)
|
||||||
set(NETWORK_SOURCES ${NETWORK_SOURCES} UnixSocket.cxx)
|
set(NETWORK_SOURCES ${NETWORK_SOURCES} UnixSocket.cxx)
|
||||||
|
|||||||
@@ -124,11 +124,20 @@ WebSocket::WebSocket(int sock) : Socket(sock)
|
|||||||
}
|
}
|
||||||
|
|
||||||
char* WebSocket::getPeerAddress() {
|
char* WebSocket::getPeerAddress() {
|
||||||
return rfb::strDup("websocket");
|
struct sockaddr_un addr;
|
||||||
|
socklen_t len = sizeof(struct sockaddr_un);
|
||||||
|
if (getpeername(getFd(), (struct sockaddr *) &addr, &len) != 0) {
|
||||||
|
vlog.error("unable to get peer name for socket");
|
||||||
|
return rfb::strDup("websocket");
|
||||||
|
}
|
||||||
|
return rfb::strDup(addr.sun_path + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
char* WebSocket::getPeerEndpoint() {
|
char* WebSocket::getPeerEndpoint() {
|
||||||
return rfb::strDup("websocket");
|
char buf[1024];
|
||||||
|
sprintf(buf, "%s::websocket", getPeerAddress());
|
||||||
|
|
||||||
|
return rfb::strDup(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -=- TcpSocket
|
// -=- TcpSocket
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#include <openssl/md5.h> /* md5 hash */
|
#include <openssl/md5.h> /* md5 hash */
|
||||||
#include <openssl/sha.h> /* sha1 hash */
|
#include <openssl/sha.h> /* sha1 hash */
|
||||||
#include "websocket.h"
|
#include "websocket.h"
|
||||||
|
#include "kasmpasswd.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Global state
|
* Global state
|
||||||
@@ -107,7 +108,7 @@ ssize_t ws_send(ws_ctx_t *ctx, const void *buf, size_t len) {
|
|||||||
|
|
||||||
ws_ctx_t *alloc_ws_ctx() {
|
ws_ctx_t *alloc_ws_ctx() {
|
||||||
ws_ctx_t *ctx;
|
ws_ctx_t *ctx;
|
||||||
if (! (ctx = malloc(sizeof(ws_ctx_t))) )
|
if (! (ctx = calloc(sizeof(ws_ctx_t), 1)) )
|
||||||
{ fatal("malloc()"); }
|
{ fatal("malloc()"); }
|
||||||
|
|
||||||
if (! (ctx->cin_buf = malloc(BUFSIZE)) )
|
if (! (ctx->cin_buf = malloc(BUFSIZE)) )
|
||||||
@@ -916,34 +917,43 @@ ws_ctx_t *do_handshake(int sock) {
|
|||||||
if (resppw && *resppw)
|
if (resppw && *resppw)
|
||||||
resppw++;
|
resppw++;
|
||||||
if (!colon[1] && settings.passwdfile) {
|
if (!colon[1] && settings.passwdfile) {
|
||||||
if (resppw && *resppw) {
|
if (resppw && *resppw && resppw - response < 32) {
|
||||||
char pwbuf[4096];
|
char pwbuf[4096];
|
||||||
FILE *f = fopen(settings.passwdfile, "r");
|
struct kasmpasswd_t *set = readkasmpasswd(settings.passwdfile);
|
||||||
if (f) {
|
if (!set->num) {
|
||||||
handler_emsg("BasicAuth reading password from %s\n", settings.passwdfile);
|
fprintf(stderr, " websocket %d: Error: BasicAuth configured to read password from file %s, but the file doesn't exist or has no valid users\n",
|
||||||
const unsigned len = fread(pwbuf, 1, 4096, f);
|
|
||||||
fclose(f);
|
|
||||||
pwbuf[4095] = '\0';
|
|
||||||
if (len < 4096)
|
|
||||||
pwbuf[len] = '\0';
|
|
||||||
|
|
||||||
snprintf(authbuf, 4096, "%s%s", settings.basicauth, pwbuf);
|
|
||||||
authbuf[4095] = '\0';
|
|
||||||
|
|
||||||
struct crypt_data cdata;
|
|
||||||
cdata.initialized = 0;
|
|
||||||
|
|
||||||
const char *encrypted = crypt_r(resppw, "$5$kasm$", &cdata);
|
|
||||||
*resppw = '\0';
|
|
||||||
|
|
||||||
snprintf(pwbuf, 4096, "%s%s", response, encrypted);
|
|
||||||
pwbuf[4095] = '\0';
|
|
||||||
strcpy(response, pwbuf);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, " websocket %d: Error: BasicAuth configured to read password from file %s, but the file doesn't exist\n",
|
|
||||||
wsthread_handler_id,
|
wsthread_handler_id,
|
||||||
settings.passwdfile);
|
settings.passwdfile);
|
||||||
|
} else {
|
||||||
|
unsigned i;
|
||||||
|
char inuser[32];
|
||||||
|
unsigned char found = 0;
|
||||||
|
memcpy(inuser, response, resppw - response - 1);
|
||||||
|
inuser[resppw - response - 1] = '\0';
|
||||||
|
|
||||||
|
for (i = 0; i < set->num; i++) {
|
||||||
|
if (!strcmp(set->entries[i].user, inuser)) {
|
||||||
|
found = 1;
|
||||||
|
strcpy(ws_ctx->user, inuser);
|
||||||
|
snprintf(authbuf, 4096, "%s:%s", set->entries[i].user,
|
||||||
|
set->entries[i].password);
|
||||||
|
authbuf[4095] = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
handler_emsg("BasicAuth user %s not found\n", inuser);
|
||||||
}
|
}
|
||||||
|
free(set->entries);
|
||||||
|
free(set);
|
||||||
|
|
||||||
|
const char *encrypted = crypt(resppw, "$5$kasm$");
|
||||||
|
*resppw = '\0';
|
||||||
|
|
||||||
|
snprintf(pwbuf, 4096, "%s%s", response, encrypted);
|
||||||
|
pwbuf[4095] = '\0';
|
||||||
|
strcpy(response, pwbuf);
|
||||||
} else {
|
} else {
|
||||||
// Client tried an empty password, just fail them
|
// Client tried an empty password, just fail them
|
||||||
response[0] = '\0';
|
response[0] = '\0';
|
||||||
@@ -1018,7 +1028,6 @@ void *subthread(void *ptr) {
|
|||||||
|
|
||||||
const int csock = pass->csock;
|
const int csock = pass->csock;
|
||||||
wsthread_handler_id = pass->id;
|
wsthread_handler_id = pass->id;
|
||||||
free((void *) pass);
|
|
||||||
|
|
||||||
ws_ctx_t *ws_ctx;
|
ws_ctx_t *ws_ctx;
|
||||||
|
|
||||||
@@ -1028,11 +1037,14 @@ void *subthread(void *ptr) {
|
|||||||
goto out; // Child process exits
|
goto out; // Child process exits
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memcpy(ws_ctx->ip, pass->ip, sizeof(pass->ip));
|
||||||
|
|
||||||
proxy_handler(ws_ctx);
|
proxy_handler(ws_ctx);
|
||||||
if (pipe_error) {
|
if (pipe_error) {
|
||||||
handler_emsg("Closing due to SIGPIPE\n");
|
handler_emsg("Closing due to SIGPIPE\n");
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
|
free((void *) pass);
|
||||||
|
|
||||||
if (ws_ctx) {
|
if (ws_ctx) {
|
||||||
ws_socket_free(ws_ctx);
|
ws_socket_free(ws_ctx);
|
||||||
@@ -1068,12 +1080,13 @@ void *start_server(void *unused) {
|
|||||||
error("ERROR on accept");
|
error("ERROR on accept");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
struct wspass_t *pass = calloc(1, sizeof(struct wspass_t));
|
||||||
|
inet_ntop(cli_addr.sin_family, &cli_addr.sin_addr, pass->ip, sizeof(pass->ip));
|
||||||
fprintf(stderr, " websocket %d: got client connection from %s\n",
|
fprintf(stderr, " websocket %d: got client connection from %s\n",
|
||||||
settings.handler_id,
|
settings.handler_id,
|
||||||
inet_ntoa(cli_addr.sin_addr));
|
pass->ip);
|
||||||
|
|
||||||
pthread_t tid;
|
pthread_t tid;
|
||||||
struct wspass_t *pass = calloc(1, sizeof(struct wspass_t));
|
|
||||||
pass->id = settings.handler_id;
|
pass->id = settings.handler_id;
|
||||||
pass->csock = csock;
|
pass->csock = csock;
|
||||||
pthread_create(&tid, NULL, subthread, pass);
|
pthread_create(&tid, NULL, subthread, pass);
|
||||||
|
|||||||
@@ -53,11 +53,15 @@ typedef struct {
|
|||||||
char *cout_buf;
|
char *cout_buf;
|
||||||
char *tin_buf;
|
char *tin_buf;
|
||||||
char *tout_buf;
|
char *tout_buf;
|
||||||
|
|
||||||
|
char user[32];
|
||||||
|
char ip[64];
|
||||||
} ws_ctx_t;
|
} ws_ctx_t;
|
||||||
|
|
||||||
struct wspass_t {
|
struct wspass_t {
|
||||||
int csock;
|
int csock;
|
||||||
unsigned id;
|
unsigned id;
|
||||||
|
char ip[64];
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
@@ -227,7 +227,13 @@ void proxy_handler(ws_ctx_t *ws_ctx) {
|
|||||||
strcpy(addr.sun_path, ".KasmVNCSock");
|
strcpy(addr.sun_path, ".KasmVNCSock");
|
||||||
addr.sun_path[0] = '\0';
|
addr.sun_path[0] = '\0';
|
||||||
|
|
||||||
|
struct sockaddr_un myaddr;
|
||||||
|
myaddr.sun_family = AF_UNIX;
|
||||||
|
sprintf(myaddr.sun_path, ".%s@%s", ws_ctx->user, ws_ctx->ip);
|
||||||
|
myaddr.sun_path[0] = '\0';
|
||||||
|
|
||||||
int tsock = socket(AF_UNIX, SOCK_STREAM, 0);
|
int tsock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
bind(tsock, (struct sockaddr *) &myaddr, sizeof(struct sockaddr_un));
|
||||||
|
|
||||||
handler_msg("connecting to VNC target\n");
|
handler_msg("connecting to VNC target\n");
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
include_directories(${CMAKE_SOURCE_DIR}/common ${JPEG_INCLUDE_DIR})
|
include_directories(${CMAKE_SOURCE_DIR}/common ${JPEG_INCLUDE_DIR}
|
||||||
|
${CMAKE_SOURCE_DIR}/unix/kasmvncpasswd)
|
||||||
|
|
||||||
set(RFB_SOURCES
|
set(RFB_SOURCES
|
||||||
Blacklist.cxx
|
Blacklist.cxx
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include <rfb/ledStates.h>
|
#include <rfb/ledStates.h>
|
||||||
#include <rfb/ConnParams.h>
|
#include <rfb/ConnParams.h>
|
||||||
#include <rfb/ServerCore.h>
|
#include <rfb/ServerCore.h>
|
||||||
|
#include <rfb/SMsgHandler.h>
|
||||||
#include <rfb/util.h>
|
#include <rfb/util.h>
|
||||||
|
|
||||||
using namespace rfb;
|
using namespace rfb;
|
||||||
@@ -43,7 +44,7 @@ ConnParams::ConnParams()
|
|||||||
supportsContinuousUpdates(false),
|
supportsContinuousUpdates(false),
|
||||||
compressLevel(2), qualityLevel(-1), fineQualityLevel(-1),
|
compressLevel(2), qualityLevel(-1), fineQualityLevel(-1),
|
||||||
subsampling(subsampleUndefined), name_(0), verStrPos(0),
|
subsampling(subsampleUndefined), name_(0), verStrPos(0),
|
||||||
ledState_(ledUnknown)
|
ledState_(ledUnknown), shandler(NULL)
|
||||||
{
|
{
|
||||||
memset(kasmPassed, 0, KASM_NUM_SETTINGS);
|
memset(kasmPassed, 0, KASM_NUM_SETTINGS);
|
||||||
setName("");
|
setName("");
|
||||||
@@ -124,6 +125,8 @@ void ConnParams::setEncodings(int nEncodings, const rdr::S32* encodings)
|
|||||||
encodings_.clear();
|
encodings_.clear();
|
||||||
encodings_.insert(encodingRaw);
|
encodings_.insert(encodingRaw);
|
||||||
|
|
||||||
|
bool canChangeSettings = !shandler || shandler->canChangeKasmSettings();
|
||||||
|
|
||||||
for (int i = nEncodings-1; i >= 0; i--) {
|
for (int i = nEncodings-1; i >= 0; i--) {
|
||||||
switch (encodings[i]) {
|
switch (encodings[i]) {
|
||||||
case encodingCopyRect:
|
case encodingCopyRect:
|
||||||
@@ -184,11 +187,11 @@ void ConnParams::setEncodings(int nEncodings, const rdr::S32* encodings)
|
|||||||
subsampling = subsample16X;
|
subsampling = subsample16X;
|
||||||
break;
|
break;
|
||||||
case pseudoEncodingPreferBandwidth:
|
case pseudoEncodingPreferBandwidth:
|
||||||
if (!rfb::Server::ignoreClientSettingsKasm)
|
if (!rfb::Server::ignoreClientSettingsKasm && canChangeSettings)
|
||||||
Server::preferBandwidth.setParam();
|
Server::preferBandwidth.setParam();
|
||||||
break;
|
break;
|
||||||
case pseudoEncodingMaxVideoResolution:
|
case pseudoEncodingMaxVideoResolution:
|
||||||
if (!rfb::Server::ignoreClientSettingsKasm)
|
if (!rfb::Server::ignoreClientSettingsKasm && canChangeSettings)
|
||||||
kasmPassed[KASM_MAX_VIDEO_RESOLUTION] = true;
|
kasmPassed[KASM_MAX_VIDEO_RESOLUTION] = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -205,7 +208,7 @@ void ConnParams::setEncodings(int nEncodings, const rdr::S32* encodings)
|
|||||||
encodings[i] <= pseudoEncodingFineQualityLevel100)
|
encodings[i] <= pseudoEncodingFineQualityLevel100)
|
||||||
fineQualityLevel = encodings[i] - pseudoEncodingFineQualityLevel0;
|
fineQualityLevel = encodings[i] - pseudoEncodingFineQualityLevel0;
|
||||||
|
|
||||||
if (!rfb::Server::ignoreClientSettingsKasm) {
|
if (!rfb::Server::ignoreClientSettingsKasm && canChangeSettings) {
|
||||||
if (encodings[i] >= pseudoEncodingJpegVideoQualityLevel0 &&
|
if (encodings[i] >= pseudoEncodingJpegVideoQualityLevel0 &&
|
||||||
encodings[i] <= pseudoEncodingJpegVideoQualityLevel9)
|
encodings[i] <= pseudoEncodingJpegVideoQualityLevel9)
|
||||||
Server::jpegVideoQuality.setParam(encodings[i] - pseudoEncodingJpegVideoQualityLevel0);
|
Server::jpegVideoQuality.setParam(encodings[i] - pseudoEncodingJpegVideoQualityLevel0);
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ namespace rfb {
|
|||||||
const int subsample8X = 4;
|
const int subsample8X = 4;
|
||||||
const int subsample16X = 5;
|
const int subsample16X = 5;
|
||||||
|
|
||||||
|
class SMsgHandler;
|
||||||
|
|
||||||
class ConnParams {
|
class ConnParams {
|
||||||
public:
|
public:
|
||||||
ConnParams();
|
ConnParams();
|
||||||
@@ -74,6 +76,8 @@ namespace rfb {
|
|||||||
const PixelFormat& pf() const { return pf_; }
|
const PixelFormat& pf() const { return pf_; }
|
||||||
void setPF(const PixelFormat& pf);
|
void setPF(const PixelFormat& pf);
|
||||||
|
|
||||||
|
void setSHandler(SMsgHandler *s) { shandler = s; }
|
||||||
|
|
||||||
const char* name() const { return name_; }
|
const char* name() const { return name_; }
|
||||||
void setName(const char* name);
|
void setName(const char* name);
|
||||||
|
|
||||||
@@ -136,6 +140,7 @@ namespace rfb {
|
|||||||
char verStr[13];
|
char verStr[13];
|
||||||
int verStrPos;
|
int verStrPos;
|
||||||
unsigned int ledState_;
|
unsigned int ledState_;
|
||||||
|
SMsgHandler *shandler;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ using namespace rfb;
|
|||||||
|
|
||||||
SMsgHandler::SMsgHandler()
|
SMsgHandler::SMsgHandler()
|
||||||
{
|
{
|
||||||
|
cp.setSHandler(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
SMsgHandler::~SMsgHandler()
|
SMsgHandler::~SMsgHandler()
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ namespace rfb {
|
|||||||
|
|
||||||
virtual void sendStats() = 0;
|
virtual void sendStats() = 0;
|
||||||
|
|
||||||
|
virtual bool canChangeKasmSettings() const = 0;
|
||||||
|
|
||||||
// InputHandler interface
|
// InputHandler interface
|
||||||
// The InputHandler methods will be called for the corresponding messages.
|
// The InputHandler methods will be called for the corresponding messages.
|
||||||
|
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ void SMsgReader::readSetMaxVideoResolution()
|
|||||||
width = is->readU16();
|
width = is->readU16();
|
||||||
height = is->readU16();
|
height = is->readU16();
|
||||||
|
|
||||||
if (!rfb::Server::ignoreClientSettingsKasm) {
|
if (!rfb::Server::ignoreClientSettingsKasm && handler->canChangeKasmSettings()) {
|
||||||
sprintf(tmp, "%ux%u", width, height);
|
sprintf(tmp, "%ux%u", width, height);
|
||||||
rfb::Server::maxVideoResolution.setParam(tmp);
|
rfb::Server::maxVideoResolution.setParam(tmp);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,9 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <wordexp.h>
|
||||||
|
|
||||||
|
#include "kasmpasswd.h"
|
||||||
|
|
||||||
using namespace rfb;
|
using namespace rfb;
|
||||||
|
|
||||||
@@ -45,6 +48,8 @@ static LogWriter vlog("VNCSConnST");
|
|||||||
|
|
||||||
static Cursor emptyCursor(0, 0, Point(0, 0), NULL);
|
static Cursor emptyCursor(0, 0, Point(0, 0), NULL);
|
||||||
|
|
||||||
|
extern rfb::StringParameter basicauth;
|
||||||
|
|
||||||
VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
|
VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
|
||||||
bool reverse)
|
bool reverse)
|
||||||
: sock(s), reverseConnection(reverse),
|
: sock(s), reverseConnection(reverse),
|
||||||
@@ -54,7 +59,7 @@ VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
|
|||||||
losslessTimer(this), kbdLogTimer(this), server(server_), updates(false),
|
losslessTimer(this), kbdLogTimer(this), server(server_), updates(false),
|
||||||
updateRenderedCursor(false), removeRenderedCursor(false),
|
updateRenderedCursor(false), removeRenderedCursor(false),
|
||||||
continuousUpdates(false), encodeManager(this, &server_->encCache),
|
continuousUpdates(false), encodeManager(this, &server_->encCache),
|
||||||
pointerEventTime(0),
|
needsPermCheck(false), pointerEventTime(0),
|
||||||
clientHasCursor(false),
|
clientHasCursor(false),
|
||||||
accessRights(AccessDefault), startTime(time(0))
|
accessRights(AccessDefault), startTime(time(0))
|
||||||
{
|
{
|
||||||
@@ -65,6 +70,25 @@ VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
|
|||||||
memset(bstats_total, 0, sizeof(bstats_total));
|
memset(bstats_total, 0, sizeof(bstats_total));
|
||||||
gettimeofday(&connStart, NULL);
|
gettimeofday(&connStart, NULL);
|
||||||
|
|
||||||
|
// Check their permissions, if applicable
|
||||||
|
kasmpasswdpath[0] = '\0';
|
||||||
|
wordexp_t wexp;
|
||||||
|
if (!wordexp(rfb::Server::kasmPasswordFile, &wexp, WRDE_NOCMD))
|
||||||
|
strncpy(kasmpasswdpath, wexp.we_wordv[0], 4096);
|
||||||
|
kasmpasswdpath[4095] = '\0';
|
||||||
|
wordfree(&wexp);
|
||||||
|
|
||||||
|
user[0] = '\0';
|
||||||
|
const char *at = strchr(peerEndpoint.buf, '@');
|
||||||
|
if (at && at - peerEndpoint.buf > 1 && at - peerEndpoint.buf < 32) {
|
||||||
|
memcpy(user, peerEndpoint.buf, at - peerEndpoint.buf);
|
||||||
|
user[at - peerEndpoint.buf] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool write, owner;
|
||||||
|
if (!getPerms(write, owner) || !write)
|
||||||
|
accessRights = (accessRights & ~(AccessPtrEvents | AccessKeyEvents | AccessSetDesktopSize));
|
||||||
|
|
||||||
// Configure the socket
|
// Configure the socket
|
||||||
setSocketTimeouts();
|
setSocketTimeouts();
|
||||||
lastEventTime = time(0);
|
lastEventTime = time(0);
|
||||||
@@ -1001,6 +1025,34 @@ bool VNCSConnectionST::isShiftPressed()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VNCSConnectionST::getPerms(bool &write, bool &owner) const
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
const char *colon = strchr(basicauth, ':');
|
||||||
|
if (!colon || colon[1]) {
|
||||||
|
// We're running without basicauth, or with both user:pass on the command line
|
||||||
|
write = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (colon && !colon[1] && user[0]) {
|
||||||
|
struct kasmpasswd_t *set = readkasmpasswd(kasmpasswdpath);
|
||||||
|
unsigned i;
|
||||||
|
for (i = 0; i < set->num; i++) {
|
||||||
|
if (!strcmp(set->entries[i].user, user)) {
|
||||||
|
write = set->entries[i].write;
|
||||||
|
owner = set->entries[i].owner;
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(set->entries);
|
||||||
|
free(set);
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
void VNCSConnectionST::writeRTTPing()
|
void VNCSConnectionST::writeRTTPing()
|
||||||
{
|
{
|
||||||
char type;
|
char type;
|
||||||
@@ -1081,6 +1133,22 @@ void VNCSConnectionST::writeFramebufferUpdate()
|
|||||||
if (isCongested())
|
if (isCongested())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Check for permission changes?
|
||||||
|
if (needsPermCheck) {
|
||||||
|
needsPermCheck = false;
|
||||||
|
|
||||||
|
bool write, owner, ret;
|
||||||
|
ret = getPerms(write, owner);
|
||||||
|
if (!ret) {
|
||||||
|
close("User was deleted");
|
||||||
|
return;
|
||||||
|
} else if (!write) {
|
||||||
|
accessRights = (accessRights & ~(AccessPtrEvents | AccessKeyEvents | AccessSetDesktopSize));
|
||||||
|
} else {
|
||||||
|
accessRights |= AccessPtrEvents | AccessKeyEvents | AccessSetDesktopSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 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
|
||||||
// need to aggregate these in order to not clog up TCP's congestion
|
// need to aggregate these in order to not clog up TCP's congestion
|
||||||
|
|||||||
@@ -102,6 +102,10 @@ namespace rfb {
|
|||||||
// or because the current cursor position has not been set by this client.
|
// or because the current cursor position has not been set by this client.
|
||||||
bool needRenderedCursor();
|
bool needRenderedCursor();
|
||||||
|
|
||||||
|
void recheckPerms() {
|
||||||
|
needsPermCheck = true;
|
||||||
|
}
|
||||||
|
|
||||||
network::Socket* getSock() { return sock; }
|
network::Socket* getSock() { return sock; }
|
||||||
void add_changed(const Region& region) { updates.add_changed(region); }
|
void add_changed(const Region& region) { updates.add_changed(region); }
|
||||||
void add_changed_all() { updates.add_changed(server->pb->getRect()); }
|
void add_changed_all() { updates.add_changed(server->pb->getRect()); }
|
||||||
@@ -179,12 +183,23 @@ namespace rfb {
|
|||||||
virtual void supportsLEDState();
|
virtual void supportsLEDState();
|
||||||
|
|
||||||
virtual void sendStats();
|
virtual void sendStats();
|
||||||
|
virtual bool canChangeKasmSettings() const {
|
||||||
|
return (accessRights & (AccessPtrEvents | AccessKeyEvents)) ==
|
||||||
|
(AccessPtrEvents | AccessKeyEvents);
|
||||||
|
}
|
||||||
|
|
||||||
// setAccessRights() allows a security package to limit the access rights
|
// setAccessRights() allows a security package to limit the access rights
|
||||||
// of a VNCSConnectioST to the server. These access rights are applied
|
// of a VNCSConnectioST to the server. These access rights are applied
|
||||||
// such that the actual rights granted are the minimum of the server's
|
// such that the actual rights granted are the minimum of the server's
|
||||||
// default access settings and the connection's access settings.
|
// default access settings and the connection's access settings.
|
||||||
virtual void setAccessRights(AccessRights ar) {accessRights=ar;}
|
virtual void setAccessRights(AccessRights ar) {
|
||||||
|
accessRights = ar;
|
||||||
|
|
||||||
|
bool write, owner;
|
||||||
|
if (!getPerms(write, owner) || !write)
|
||||||
|
accessRights = (accessRights & ~(AccessPtrEvents | AccessKeyEvents));
|
||||||
|
needsPermCheck = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Timer callbacks
|
// Timer callbacks
|
||||||
virtual bool handleTimeout(Timer* t);
|
virtual bool handleTimeout(Timer* t);
|
||||||
@@ -193,6 +208,8 @@ namespace rfb {
|
|||||||
|
|
||||||
bool isShiftPressed();
|
bool isShiftPressed();
|
||||||
|
|
||||||
|
bool getPerms(bool &write, bool &owner) const;
|
||||||
|
|
||||||
// Congestion control
|
// Congestion control
|
||||||
void writeRTTPing();
|
void writeRTTPing();
|
||||||
bool isCongested();
|
bool isCongested();
|
||||||
@@ -249,6 +266,10 @@ namespace rfb {
|
|||||||
rdr::U64 bstats_total[BS_NUM];
|
rdr::U64 bstats_total[BS_NUM];
|
||||||
struct timeval connStart;
|
struct timeval connStart;
|
||||||
|
|
||||||
|
char user[32];
|
||||||
|
char kasmpasswdpath[4096];
|
||||||
|
bool needsPermCheck;
|
||||||
|
|
||||||
time_t lastEventTime;
|
time_t lastEventTime;
|
||||||
time_t pointerEventTime;
|
time_t pointerEventTime;
|
||||||
Point pointerEventPos;
|
Point pointerEventPos;
|
||||||
|
|||||||
@@ -63,6 +63,11 @@
|
|||||||
|
|
||||||
#include <rdr/types.h>
|
#include <rdr/types.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/inotify.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <wordexp.h>
|
||||||
|
|
||||||
using namespace rfb;
|
using namespace rfb;
|
||||||
|
|
||||||
static LogWriter slog("VNCServerST");
|
static LogWriter slog("VNCServerST");
|
||||||
@@ -73,6 +78,9 @@ EncCache VNCServerST::encCache;
|
|||||||
// -=- VNCServerST Implementation
|
// -=- VNCServerST Implementation
|
||||||
//
|
//
|
||||||
|
|
||||||
|
static char kasmpasswdpath[4096];
|
||||||
|
extern rfb::StringParameter basicauth;
|
||||||
|
|
||||||
// -=- Constructors/Destructor
|
// -=- Constructors/Destructor
|
||||||
|
|
||||||
VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_)
|
VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_)
|
||||||
@@ -87,6 +95,26 @@ VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_)
|
|||||||
{
|
{
|
||||||
lastUserInputTime = lastDisconnectTime = time(0);
|
lastUserInputTime = lastDisconnectTime = time(0);
|
||||||
slog.debug("creating single-threaded server %s", name.buf);
|
slog.debug("creating single-threaded server %s", name.buf);
|
||||||
|
|
||||||
|
kasmpasswdpath[0] = '\0';
|
||||||
|
wordexp_t wexp;
|
||||||
|
if (!wordexp(rfb::Server::kasmPasswordFile, &wexp, WRDE_NOCMD))
|
||||||
|
strncpy(kasmpasswdpath, wexp.we_wordv[0], 4096);
|
||||||
|
kasmpasswdpath[4095] = '\0';
|
||||||
|
wordfree(&wexp);
|
||||||
|
|
||||||
|
if (kasmpasswdpath[0] && access(kasmpasswdpath, R_OK) == 0) {
|
||||||
|
// Set up a watch on the password file
|
||||||
|
inotifyfd = inotify_init();
|
||||||
|
if (inotifyfd < 0)
|
||||||
|
slog.error("Failed to init inotify");
|
||||||
|
|
||||||
|
int flags = fcntl(inotifyfd, F_GETFL, 0);
|
||||||
|
fcntl(inotifyfd, F_SETFL, flags | O_NONBLOCK);
|
||||||
|
|
||||||
|
if (inotify_add_watch(inotifyfd, kasmpasswdpath, IN_CLOSE_WRITE | IN_DELETE_SELF) < 0)
|
||||||
|
slog.error("Failed to set watch");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VNCServerST::~VNCServerST()
|
VNCServerST::~VNCServerST()
|
||||||
@@ -659,8 +687,34 @@ void VNCServerST::writeUpdate()
|
|||||||
encCache.clear();
|
encCache.clear();
|
||||||
encCache.enabled = clients.size() > 1;
|
encCache.enabled = clients.size() > 1;
|
||||||
|
|
||||||
|
// Check if the password file was updated
|
||||||
|
bool permcheck = false;
|
||||||
|
if (inotifyfd >= 0) {
|
||||||
|
char buf[256];
|
||||||
|
int ret = read(inotifyfd, buf, 256);
|
||||||
|
int pos = 0;
|
||||||
|
while (ret > 0) {
|
||||||
|
const struct inotify_event * const ev = (struct inotify_event *) &buf[pos];
|
||||||
|
|
||||||
|
if (ev->mask & IN_IGNORED) {
|
||||||
|
// file was deleted, set new watch
|
||||||
|
if (inotify_add_watch(inotifyfd, kasmpasswdpath, IN_CLOSE_WRITE | IN_DELETE_SELF) < 0)
|
||||||
|
slog.error("Failed to set watch");
|
||||||
|
}
|
||||||
|
|
||||||
|
permcheck = true;
|
||||||
|
|
||||||
|
ret -= sizeof(struct inotify_event) - ev->len;
|
||||||
|
pos += sizeof(struct inotify_event) - ev->len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
|
for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
|
||||||
ci_next = ci; ci_next++;
|
ci_next = ci; ci_next++;
|
||||||
|
|
||||||
|
if (permcheck)
|
||||||
|
(*ci)->recheckPerms();
|
||||||
|
|
||||||
(*ci)->add_copied(ui.copied, ui.copy_delta);
|
(*ci)->add_copied(ui.copied, ui.copy_delta);
|
||||||
(*ci)->add_copypassed(ui.copypassed);
|
(*ci)->add_copypassed(ui.copypassed);
|
||||||
(*ci)->add_changed(ui.changed);
|
(*ci)->add_changed(ui.changed);
|
||||||
|
|||||||
@@ -249,6 +249,8 @@ namespace rfb {
|
|||||||
bool disableclients;
|
bool disableclients;
|
||||||
|
|
||||||
Timer frameTimer;
|
Timer frameTimer;
|
||||||
|
|
||||||
|
int inotifyfd;
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1068,14 +1068,7 @@ export default class RFB extends EventTargetMixin {
|
|||||||
_negotiate_std_vnc_auth() {
|
_negotiate_std_vnc_auth() {
|
||||||
if (this._sock.rQwait("auth challenge", 16)) { return false; }
|
if (this._sock.rQwait("auth challenge", 16)) { return false; }
|
||||||
|
|
||||||
/* Empty passwords are allowed in VNC and since we use HTTPS basic auth, wich is superior, lets allow the bypass of the vnc password
|
// KasmVNC uses basic Auth, clear the VNC password, which is not used
|
||||||
if (!this._rfb_credentials.password) {
|
|
||||||
this.dispatchEvent(new CustomEvent(
|
|
||||||
"credentialsrequired",
|
|
||||||
{ detail: { types: ["password"] } }));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
this._rfb_credentials.password = "";
|
this._rfb_credentials.password = "";
|
||||||
|
|
||||||
// TODO(directxman12): make genDES not require an Array
|
// TODO(directxman12): make genDES not require an Array
|
||||||
|
|||||||
@@ -71,9 +71,19 @@
|
|||||||
loader.src = "vendor/browser-es-module-loader/dist/browser-es-module-loader.js";
|
loader.src = "vendor/browser-es-module-loader/dist/browser-es-module-loader.js";
|
||||||
document.head.appendChild(loader);
|
document.head.appendChild(loader);
|
||||||
});
|
});
|
||||||
window.addEventListener("load", function() {
|
|
||||||
document.getElementById("noVNC_connect_button").click();
|
let isInsideKasmVDI = false;
|
||||||
});
|
try {
|
||||||
|
isInsideKasmVDI = (window.self !== window.top);
|
||||||
|
} catch (e) {
|
||||||
|
isInsideKasmVDI = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isInsideKasmVDI) {
|
||||||
|
window.addEventListener("load", function() {
|
||||||
|
document.getElementById("noVNC_connect_button").click();
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<!-- actual script modules -->
|
<!-- actual script modules -->
|
||||||
<script type="module" crossorigin='use-credentials' src="app/ui.js"></script>
|
<script type="module" crossorigin='use-credentials' src="app/ui.js"></script>
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
include_directories(${CMAKE_SOURCE_DIR}/common)
|
include_directories(${CMAKE_SOURCE_DIR}/common)
|
||||||
|
|
||||||
add_executable(kasmvncpasswd
|
add_executable(kasmvncpasswd
|
||||||
kasmvncpasswd.c)
|
kasmvncpasswd.c
|
||||||
|
kasmpasswd.c)
|
||||||
|
|
||||||
target_link_libraries(kasmvncpasswd crypt)
|
target_link_libraries(kasmvncpasswd crypt)
|
||||||
|
|
||||||
|
|||||||
117
unix/kasmvncpasswd/kasmpasswd.c
Normal file
117
unix/kasmvncpasswd/kasmpasswd.c
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
#include <limits.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "kasmpasswd.h"
|
||||||
|
|
||||||
|
struct kasmpasswd_t *readkasmpasswd(const char path[]) {
|
||||||
|
|
||||||
|
struct kasmpasswd_t *set = calloc(sizeof(struct kasmpasswd_t), 1);
|
||||||
|
FILE *f = fopen(path, "r");
|
||||||
|
if (!f)
|
||||||
|
return set;
|
||||||
|
|
||||||
|
// Count lines
|
||||||
|
unsigned lines = 0;
|
||||||
|
char buf[4096];
|
||||||
|
|
||||||
|
while (fgets(buf, 4096, f)) {
|
||||||
|
lines++;
|
||||||
|
}
|
||||||
|
|
||||||
|
rewind(f);
|
||||||
|
|
||||||
|
set->entries = calloc(sizeof(struct kasmpasswd_entry_t), lines);
|
||||||
|
|
||||||
|
unsigned cur = 0;
|
||||||
|
while (fgets(buf, 4096, f)) {
|
||||||
|
char *lim = strchr(buf, ':');
|
||||||
|
if (!lim)
|
||||||
|
continue;
|
||||||
|
*lim = '\0';
|
||||||
|
lim++;
|
||||||
|
|
||||||
|
const char * const pw = lim;
|
||||||
|
|
||||||
|
lim = strchr(lim, ':');
|
||||||
|
if (!lim)
|
||||||
|
continue;
|
||||||
|
*lim = '\0';
|
||||||
|
lim++;
|
||||||
|
|
||||||
|
const char * const perms = lim;
|
||||||
|
|
||||||
|
lim = strchr(lim, '\n');
|
||||||
|
if (lim)
|
||||||
|
*lim = '\0';
|
||||||
|
|
||||||
|
if (strlen(buf) + 1 > sizeof(((struct kasmpasswd_entry_t *)0)->user)) {
|
||||||
|
fprintf(stderr, "Username %s too long\n", buf);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strlen(pw) + 1 > sizeof(((struct kasmpasswd_entry_t *)0)->password)) {
|
||||||
|
fprintf(stderr, "Password for user %s too long\n", buf);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(set->entries[cur].user, buf);
|
||||||
|
strcpy(set->entries[cur].password, pw);
|
||||||
|
|
||||||
|
if (strchr(perms, 'w'))
|
||||||
|
set->entries[cur].write = 1;
|
||||||
|
if (strchr(perms, 'o'))
|
||||||
|
set->entries[cur].owner = 1;
|
||||||
|
|
||||||
|
cur++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
set->num = cur;
|
||||||
|
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
void writekasmpasswd(const char path[], const struct kasmpasswd_t *set) {
|
||||||
|
char tmpname[PATH_MAX];
|
||||||
|
|
||||||
|
if (!set || !set->entries || !set->num)
|
||||||
|
return;
|
||||||
|
|
||||||
|
snprintf(tmpname, PATH_MAX, "%s.tmp", path);
|
||||||
|
tmpname[PATH_MAX - 1] = '\0';
|
||||||
|
|
||||||
|
FILE *f = fopen(tmpname, "w");
|
||||||
|
if (!f) {
|
||||||
|
fprintf(stderr, "Failed to open temp file %s\n", tmpname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char * const perms[] = {
|
||||||
|
"",
|
||||||
|
"w",
|
||||||
|
"o",
|
||||||
|
"ow"
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned i;
|
||||||
|
for (i = 0; i < set->num; i++) {
|
||||||
|
if (!set->entries[i].user[0])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
fprintf(f, "%s:%s:%s\n",
|
||||||
|
set->entries[i].user,
|
||||||
|
set->entries[i].password,
|
||||||
|
perms[set->entries[i].owner * 2 + set->entries[i].write]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fsync(fileno(f));
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
if (rename(tmpname, path))
|
||||||
|
fprintf(stderr, "Failed writing the password file %s\n", path);
|
||||||
|
chmod(path, S_IRUSR|S_IWUSR);
|
||||||
|
}
|
||||||
27
unix/kasmvncpasswd/kasmpasswd.h
Normal file
27
unix/kasmvncpasswd/kasmpasswd.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#ifndef KASMPASSWD_H
|
||||||
|
#define KASMPASSWD_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct kasmpasswd_entry_t {
|
||||||
|
char user[32];
|
||||||
|
char password[128];
|
||||||
|
unsigned char write : 1;
|
||||||
|
unsigned char owner : 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct kasmpasswd_t {
|
||||||
|
struct kasmpasswd_entry_t *entries;
|
||||||
|
unsigned num;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct kasmpasswd_t *readkasmpasswd(const char path[]);
|
||||||
|
void writekasmpasswd(const char path[], const struct kasmpasswd_t *set);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern C
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -29,10 +29,17 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <wordexp.h>
|
#include <wordexp.h>
|
||||||
|
|
||||||
|
#include "kasmpasswd.h"
|
||||||
|
|
||||||
static void usage(const char *prog)
|
static void usage(const char *prog)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Usage: %s [file]\n", prog);
|
fprintf(stderr, "Usage: %s -u username [-wnod] [file]\n"
|
||||||
fprintf(stderr, " %s -f\n", prog);
|
"-w Write permission\n"
|
||||||
|
"-o Owner\n"
|
||||||
|
"-n Don't change password, change permissions only\n"
|
||||||
|
"-d Delete this user\n"
|
||||||
|
"\n"
|
||||||
|
"The file is updated atomically.\n", prog);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,18 +75,6 @@ static char* getpassword(const char* prompt, char *buf) {
|
|||||||
static char pw1[4096];
|
static char pw1[4096];
|
||||||
static char pw2[4096];
|
static char pw2[4096];
|
||||||
|
|
||||||
// Reads passwords from stdin and prints encrypted passwords to stdout.
|
|
||||||
static int encrypt_pipe() {
|
|
||||||
char *result = getpassword(NULL, pw1);
|
|
||||||
if (!result)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
printf("%s", encryptpw(result));
|
|
||||||
fflush(stdout);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *readpassword() {
|
static const char *readpassword() {
|
||||||
while (1) {
|
while (1) {
|
||||||
if (!getpassword("Password:", pw1)) {
|
if (!getpassword("Password:", pw1)) {
|
||||||
@@ -110,20 +105,49 @@ static const char *readpassword() {
|
|||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
char* fname = 0;
|
const char *fname = NULL;
|
||||||
|
const char *user = NULL;
|
||||||
|
const char args[] = "u:wnod";
|
||||||
|
int opt;
|
||||||
|
|
||||||
for (int i = 1; i < argc; i++) {
|
unsigned char nopass = 0, writer = 0, owner = 0, deleting = 0;
|
||||||
if (strncmp(argv[i], "-f", 2) == 0) {
|
|
||||||
return encrypt_pipe();
|
while ((opt = getopt(argc, argv, args)) != -1) {
|
||||||
} else if (argv[i][0] == '-') {
|
switch (opt) {
|
||||||
usage(argv[0]);
|
case 'u':
|
||||||
} else if (!fname) {
|
user = optarg;
|
||||||
fname = argv[i];
|
if (strlen(user) + 1 > sizeof(((struct kasmpasswd_entry_t *)0)->user)) {
|
||||||
} else {
|
fprintf(stderr, "Username %s too long\n", user);
|
||||||
usage(argv[0]);
|
exit(1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
nopass = 1;
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
writer = 1;
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
owner = 1;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
deleting = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage(argv[0]);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (deleting && (nopass || writer || owner))
|
||||||
|
usage(argv[0]);
|
||||||
|
|
||||||
|
if (!user)
|
||||||
|
usage(argv[0]);
|
||||||
|
|
||||||
|
if (optind < argc)
|
||||||
|
fname = argv[optind];
|
||||||
|
|
||||||
if (!fname) {
|
if (!fname) {
|
||||||
wordexp_t wexp;
|
wordexp_t wexp;
|
||||||
if (!wordexp("~/.kasmpasswd", &wexp, WRDE_NOCMD) && wexp.we_wordv[0])
|
if (!wordexp("~/.kasmpasswd", &wexp, WRDE_NOCMD) && wexp.we_wordv[0])
|
||||||
@@ -133,23 +157,54 @@ int main(int argc, char** argv)
|
|||||||
if (!fname)
|
if (!fname)
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
|
|
||||||
while (1) {
|
// Action
|
||||||
|
struct kasmpasswd_t *set = readkasmpasswd(fname);
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
if (nopass) {
|
||||||
|
for (i = 0; i < set->num; i++) {
|
||||||
|
if (!strcmp(set->entries[i].user, user)) {
|
||||||
|
set->entries[i].write = writer;
|
||||||
|
set->entries[i].owner = owner;
|
||||||
|
|
||||||
|
writekasmpasswd(fname, set);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(stderr, "No user named %s found\n", user);
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
} else if (deleting) {
|
||||||
|
for (i = 0; i < set->num; i++) {
|
||||||
|
if (!strcmp(set->entries[i].user, user)) {
|
||||||
|
set->entries[i].user[0] = '\0';
|
||||||
|
|
||||||
|
writekasmpasswd(fname, set);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(stderr, "No user named %s found\n", user);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
const char *encrypted = readpassword();
|
const char *encrypted = readpassword();
|
||||||
|
for (i = 0; i < set->num; i++) {
|
||||||
FILE* fp = fopen(fname, "w");
|
if (!strcmp(set->entries[i].user, user))
|
||||||
if (!fp) {
|
break;
|
||||||
fprintf(stderr, "Couldn't open %s for writing\n", fname);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
chmod(fname, S_IRUSR|S_IWUSR);
|
|
||||||
|
|
||||||
if (fwrite(encrypted, strlen(encrypted), 1, fp) != 1) {
|
|
||||||
fprintf(stderr,"Writing to %s failed\n",fname);
|
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fp);
|
// No existing user by that name?
|
||||||
|
if (i >= set->num) {
|
||||||
|
i = set->num++;
|
||||||
|
set->entries = realloc(set->entries, set->num * sizeof(struct kasmpasswd_entry_t));
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
strcpy(set->entries[i].user, user);
|
||||||
|
strcpy(set->entries[i].password, encrypted);
|
||||||
|
set->entries[i].write = writer;
|
||||||
|
set->entries[i].owner = owner;
|
||||||
|
|
||||||
|
writekasmpasswd(fname, set);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user