opennx/SimpleXauth.cpp
2025-08-08 20:34:09 +02:00

453 lines
12 KiB
C++

// $Id: SimpleXauth.cpp 501 2010-03-01 08:10:39Z felfert $
//
// Copyright (C) 2010 The OpenNX Team
// Author: Fritz Elfert
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU Library General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this program; if not, write to the
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#if defined(__GNUG__) && !defined(__APPLE__)
#pragma implementation "SimpleXauth.h"
#endif
// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
# if defined(__WXMSW__) || defined(APP_TESTXAUTH)
#include "SimpleXauth.h"
#include "pwcrypt.h"
#include <wx/socket.h>
#include <wx/tokenzr.h>
#include <wx/hashset.h>
#include <wx/wfstream.h>
# define XauthFamilyInternet 0 /* IPv4 */
# define XauthFamilyDECnet 1
# define XauthFamilyChaos 2
# define XauthFamilyInternet6 6 /* IPv6 */
# define XauthFamilyServerInterpreted 5
# define XauthFamilyLocal 256 /* not part of X standard (i.e. X.h) */
# define XauthFamilyWild 65535
# define XauthFamilyNetname 254 /* not part of X standard */
# define XauthFamilyKrb5Principal 253 /* Kerberos 5 principal name */
# define XauthFamilyLocalHost 252 /* for local non-net authentication */
typedef struct xauth {
unsigned short family;
unsigned short address_length;
char *address;
unsigned short number_length;
char *number;
unsigned short name_length;
char *name;
unsigned short data_length;
char *data;
} Xauth;
class SimpleXauthEntry
{
public:
SimpleXauthEntry();
SimpleXauthEntry(wxString cookie);
SimpleXauthEntry(const SimpleXauthEntry &);
~SimpleXauthEntry();
bool Read(wxInputStream &);
bool Write(wxOutputStream &);
void SetUnix(wxString name, int display);
void SetInternet(wxIPV4address addr, int display);
wxString GetKey() const;
wxString Dump() const;
private:
Xauth au;
wxIPV4address iaddr;
wxString naddr;
wxString dpystr;
void init();
bool readShort(wxInputStream &, unsigned short &);
bool readString(wxInputStream &, unsigned short &, char *&);
bool writeShort(wxOutputStream &, unsigned short);
bool writeString(wxOutputStream &, unsigned short, char *);
friend class SimpleXauthEntryHash;
friend class SimpleXauthEntryEqual;
};
SimpleXauthEntry::SimpleXauthEntry()
{
init();
}
SimpleXauthEntry::SimpleXauthEntry(wxString cookie)
{
init();
unsigned long l;
unsigned int idx = 0;
for (idx = 0; idx < cookie.Length(); idx += 2) {
if (!cookie.Mid(idx, 2).ToULong(&l, 16))
break;
au.data_length++;
}
au.data = new char[au.data_length];
for (idx = 0; idx < cookie.Length(); idx += 2) {
if (!cookie.Mid(idx, 2).ToULong(&l, 16))
break;
au.data[idx / 2] = l;
}
}
SimpleXauthEntry::SimpleXauthEntry(const SimpleXauthEntry &other)
{
memcpy(&au, &other.au, sizeof(au));
if (au.address_length && au.address) {
au.address = new char [au.address_length];
if (au.address)
memcpy(au.address, other.au.address, au.address_length);
}
if (au.number_length && au.number) {
au.number = new char [au.number_length];
if (au.number)
memcpy(au.number, other.au.number, au.number_length);
}
if (au.name_length && au.name) {
au.name = new char [au.name_length];
if (au.name)
memcpy(au.name, other.au.name, au.name_length);
}
if (au.data_length && au.data) {
au.data = new char [au.data_length];
if (au.data)
memcpy(au.data, other.au.data, au.data_length);
}
dpystr = other.dpystr;
naddr = other.naddr;
iaddr = other.iaddr;
}
SimpleXauthEntry::~SimpleXauthEntry()
{
if (au.address)
delete au.address;
if (au.number)
delete au.number;
if (au.name)
delete au.name;
if (au.data)
delete au.data;
}
void SimpleXauthEntry::init()
{
memset(&au, 0, sizeof(au));
// set our defaults
au.name = strdup("MIT-MAGIC-COOKIE-1");
au.name_length = 18;
}
wxString SimpleXauthEntry::Dump() const
{
wxString tmp;
tmp << wxT("family: ") << au.family << wxT(", addr: ");
if (au.family == XauthFamilyInternet)
tmp << iaddr.IPAddress();
else
tmp << naddr;
tmp << wxT(", dpy: ") << dpystr;
return tmp;
}
wxString SimpleXauthEntry::GetKey() const
{
wxString key;
key << au.family << wxT(":");
switch (au.family) {
case XauthFamilyInternet:
key << iaddr.IPAddress();
break;
default:
key << naddr.Upper();
break;
}
key << wxT(":") << dpystr;
return key;
}
bool SimpleXauthEntry::readShort(wxInputStream &s, unsigned short &val)
{
unsigned char buf[2];
if (s.Read(&buf, sizeof(buf)).LastRead() == sizeof(buf)) {
val = buf[0] * 256 + buf[1];
return true;
}
return false;
}
bool SimpleXauthEntry::readString(wxInputStream &s, unsigned short &len, char * &buf)
{
if (readShort(s, len)) {
if (buf) {
delete buf;
buf = NULL;
}
if (len > 0) {
buf = new char[len];
if (!buf)
return false;
return (s.Read(buf, len).LastRead() == len);
} else
return true;
}
return false;
}
bool SimpleXauthEntry::Read(wxInputStream &s)
{
char *tmp;
if (!readShort(s, au.family))
return false;
if (!readString(s, au.address_length, au.address))
return false;
if (!readString(s, au.number_length, au.number))
return false;
if (!readString(s, au.name_length, au.name))
return false;
if (!readString(s, au.data_length, au.data))
return false;
switch (au.family) {
case XauthFamilyLocal:
if (au.address_length > 0) {
tmp = new char[au.address_length + 1];
if (tmp) {
memcpy(tmp, au.address, au.address_length);
tmp[au.address_length] = '\0';
naddr = wxString(wxConvUTF8.cMB2WC(tmp));
delete tmp;
}
}
break;
case XauthFamilyInternet:
if (au.address_length == 4) {
iaddr.Hostname(wxString::Format(wxT("%d.%d.%d.%d"),
au.address[0] & 255, au.address[1] & 255,
au.address[2] & 255, au.address[3] & 255));
}
break;
default:
naddr = wxEmptyString;
for (int i = 0; i < au.address_length; i++) {
int ia = au.address[i];
naddr.Append(wxString::Format(wxT("%02x"), ia));
}
break;
}
if (au.number_length > 0) {
tmp = new char[au.number_length + 1];
if (tmp) {
memcpy(tmp, au.number, au.number_length);
tmp[au.number_length] = '\0';
dpystr = wxString(wxConvUTF8.cMB2WC(tmp));
delete tmp;
}
}
return true;
}
bool SimpleXauthEntry::writeShort(wxOutputStream &s, unsigned short val)
{
unsigned char buf[2];
buf[0] = (val & (unsigned)0xff00) >> 8;
buf[1] = val & 0xff;
return (s.Write(&buf, sizeof(buf)).LastWrite() == sizeof(buf));
}
bool SimpleXauthEntry::writeString(wxOutputStream &s, unsigned short len, char *buf)
{
if (!writeShort(s, len))
return false;
if (len > 0)
return (s.Write(buf, len).LastWrite() == len);
return true;
}
bool SimpleXauthEntry::Write(wxOutputStream &s)
{
if (!writeShort(s, au.family))
return false;
if (!writeString(s, au.address_length, au.address))
return false;
if (!writeString(s, au.number_length, au.number))
return false;
if (!writeString(s, au.name_length, au.name))
return false;
return writeString(s, au.data_length, au.data);
}
void SimpleXauthEntry::SetUnix(wxString addr, int display)
{
au.family = XauthFamilyLocal;
dpystr = wxString::Format(wxT("%d"), display);
au.number_length = dpystr.Length();
au.number = strdup((const char *)dpystr.mb_str());
naddr = addr;
if (au.address)
delete au.address;
au.address_length = naddr.Length();
au.address = strdup((const char *)naddr.To8BitData());
}
void SimpleXauthEntry::SetInternet(wxIPV4address addr, int display)
{
au.family = XauthFamilyInternet;
dpystr = wxString::Format(wxT("%d"), display);
au.number_length = dpystr.Length();
au.number = strdup((const char *)dpystr.mb_str());
iaddr = addr;
au.address_length = 4;
if (au.address)
delete au.address;
au.address = new char[4];
if (au.address) {
int i = 0;
wxStringTokenizer t(iaddr.IPAddress(), wxT("."));
while (t.HasMoreTokens() && (i < 4)) {
unsigned long l;
if (t.GetNextToken().ToULong(&l))
au.address[i++] = l;
}
}
}
class SimpleXauthEntryHash
{
public:
SimpleXauthEntryHash() { }
unsigned long operator()(const SimpleXauthEntry & k) const
{
return wxStringHash::wxCharStringHash(k.GetKey());
}
SimpleXauthEntryHash& operator=(const SimpleXauthEntryHash&) { return *this; }
};
class SimpleXauthEntryEqual
{
public:
SimpleXauthEntryEqual() { }
bool operator()(const SimpleXauthEntry& a, const SimpleXauthEntry& b) const
{
return a.GetKey().IsSameAs(b.GetKey());
}
SimpleXauthEntryEqual& operator=(const SimpleXauthEntryEqual&) { return *this; }
};
WX_DECLARE_HASH_SET(
SimpleXauthEntry, SimpleXauthEntryHash, SimpleXauthEntryEqual, SimpleXauthEntrySet
);
class SimpleXauthPrivate
{
public:
SimpleXauthPrivate() {
cookie = md5sum(::wxGetUserId() + wxDateTime::Now().Format());
};
wxString filename;
wxString cookie;
SimpleXauthEntrySet entries;
};
SimpleXauth::SimpleXauth(wxString filename)
{
m_pPrivate = new SimpleXauthPrivate();
m_pPrivate->filename = filename;
readFile();
}
SimpleXauth::~SimpleXauth()
{
writeFile();
delete m_pPrivate;
}
bool SimpleXauth::readFile()
{
wxLogNull nolog;
wxFileInputStream s(m_pPrivate->filename);
while (s.IsOk()) {
SimpleXauthEntry e;
if (!e.Read(s))
return (m_pPrivate->entries.size() > 0);
m_pPrivate->entries.insert(e);
}
return false;
}
bool SimpleXauth::writeFile()
{
wxFileOutputStream s(m_pPrivate->filename);
if (s.IsOk()) {
SimpleXauthEntrySet::iterator it = m_pPrivate->entries.begin();
for (; it != m_pPrivate->entries.end(); ++it) {
if (!it->Write(s))
return false;
}
return true;
}
return false;
}
wxString SimpleXauth::GetCookie()
{
return m_pPrivate->cookie;
}
void SimpleXauth::AddDisplay(int displayNum)
{
// We always add the following 3 variants (suitable
// for both Xming and NXWin):
// localhost:X
// ipaddress:X
// localname/unix:X
wxString host = ::wxGetFullHostName();
wxIPV4address a;
a.Hostname(host);
SimpleXauthEntry e(m_pPrivate->cookie);
e.SetInternet(a, displayNum);
m_pPrivate->entries.insert(e);
a.LocalHost();
e.SetInternet(a, displayNum);
m_pPrivate->entries.insert(e);
e.SetUnix(host.BeforeFirst(wxT('.')), displayNum);
m_pPrivate->entries.insert(e);
}
#endif