Browse Source

Return static char buffer from some methods

This mimics how some system functions (like inet_ntop()) work, and
avoids complexity around ownership of the returned string buffer.

The downside is that the string must be consumed directly as it will be
overwritten on the next call, but that is not an issue with the current
usage.
pull/1587/head
Pierre Ossman 1 year ago
parent
commit
5c1ac16776

+ 2
- 2
common/network/Socket.h View File

@@ -49,8 +49,8 @@ namespace network {
void cork(bool enable) { outstream->cork(enable); }

// information about the remote end of the socket
virtual char* getPeerAddress() = 0; // a string e.g. "192.168.0.1"
virtual char* getPeerEndpoint() = 0; // <address>::<port>
virtual const char* getPeerAddress() = 0; // a string e.g. "192.168.0.1"
virtual const char* getPeerEndpoint() = 0; // <address>::<port>

// Was there a "?" in the ConnectionFilter used to accept this Socket?
void setRequiresQuery();

+ 16
- 19
common/network/TcpSocket.cxx View File

@@ -211,17 +211,17 @@ TcpSocket::TcpSocket(const char *host, int port)
enableNagles(false);
}

char* TcpSocket::getPeerAddress() {
const char* TcpSocket::getPeerAddress() {
vnc_sockaddr_t sa;
socklen_t sa_size = sizeof(sa);

if (getpeername(getFd(), &sa.u.sa, &sa_size) != 0) {
vlog.error("unable to get peer name for socket");
return rfb::strDup("");
return "";
}

if (sa.u.sa.sa_family == AF_INET6) {
char buffer[INET6_ADDRSTRLEN + 2];
static char buffer[INET6_ADDRSTRLEN + 2];
int ret;

buffer[0] = '[';
@@ -231,12 +231,12 @@ char* TcpSocket::getPeerAddress() {
NI_NUMERICHOST);
if (ret != 0) {
vlog.error("unable to convert peer name to a string");
return rfb::strDup("");
return "";
}

strcat(buffer, "]");

return rfb::strDup(buffer);
return buffer;
}

if (sa.u.sa.sa_family == AF_INET) {
@@ -245,18 +245,18 @@ char* TcpSocket::getPeerAddress() {
name = inet_ntoa(sa.u.sin.sin_addr);
if (name == NULL) {
vlog.error("unable to convert peer name to a string");
return rfb::strDup("");
return "";
}

return rfb::strDup(name);
return name;
}

vlog.error("unknown address family for socket");
return rfb::strDup("");
return "";
}

char* TcpSocket::getPeerEndpoint() {
rfb::CharArray address; address.buf = getPeerAddress();
const char* TcpSocket::getPeerEndpoint() {
static char buffer[INET6_ADDRSTRLEN + 2 + 32];
vnc_sockaddr_t sa;
socklen_t sa_size = sizeof(sa);
int port;
@@ -270,9 +270,8 @@ char* TcpSocket::getPeerEndpoint() {
else
port = 0;

int buflen = strlen(address.buf) + 32;
char* buffer = new char[buflen];
sprintf(buffer, "%s::%d", address.buf, port);
sprintf(buffer, "%s::%d", getPeerAddress(), port);

return buffer;
}

@@ -569,33 +568,31 @@ patternMatchIP(const TcpFilter::Pattern& pattern, vnc_sockaddr_t *sa) {

bool
TcpFilter::verifyConnection(Socket* s) {
rfb::CharArray name;
vnc_sockaddr_t sa;
socklen_t sa_size = sizeof(sa);

if (getpeername(s->getFd(), &sa.u.sa, &sa_size) != 0)
return false;

name.buf = s->getPeerAddress();
std::list<TcpFilter::Pattern>::iterator i;
for (i=filter.begin(); i!=filter.end(); i++) {
if (patternMatchIP(*i, &sa)) {
switch ((*i).action) {
case Accept:
vlog.debug("ACCEPT %s", name.buf);
vlog.debug("ACCEPT %s", s->getPeerAddress());
return true;
case Query:
vlog.debug("QUERY %s", name.buf);
vlog.debug("QUERY %s", s->getPeerAddress());
s->setRequiresQuery();
return true;
case Reject:
vlog.debug("REJECT %s", name.buf);
vlog.debug("REJECT %s", s->getPeerAddress());
return false;
}
}
}

vlog.debug("[REJECT] %s", name.buf);
vlog.debug("[REJECT] %s", s->getPeerAddress());
return false;
}


+ 2
- 2
common/network/TcpSocket.h View File

@@ -55,8 +55,8 @@ namespace network {
TcpSocket(int sock);
TcpSocket(const char *name, int port);

virtual char* getPeerAddress();
virtual char* getPeerEndpoint();
virtual const char* getPeerAddress();
virtual const char* getPeerEndpoint();

protected:
bool enableNagles(bool enable);

+ 8
- 8
common/network/UnixSocket.cxx View File

@@ -74,8 +74,8 @@ UnixSocket::UnixSocket(const char *path)
setFd(sock);
}

char* UnixSocket::getPeerAddress() {
struct sockaddr_un addr;
const char* UnixSocket::getPeerAddress() {
static struct sockaddr_un addr;
socklen_t salen;

// AF_UNIX only has a single address (the server side).
@@ -85,27 +85,27 @@ char* UnixSocket::getPeerAddress() {
salen = sizeof(addr);
if (getpeername(getFd(), (struct sockaddr *)&addr, &salen) != 0) {
vlog.error("unable to get peer name for socket");
return rfb::strDup("");
return "";
}

if (salen > offsetof(struct sockaddr_un, sun_path))
return rfb::strDup(addr.sun_path);
return addr.sun_path;

salen = sizeof(addr);
if (getsockname(getFd(), (struct sockaddr *)&addr, &salen) != 0) {
vlog.error("unable to get local name for socket");
return rfb::strDup("");
return "";
}

if (salen > offsetof(struct sockaddr_un, sun_path))
return rfb::strDup(addr.sun_path);
return addr.sun_path;

// socketpair() will create unnamed sockets

return rfb::strDup("(unnamed UNIX socket)");
return "(unnamed UNIX socket)";
}

char* UnixSocket::getPeerEndpoint() {
const char* UnixSocket::getPeerEndpoint() {
return getPeerAddress();
}


+ 2
- 2
common/network/UnixSocket.h View File

@@ -38,8 +38,8 @@ namespace network {
UnixSocket(int sock);
UnixSocket(const char *name);

virtual char* getPeerAddress();
virtual char* getPeerEndpoint();
virtual const char* getPeerAddress();
virtual const char* getPeerEndpoint();
};

class UnixListener : public SocketListener {

+ 28
- 33
common/os/os.cxx View File

@@ -1,4 +1,5 @@
/* Copyright (C) 2010 TightVNC Team. All Rights Reserved.
* Copyright 2021-2023 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,6 +27,8 @@

#ifndef WIN32
#include <pwd.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
@@ -36,20 +39,18 @@
#include <shlobj.h>
#endif

static int gethomedir(char **dirp, bool userDir)
static const char* gethomedir(bool userDir)
{
static char dir[PATH_MAX];

#ifndef WIN32
char *homedir, *dir;
size_t len;
char *homedir;
uid_t uid;
struct passwd *passwd;
#else
char *dir;
BOOL ret;
#endif

assert(dirp != NULL && *dirp == NULL);

#ifndef WIN32
homedir = getenv("HOME");
if (homedir == NULL) {
@@ -57,51 +58,45 @@ static int gethomedir(char **dirp, bool userDir)
passwd = getpwuid(uid);
if (passwd == NULL) {
/* Do we want emit error msg here? */
return -1;
return NULL;
}
homedir = passwd->pw_dir;
}

len = strlen(homedir);
dir = new char[len+7];
if (dir == NULL)
return -1;

memcpy(dir, homedir, len);
if (userDir)
dir[len]='\0';
else
memcpy(dir + len, "/.vnc/\0", 7);
#else
dir = new char[MAX_PATH];
if (dir == NULL)
return -1;
return homedir;

snprintf(dir, sizeof(dir), "%s/.vnc/", homedir);

return dir;
#else
if (userDir)
ret = SHGetSpecialFolderPath(NULL, dir, CSIDL_PROFILE, FALSE);
else
ret = SHGetSpecialFolderPath(NULL, dir, CSIDL_APPDATA, FALSE);

if (ret == FALSE) {
delete [] dir;
return -1;
}
if (ret == FALSE)
return NULL;

if (userDir)
dir[strlen(dir)+1] = '\0';
else
memcpy(dir+strlen(dir), "\\vnc\\\0", 6);
return dir;

if (strlen(dir) + strlen("\\vnc\\") >= sizeof(dir))
return NULL;

strcat(dir, "\\vnc\\");

return dir;
#endif
*dirp = dir;
return 0;
}

int getvnchomedir(char **dirp)
const char* getvnchomedir()
{
return gethomedir(dirp, false);
return gethomedir(false);
}

int getuserhomedir(char **dirp)
const char* getuserhomedir()
{
return gethomedir(dirp, true);
return gethomedir(true);
}


+ 5
- 8
common/os/os.h View File

@@ -1,4 +1,5 @@
/* Copyright (C) 2010 TightVNC Team. All Rights Reserved.
* Copyright 2021-2023 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,21 +25,17 @@
* If HOME environment variable is set then it is used.
* Otherwise home directory is obtained via getpwuid function.
*
* Returns:
* 0 - Success
* -1 - Failure
* Returns NULL on failure.
*/
int getvnchomedir(char **dirp);
const char* getvnchomedir();

/*
* Get user home directory.
* If HOME environment variable is set then it is used.
* Otherwise home directory is obtained via getpwuid function.
*
* Returns:
* 0 - Success
* -1 - Failure
* Returns NULL on failure.
*/
int getuserhomedir(char **dirp);
const char* getuserhomedir();

#endif /* OS_OS_H */

+ 6
- 8
common/rfb/CSecurityTLS.cxx View File

@@ -76,15 +76,14 @@ static LogWriter vlog("TLS");
static const char* homedirfn(const char* fn)
{
static char full_path[PATH_MAX];
char* homedir = NULL;
const char* homedir;

if (getvnchomedir(&homedir) == -1)
homedir = getvnchomedir();
if (homedir == NULL)
return "";

snprintf(full_path, sizeof(full_path), "%s%s", homedir, fn);

delete [] homedir;

return full_path;
}

@@ -310,7 +309,7 @@ void CSecurityTLS::checkSession()
unsigned int cert_list_size = 0;
int err;

char *homeDir;
const char *homeDir;
gnutls_datum_t info;
size_t len;

@@ -390,15 +389,14 @@ void CSecurityTLS::checkSession()

/* Certificate is fine, except we don't know the issuer, so TOFU time */

homeDir = NULL;
if (getvnchomedir(&homeDir) == -1) {
homeDir = getvnchomedir();
if (homeDir == NULL) {
throw AuthFailureException("Could not obtain VNC home directory "
"path for known hosts storage");
}

CharArray dbPath(strlen(homeDir) + 16 + 1);
sprintf(dbPath.buf, "%sx509_known_hosts", homeDir);
delete [] homeDir;

err = gnutls_verify_stored_pubkey(dbPath.buf, NULL,
client->getServerName(), NULL,

+ 1
- 1
common/rfb/VNCSConnectionST.cxx View File

@@ -59,7 +59,7 @@ VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
pointerEventTime(0), clientHasCursor(false)
{
setStreams(&sock->inStream(), &sock->outStream());
peerEndpoint.buf = sock->getPeerEndpoint();
peerEndpoint.buf = strDup(sock->getPeerEndpoint());

// Kick off the idle timer
if (rfb::Server::idleTimeout) {

+ 5
- 9
common/rfb/VNCServerST.cxx View File

@@ -131,9 +131,9 @@ void VNCServerST::addSocket(network::Socket* sock, bool outgoing)
{
// - Check the connection isn't black-marked
// *** do this in getSecurity instead?
CharArray address(sock->getPeerAddress());
if (blHosts->isBlackmarked(address.buf)) {
connectionsLog.error("blacklisted: %s", address.buf);
const char *address = sock->getPeerAddress();
if (blHosts->isBlackmarked(address)) {
connectionsLog.error("blacklisted: %s", address);
try {
rdr::OutStream& os = sock->outStream();

@@ -151,9 +151,7 @@ void VNCServerST::addSocket(network::Socket* sock, bool outgoing)
return;
}

CharArray name;
name.buf = sock->getPeerEndpoint();
connectionsLog.status("accepted: %s", name.buf);
connectionsLog.status("accepted: %s", sock->getPeerEndpoint());

// Adjust the exit timers
if (rfb::Server::maxConnectionTime && clients.empty())
@@ -651,9 +649,7 @@ void VNCServerST::queryConnection(VNCSConnectionST* client,
const char* userName)
{
// - Authentication succeeded - clear from blacklist
CharArray name;
name.buf = client->getSock()->getPeerAddress();
blHosts->clearBlackmark(name.buf);
blHosts->clearBlackmark(client->getSock()->getPeerAddress());

// - Prepare the desktop for that the client will start requiring
// resources after this

+ 2
- 3
unix/vncpasswd/vncpasswd.cxx View File

@@ -146,15 +146,14 @@ int main(int argc, char** argv)
}

if (!fname) {
char *homeDir = NULL;
if (getvnchomedir(&homeDir) == -1) {
const char *homeDir = getvnchomedir();
if (homeDir == NULL) {
fprintf(stderr, "Can't obtain VNC home directory\n");
exit(1);
}
mkdir(homeDir, 0777);
fname = new char[strlen(homeDir) + 7];
sprintf(fname, "%spasswd", homeDir);
delete [] homeDir;
}

while (true) {

+ 2
- 2
unix/x0vncserver/XDesktop.cxx View File

@@ -327,9 +327,9 @@ void XDesktop::queryConnection(network::Socket* sock,

queryConnectSock = sock;

CharArray address(sock->getPeerAddress());
delete queryConnectDialog;
queryConnectDialog = new QueryConnectDialog(dpy, address.buf,
queryConnectDialog = new QueryConnectDialog(dpy,
sock->getPeerAddress(),
userName,
queryConnectTimeout,
this);

+ 1
- 1
unix/xserver/hw/vnc/XserverDesktop.cc View File

@@ -172,7 +172,7 @@ void XserverDesktop::queryConnection(network::Socket* sock,
return;
}

queryConnectAddress.replaceBuf(sock->getPeerAddress());
queryConnectAddress.replaceBuf(strDup(sock->getPeerAddress()));
if (!userName)
userName = "(anonymous)";
queryConnectUsername.replaceBuf(strDup(userName));

+ 1
- 2
vncviewer/CConn.cxx View File

@@ -32,7 +32,6 @@
#include <rfb/Hostname.h>
#include <rfb/LogWriter.h>
#include <rfb/Security.h>
#include <rfb/util.h>
#include <rfb/screenTypes.h>
#include <rfb/fenceTypes.h>
#include <rfb/Timer.h>
@@ -99,7 +98,7 @@ CConn::CConn(const char* vncServerName, network::Socket* socket=NULL)
#ifndef WIN32
if (strchr(vncServerName, '/') != NULL) {
sock = new network::UnixSocket(vncServerName);
serverHost = sock->getPeerAddress();
serverHost = strDup(sock->getPeerAddress());
vlog.info(_("Connected to socket %s"), serverHost);
} else
#endif

+ 6
- 8
vncviewer/ServerDialog.cxx View File

@@ -168,7 +168,7 @@ void ServerDialog::handleLoad(Fl_Widget* /*widget*/, void* data)
ServerDialog *dialog = (ServerDialog*)data;

if (!dialog->usedDir)
getuserhomedir(&(dialog->usedDir));
dialog->usedDir = strDup(getuserhomedir());

Fl_File_Chooser* file_chooser = new Fl_File_Chooser(dialog->usedDir, _("TigerVNC configuration (*.tigervnc)"),
0, _("Select a TigerVNC configuration file"));
@@ -207,7 +207,7 @@ void ServerDialog::handleSaveAs(Fl_Widget* /*widget*/, void* data)
const char* servername = dialog->serverName->value();
const char* filename;
if (!dialog->usedDir)
getuserhomedir(&dialog->usedDir);
dialog->usedDir = strDup(getuserhomedir());
Fl_File_Chooser* file_chooser = new Fl_File_Chooser(dialog->usedDir, _("TigerVNC configuration (*.tigervnc)"),
2, _("Save the TigerVNC configuration to file"));
@@ -315,13 +315,12 @@ void ServerDialog::loadServerHistory()
return;
#endif

char* homeDir = NULL;
if (getvnchomedir(&homeDir) == -1)
const char* homeDir = getvnchomedir();
if (homeDir == NULL)
throw Exception(_("Could not obtain the home directory path"));

char filepath[PATH_MAX];
snprintf(filepath, sizeof(filepath), "%s%s", homeDir, SERVER_HISTORY);
delete[] homeDir;

/* Read server history from file */
FILE* f = fopen(filepath, "r");
@@ -382,13 +381,12 @@ void ServerDialog::saveServerHistory()
return;
#endif

char* homeDir = NULL;
if (getvnchomedir(&homeDir) == -1)
const char* homeDir = getvnchomedir();
if (homeDir == NULL)
throw Exception(_("Could not obtain the home directory path"));

char filepath[PATH_MAX];
snprintf(filepath, sizeof(filepath), "%s%s", homeDir, SERVER_HISTORY);
delete[] homeDir;

/* Write server history to file */
FILE* f = fopen(filepath, "w+");

+ 4
- 6
vncviewer/parameters.cxx View File

@@ -629,12 +629,11 @@ void saveViewerParameters(const char *filename, const char *servername) {
return;
#endif
char* homeDir = NULL;
if (getvnchomedir(&homeDir) == -1)
const char* homeDir = getvnchomedir();
if (homeDir == NULL)
throw Exception(_("Could not obtain the home directory path"));

snprintf(filepath, sizeof(filepath), "%sdefault.tigervnc", homeDir);
delete[] homeDir;
} else {
snprintf(filepath, sizeof(filepath), "%s", filename);
}
@@ -734,12 +733,11 @@ char* loadViewerParameters(const char *filename) {
return loadFromReg();
#endif

char* homeDir = NULL;
if (getvnchomedir(&homeDir) == -1)
const char* homeDir = getvnchomedir();
if (homeDir == NULL)
throw Exception(_("Could not obtain the home directory path"));

snprintf(filepath, sizeof(filepath), "%sdefault.tigervnc", homeDir);
delete[] homeDir;
} else {
snprintf(filepath, sizeof(filepath), "%s", filename);
}

+ 2
- 4
vncviewer/vncviewer.cxx View File

@@ -433,15 +433,13 @@ static void init_fltk()
static void mkvnchomedir()
{
// Create .vnc in the user's home directory if it doesn't already exist
char* homeDir = NULL;

if (getvnchomedir(&homeDir) == -1) {
const char* homeDir = getvnchomedir();
if (homeDir == NULL) {
vlog.error(_("Could not obtain the home directory path"));
} else {
int result = mkdir(homeDir, 0755);
if (result == -1 && errno != EEXIST)
vlog.error(_("Could not create VNC home directory: %s"), strerror(errno));
delete [] homeDir;
}
}


+ 5
- 5
win/rfb_win32/Dialog.cxx View File

@@ -81,11 +81,11 @@ int Dialog::getItemInt(int id) {
throw rdr::Exception("unable to read dialog Int");
return result;
}
char* Dialog::getItemString(int id) {
CharArray tmp(256);
if (!GetDlgItemText(handle, id, tmp.buf, 256))
tmp.buf[0] = 0;
return tmp.takeBuf();
const char* Dialog::getItemString(int id) {
static char tmp[256];
if (!GetDlgItemText(handle, id, tmp, 256))
return "";
return tmp;
}

void Dialog::setItemChecked(int id, bool state) {

+ 1
- 1
win/rfb_win32/Dialog.h View File

@@ -77,7 +77,7 @@ namespace rfb {
// Read the states of items
bool isItemChecked(int id);
int getItemInt(int id);
char* getItemString(int id); // Recipient owns string storage
const char *getItemString(int id);
// Set the states of items
void setItemChecked(int id, bool state);

+ 7
- 7
win/rfb_win32/Service.cxx View File

@@ -462,15 +462,15 @@ DWORD rfb::win32::getServiceState(const char* name) {
return status.dwCurrentState;
}

char* rfb::win32::serviceStateName(DWORD state) {
const char* rfb::win32::serviceStateName(DWORD state) {
switch (state) {
case SERVICE_RUNNING: return strDup("Running");
case SERVICE_STOPPED: return strDup("Stopped");
case SERVICE_STOP_PENDING: return strDup("Stopping");
case SERVICE_RUNNING: return "Running";
case SERVICE_STOPPED: return "Stopped";
case SERVICE_STOP_PENDING: return "Stopping";
};
CharArray tmp(32);
sprintf(tmp.buf, "Unknown (%lu)", state);
return tmp.takeBuf();
static char tmp[32];
sprintf(tmp, "Unknown (%lu)", state);
return tmp;
}



+ 1
- 2
win/rfb_win32/Service.h View File

@@ -110,8 +110,7 @@ namespace rfb {
DWORD getServiceState(const char* name);

// -=- Convert a supplied service state value to a printable string e.g. Running, Stopped...
// The caller must delete the returned string buffer
char* serviceStateName(DWORD state);
const char* serviceStateName(DWORD state);

// -=- Routine to determine whether the host process is running a service
bool isServiceProcess();

+ 1
- 1
win/vncconfig/Connections.h View File

@@ -60,7 +60,7 @@ namespace rfb {
pattern.replaceBuf(0);
}
bool onOk() {
CharArray host(getItemString(IDC_HOST_PATTERN));
CharArray host(strDup(getItemString(IDC_HOST_PATTERN)));
CharArray newPat(strlen(host.buf)+2);
if (isItemChecked(IDC_ALLOW))
newPat.buf[0] = '+';

+ 2
- 2
win/vncconfig/PasswordDialog.cxx View File

@@ -33,8 +33,8 @@ bool PasswordDialog::showDialog(HWND owner) {
}

bool PasswordDialog::onOk() {
PlainPasswd password1(getItemString(IDC_PASSWORD1));
PlainPasswd password2(getItemString(IDC_PASSWORD2));
PlainPasswd password1(strDup(getItemString(IDC_PASSWORD1)));
PlainPasswd password2(strDup(getItemString(IDC_PASSWORD2)));
if (strcmp(password1.buf, password2.buf) != 0) {
MsgBox(0, "The supplied passwords do not match",
MB_ICONEXCLAMATION | MB_OK);

+ 1
- 1
win/winvnc/QueryConnectDialog.cxx View File

@@ -46,7 +46,7 @@ QueryConnectDialog::QueryConnectDialog(network::Socket* sock_,
VNCServerWin32* s)
: Dialog(GetModuleHandle(0)),
sock(sock_), approve(false), server(s) {
peerIp.buf = sock->getPeerAddress();
peerIp.buf = strDup(sock->getPeerAddress());
userName.buf = strDup(userName_);
}


Loading…
Cancel
Save