<commit_before>/********************************************************************************
*                                                                               *
*                           An Access Control List                              *
*                                                                               *
*********************************************************************************
*        Copyright (C) 2003 by <NAME>.   All Rights Reserved.            *
*       NOTE THAT I DO NOT PERMIT ANY OF MY CODE TO BE PROMOTED TO THE GPL      *
*********************************************************************************
* This code is free software; you can redistribute it and/or modify it under    *
* the terms of the GNU Library General Public License v2.1 as published by the  *
* Free Software Foundation EXCEPT that clause 3 does not apply ie; you may not  *
* "upgrade" this code to the GPL without my prior written permission.           *
* Please consult the file "License_Addendum2.txt" accompanying this file.       *
*                                                                               *
* This code 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.                          *
*********************************************************************************
* $Id:                                                                          *
********************************************************************************/

#include "FXACL.h"
#include "FXException.h"
#include "FXRollback.h"
#include "QDir.h"
#include "QThread.h"
#include "QTrans.h"
#include "FXFile.h"
#include "FXProcess.h"
#include "FXErrCodes.h"
#include "qvaluelist.h"
#include "qcstring.h"
#include <assert.h>
#ifndef USE_POSIX
#define USE_WINAPI
#include "WindowsGubbins.h"
#include "WinIoCtl.h"
#include "Sddl.h"
#include "Aclapi.h"
#include "Lm.h"
#include "shlobj.h"
#include "Userenv.h"
#define SECURITY_WIN32
#include "Security.h"
#include <io.h>
#endif
#ifdef USE_POSIX
#include <unistd.h>
#include <sys/stat.h>
#include <pwd.h>
#include <grp.h>
#ifdef HAVE_PAM
#include <security/pam_appl.h>
#endif
//#include <shadow.h>
#endif
#include "FXMemDbg.h"
#if defined(DEBUG) && defined(FXMEMDBG_H)
static const char *_fxmemdbg_current_file_ = __FILE__;
#endif

namespace FX {

#ifdef USE_WINAPI
class FXACLInit
{	// Cached here to speed FXACL::check()
public:
	HANDLE myprocessh;
	DWORD pssize;
	PRIVILEGE_SET *ps;
	FXACLInit()
	{
		FXERRHWIN(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY|TOKEN_DUPLICATE|TOKEN_ADJUST_PRIVILEGES, &myprocessh));
		//DWORD privsinfolen=0;
		//FXERRHWIN(GetTokenInformation(myprocessh, TokenPrivileges, NULL, privsinfolen, &privsinfolen));
		//TOKEN_PRIVILEGES *privsinfo;
		//FXERRHM(privsinfo=malloc(privsinfolen+sizeof(DWORD)));
		//FXRBOp unalloc=FXRBAlloc(privsinfo);
		//FXERRHWIN(GetTokenInformation(myprocessh, TokenPrivileges, privsinfo, privsinfolen, &privsinfolen));
		//// Stupid god damn extra DWORD ...
		//PRIVILEGE_SET *ps=(PRIVILEGE_SET *) privsinfo;
		//memmove(&ps->Privileges, &privsinfo->Privileges, privsinfolen-sizeof(DWORD));
		//ps->Control=PRIVILEGE_SET_ALL_NECESSARY;
		pssize=sizeof(PRIVILEGE_SET)+3*sizeof(LUID_AND_ATTRIBUTES);
		FXERRHM(ps=(PRIVILEGE_SET *) malloc(pssize));
		ps->PrivilegeCount=3;
		ps->Control=0;
		// Just some useful privileges
		ps->Privilege[0].Attributes=0;
		FXERRHWIN(LookupPrivilegeValue(0, SE_CHANGE_NOTIFY_NAME, &ps->Privilege[0].Luid));
		ps->Privilege[1].Attributes=0;
		FXERRHWIN(LookupPrivilegeValue(0, SE_TAKE_OWNERSHIP_NAME, &ps->Privilege[1].Luid));
		ps->Privilege[2].Attributes=0;
		FXERRHWIN(LookupPrivilegeValue(0, SE_TCB_NAME, &ps->Privilege[2].Luid));

		/*{	// Try to give ourselves the SE_TCB_NAME privilege
			HANDLE adjh;
			if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &adjh)) return;
			FXRBOp unadjh=FXRBFunc(CloseHandle, adjh);
			TOKEN_PRIVILEGES tp={ 1 };
			tp.Privileges[0].Luid=ps->Privilege[2].Luid;
			tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
			DWORD retlen=0;
			BOOL ret=AdjustTokenPrivileges(adjh, FALSE, &tp, 0, NULL, &retlen);
			ret=ret;
		}*/
	}
	~FXACLInit()
	{
		free(ps); ps=0;
		FXERRHWIN(CloseHandle(myprocessh)); myprocessh=0;
	}
};
static FXProcess_StaticInit<FXACLInit> fxaclinit("FXACLInit");
#endif



struct FXDLLLOCAL FXACLEntityPrivate
{
	FXString machine;
#ifdef USE_WINAPI
	bool win32alloc;
	SID *sid, *group;
	HANDLE token;
	void copySid(SID *osid, SID *ogroup, const FXString &_machine)
	{
		assert(IsValidSid(osid)); assert(IsValidSid(ogroup));
		DWORD len;
		win32alloc=false;
		FXERRHM(sid=(SID *) malloc((len=GetLengthSid(osid))));
		FXERRHWIN(CopySid(len, sid, osid));
		FXERRHM(group=(SID *) malloc((len=GetLengthSid(ogroup))));
		FXERRHWIN(CopySid(len, group, ogroup));
		machine=_machine;
	}
	FXACLEntityPrivate(SID *osid, SID *ogroup, const FXString &_machine) : win32alloc(false), sid(0), group(0), token(0)
	{
		FXRBOp unconstr=FXRBConstruct(this);
		copySid(osid, ogroup, _machine);
		unconstr.dismiss();
	}
	FXACLEntityPrivate(bool _win32alloc, SID *osid, SID *ogroup, const FXString &_machine) : win32alloc(_win32alloc), sid(osid), group(ogroup), token(0), machine(_machine)
	{
	}
	FXACLEntityPrivate(const FXACLEntityPrivate &o) : win32alloc(false), sid(0), group(0), token(0)
	{
		FXRBOp unconstr=FXRBConstruct(this);
		copySid(o.sid, o.group, o.machine);
		if(o.token)
		{
			FXERRHWIN(DuplicateTokenEx(o.token, 0, NULL, SecurityImpersonation, TokenImpersonation, &token));
		}
		unconstr.dismiss();
	}
	~FXACLEntityPrivate();
#endif
#ifdef USE_POSIX
	uid_t userId;	// 0=root, -1=public, -2=owner
	gid_t groupId;	// 0=root, -1=public, -2=owner
	bool amGroup, amOwner, amPublic;
	FXACLEntityPrivate(uid_t _userId, gid_t _groupId, bool _amGroup, const FXString &_machine)
		: userId(_userId), groupId(_groupId), amGroup(_amGroup), amOwner(-2==_userId), amPublic(-1==_userId), machine(_machine) { }
#endif
private:
	FXACLEntityPrivate &operator=(const FXACLEntityPrivate &);
};
#ifdef USE_WINAPI
FXACLEntityPrivate::~FXACLEntityPrivate()
{ FXEXCEPTIONDESTRUCT1 {
	if(sid)
	{
		if(win32alloc)
		{
			FreeSid(sid);
		}
		else free(sid);
		sid=0;
	}
	if(group)
	{
		if(win32alloc)
		{
			FreeSid(group);
		}
		else free(group);
		group=0;
	}
	if(token)
	{
		FXERRHWIN(CloseHandle(token));
		token=0;
	}
} FXEXCEPTIONDESTRUCT2; }
#endif

FXACLEntity::FXACLEntity() : p(0)
{
}
FXACLEntity::FXACLEntity(const FXACLEntity &o) : p(0)
{
	FXERRHM(p=new FXACLEntityPrivate(*o.p));
}
FXACLEntity::~FXACLEntity()
{ FXEXCEPTIONDESTRUCT1 {
	FXDELETE(p);
} FXEXCEPTIONDESTRUCT2; }
FXACLEntity &FXACLEntity::operator=(const FXACLEntity &o)
{
	FXDELETE(p);
	FXERRHM(p=new FXACLEntityPrivate(*o.p));
	return *this;
}
bool FXACLEntity::operator==(const FXACLEntity &o) const
{
	if(!p && !o.p) return true;
	if(!p || !o.p) return false;
	if(p==o.p) return true;
#ifdef USE_WINAPI
	return EqualSid(p->sid, o.p->sid) ? true : false;
#endif
#ifdef USE_POSIX
	if(p->amGroup || o.p->amGroup)
	{
		if(!p->amGroup || !o.p->amGroup) return false;
		return p->groupId==o.p->groupId;
	}
	return p->userId==o.p->userId;
#endif
}
bool FXACLEntity::isGroup() const
{
	if(!p) return false;
#ifdef USE_WINAPI
	SID_NAME_USE use;
	TCHAR b1[512], b2[512];
	DWORD accsize=sizeof(b1)/sizeof(TCHAR), compsize=sizeof(b2)/sizeof(TCHAR);
	FXUnicodify<> computer(p->machine);
	FXERRHWIN(LookupAccountSid(p->machine.empty() ? 0 : computer.buffer(), p->sid, b1, &accsize, b2, &compsize, &use));
	return SidTypeGroup==use || SidTypeWellKnownGroup==use;
#endif
#ifdef USE_POSIX
	return p->amGroup;
#endif
}
FXACLEntity FXACLEntity::group() const
{
	if(!p) return FXACLEntity();
	FXACLEntity ret;
#ifdef USE_WINAPI
	FXERRHM(ret.p=new FXACLEntityPrivate(p->group, p->group, p->machine));
#endif
#ifdef USE_POSIX
	FXERRHM(ret.p=new FXACLEntityPrivate(p->groupId, p->groupId, true, p->machine));
#endif
	return ret;
}
FXString FXACLEntity::asString(bool withId, bool withMachine) const
{
	if(!p) return FXString();
#ifdef USE_WINAPI
	TCHAR account[1024], computer[1024];
	DWORD accsize=sizeof(account)/sizeof(TCHAR), compsize=sizeof(computer)/sizeof(TCHAR);
	SID_NAME_USE use;
	FXUnicodify<> machine2(p->machine);
	if(!LookupAccountSid(p->machine.empty() ? 0 : machine2.buffer(), p->sid, account, &accsize, computer, &compsize, &use))
	{
		if(ERROR_NONE_MAPPED==GetLastError())
		{	// NT sometimes doesn't know a SID eg; if it's orphaned
			strcpy(account, FXString(QTrans::tr("FXACLEntity", "Unknown")).text());
			withId=true;
		}
		else
			FXERRHWIN(0);
	}
	FXString ret=withMachine ? FXString("%1/%2").arg(computer).arg(account) : FXString(account);
	if(withId)
	{
		ret.append(" {");
		LPTSTR _sidstr;
		FXERRHWIN(ConvertSidToStringSid(p->sid, &_sidstr));
		ret.append(_sidstr);
		FXERRHWIN(!LocalFree(_sidstr));
		ret.append("}");
	}
	return ret;
#endif
#ifdef USE_POSIX
	if(p->amOwner)
	{
		return p->amGroup ? QTrans::tr("FXACLEntity", "Owner group")
			: QTrans::tr("FXACLEntity", "Owner");
	}
	if(p->amPublic) return QTrans::tr("FXACLEntity", "Everything");
	int ret;
	QByteArray store(1024);
	struct passwd *_userinfo=0, userinfo={0};
	struct group *_groupinfo=0, groupinfo={0};
	if(!p->amGroup)
	{
		for(;;)
		{
			if(!(ret=getpwuid_r(p->userId, &userinfo, (char *) store.data(), store.size(), &_userinfo))) break;
			if(ret && ERANGE!=ret) FXERRHOS(-1);
			store.resize(store.size()+1024);
		}
		if(!_userinfo) memset(&userinfo, 0, sizeof(userinfo));
	}
	else
	{
		for(;;)
		{
			if(!(ret=getgrgid_r(p->groupId, &groupinfo, (char *) store.data(), store.size(), &_groupinfo))) break;
			if(ret && ERANGE!=ret) FXERRHOS(-1);
			store.resize(store.size()+1024);
		}
		if(!_groupinfo) memset(&groupinfo, 0, sizeof(groupinfo));
	}
	FXString retstr("%1");
	if(!p->amGroup) retstr.arg(FXString(userinfo.pw_name));
	else retstr.arg(FXString(groupinfo.gr_name));
	if(full)
	{
		retstr+=" {%2}";
		if(!p->amGroup) retstr.arg(userinfo.pw_uid); else retstr.arg(groupinfo.gr_gid);
	}
	return retstr;
#endif
}
bool FXACLEntity::isLoginPassword(const FXchar *password) const
{
	if(!p) return false;
#ifdef USE_WINAPI
	TCHAR account[1024], computer[1024];
	DWORD accsize=sizeof(account)/sizeof(TCHAR), compsize=sizeof(computer)/sizeof(TCHAR);
	SID_NAME_USE use;
	FXUnicodify<> machine2(p->machine);
	FXERRHWIN(LookupAccountSid(p->machine.empty() ? 0 : machine2.buffer(), p->sid, account, &accsize, computer, &compsize, &use));
	if(p->token)
	{
		FXERRHWIN(CloseHandle(p->token));
		p->token=0;
	}
	/* Needs SE_TCB_NAME privs on Win2k :(
	HANDLE usertoken;
	if(LogonUser(account, computer, password, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &usertoken))
	{
		FXERRHWIN(CloseHandle(usertoken));<commit_msg>Fix on POSIX<commit_after>/********************************************************************************
*                                                                               *
*                           An Access Control List                              *
*                                                                               *
*********************************************************************************
*        Copyright (C) 2003 by <NAME>.   All Rights Reserved.            *
*       NOTE THAT I DO NOT PERMIT ANY OF MY CODE TO BE PROMOTED TO THE GPL      *
*********************************************************************************
* This code is free software; you can redistribute it and/or modify it under    *
* the terms of the GNU Library General Public License v2.1 as published by the  *
* Free Software Foundation EXCEPT that clause 3 does not apply ie; you may not  *
* "upgrade" this code to the GPL without my prior written permission.           *
* Please consult the file "License_Addendum2.txt" accompanying this file.       *
*                                                                               *
* This code 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.                          *
*********************************************************************************
* $Id:                                                                          *
********************************************************************************/

#include "FXACL.h"
#include "FXException.h"
#include "FXRollback.h"
#include "QDir.h"
#include "QThread.h"
#include "QTrans.h"
#include "FXFile.h"
#include "FXProcess.h"
#include "FXErrCodes.h"
#include "qvaluelist.h"
#include "qcstring.h"
#include <assert.h>
#ifndef USE_POSIX
#define USE_WINAPI
#include "WindowsGubbins.h"
#include "WinIoCtl.h"
#include "Sddl.h"
#include "Aclapi.h"
#include "Lm.h"
#include "shlobj.h"
#include "Userenv.h"
#define SECURITY_WIN32
#include "Security.h"
#include <io.h>
#endif
#ifdef USE_POSIX
#include <unistd.h>
#include <sys/stat.h>
#include <pwd.h>
#include <grp.h>
#ifdef HAVE_PAM
#include <security/pam_appl.h>
#endif
//#include <shadow.h>
#endif
#include "FXMemDbg.h"
#if defined(DEBUG) && defined(FXMEMDBG_H)
static const char *_fxmemdbg_current_file_ = __FILE__;
#endif

namespace FX {

#ifdef USE_WINAPI
class FXACLInit
{	// Cached here to speed FXACL::check()
public:
	HANDLE myprocessh;
	DWORD pssize;
	PRIVILEGE_SET *ps;
	FXACLInit()
	{
		FXERRHWIN(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY|TOKEN_DUPLICATE|TOKEN_ADJUST_PRIVILEGES, &myprocessh));
		//DWORD privsinfolen=0;
		//FXERRHWIN(GetTokenInformation(myprocessh, TokenPrivileges, NULL, privsinfolen, &privsinfolen));
		//TOKEN_PRIVILEGES *privsinfo;
		//FXERRHM(privsinfo=malloc(privsinfolen+sizeof(DWORD)));
		//FXRBOp unalloc=FXRBAlloc(privsinfo);
		//FXERRHWIN(GetTokenInformation(myprocessh, TokenPrivileges, privsinfo, privsinfolen, &privsinfolen));
		//// Stupid god damn extra DWORD ...
		//PRIVILEGE_SET *ps=(PRIVILEGE_SET *) privsinfo;
		//memmove(&ps->Privileges, &privsinfo->Privileges, privsinfolen-sizeof(DWORD));
		//ps->Control=PRIVILEGE_SET_ALL_NECESSARY;
		pssize=sizeof(PRIVILEGE_SET)+3*sizeof(LUID_AND_ATTRIBUTES);
		FXERRHM(ps=(PRIVILEGE_SET *) malloc(pssize));
		ps->PrivilegeCount=3;
		ps->Control=0;
		// Just some useful privileges
		ps->Privilege[0].Attributes=0;
		FXERRHWIN(LookupPrivilegeValue(0, SE_CHANGE_NOTIFY_NAME, &ps->Privilege[0].Luid));
		ps->Privilege[1].Attributes=0;
		FXERRHWIN(LookupPrivilegeValue(0, SE_TAKE_OWNERSHIP_NAME, &ps->Privilege[1].Luid));
		ps->Privilege[2].Attributes=0;
		FXERRHWIN(LookupPrivilegeValue(0, SE_TCB_NAME, &ps->Privilege[2].Luid));

		/*{	// Try to give ourselves the SE_TCB_NAME privilege
			HANDLE adjh;
			if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &adjh)) return;
			FXRBOp unadjh=FXRBFunc(CloseHandle, adjh);
			TOKEN_PRIVILEGES tp={ 1 };
			tp.Privileges[0].Luid=ps->Privilege[2].Luid;
			tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
			DWORD retlen=0;
			BOOL ret=AdjustTokenPrivileges(adjh, FALSE, &tp, 0, NULL, &retlen);
			ret=ret;
		}*/
	}
	~FXACLInit()
	{
		free(ps); ps=0;
		FXERRHWIN(CloseHandle(myprocessh)); myprocessh=0;
	}
};
static FXProcess_StaticInit<FXACLInit> fxaclinit("FXACLInit");
#endif



struct FXDLLLOCAL FXACLEntityPrivate
{
	FXString machine;
#ifdef USE_WINAPI
	bool win32alloc;
	SID *sid, *group;
	HANDLE token;
	void copySid(SID *osid, SID *ogroup, const FXString &_machine)
	{
		assert(IsValidSid(osid)); assert(IsValidSid(ogroup));
		DWORD len;
		win32alloc=false;
		FXERRHM(sid=(SID *) malloc((len=GetLengthSid(osid))));
		FXERRHWIN(CopySid(len, sid, osid));
		FXERRHM(group=(SID *) malloc((len=GetLengthSid(ogroup))));
		FXERRHWIN(CopySid(len, group, ogroup));
		machine=_machine;
	}
	FXACLEntityPrivate(SID *osid, SID *ogroup, const FXString &_machine) : win32alloc(false), sid(0), group(0), token(0)
	{
		FXRBOp unconstr=FXRBConstruct(this);
		copySid(osid, ogroup, _machine);
		unconstr.dismiss();
	}
	FXACLEntityPrivate(bool _win32alloc, SID *osid, SID *ogroup, const FXString &_machine) : win32alloc(_win32alloc), sid(osid), group(ogroup), token(0), machine(_machine)
	{
	}
	FXACLEntityPrivate(const FXACLEntityPrivate &o) : win32alloc(false), sid(0), group(0), token(0)
	{
		FXRBOp unconstr=FXRBConstruct(this);
		copySid(o.sid, o.group, o.machine);
		if(o.token)
		{
			FXERRHWIN(DuplicateTokenEx(o.token, 0, NULL, SecurityImpersonation, TokenImpersonation, &token));
		}
		unconstr.dismiss();
	}
	~FXACLEntityPrivate();
#endif
#ifdef USE_POSIX
	uid_t userId;	// 0=root, -1=public, -2=owner
	gid_t groupId;	// 0=root, -1=public, -2=owner
	bool amGroup, amOwner, amPublic;
	FXACLEntityPrivate(uid_t _userId, gid_t _groupId, bool _amGroup, const FXString &_machine)
		: userId(_userId), groupId(_groupId), amGroup(_amGroup), amOwner(-2==_userId), amPublic(-1==_userId), machine(_machine) { }
#endif
private:
	FXACLEntityPrivate &operator=(const FXACLEntityPrivate &);
};
#ifdef USE_WINAPI
FXACLEntityPrivate::~FXACLEntityPrivate()
{ FXEXCEPTIONDESTRUCT1 {
	if(sid)
	{
		if(win32alloc)
		{
			FreeSid(sid);
		}
		else free(sid);
		sid=0;
	}
	if(group)
	{
		if(win32alloc)
		{
			FreeSid(group);
		}
		else free(group);
		group=0;
	}
	if(token)
	{
		FXERRHWIN(CloseHandle(token));
		token=0;
	}
} FXEXCEPTIONDESTRUCT2; }
#endif

FXACLEntity::FXACLEntity() : p(0)
{
}
FXACLEntity::FXACLEntity(const FXACLEntity &o) : p(0)
{
	FXERRHM(p=new FXACLEntityPrivate(*o.p));
}
FXACLEntity::~FXACLEntity()
{ FXEXCEPTIONDESTRUCT1 {
	FXDELETE(p);
} FXEXCEPTIONDESTRUCT2; }
FXACLEntity &FXACLEntity::operator=(const FXACLEntity &o)
{
	FXDELETE(p);
	FXERRHM(p=new FXACLEntityPrivate(*o.p));
	return *this;
}
bool FXACLEntity::operator==(const FXACLEntity &o) const
{
	if(!p && !o.p) return true;
	if(!p || !o.p) return false;
	if(p==o.p) return true;
#ifdef USE_WINAPI
	return EqualSid(p->sid, o.p->sid) ? true : false;
#endif
#ifdef USE_POSIX
	if(p->amGroup || o.p->amGroup)
	{
		if(!p->amGroup || !o.p->amGroup) return false;
		return p->groupId==o.p->groupId;
	}
	return p->userId==o.p->userId;
#endif
}
bool FXACLEntity::isGroup() const
{
	if(!p) return false;
#ifdef USE_WINAPI
	SID_NAME_USE use;
	TCHAR b1[512], b2[512];
	DWORD accsize=sizeof(b1)/sizeof(TCHAR), compsize=sizeof(b2)/sizeof(TCHAR);
	FXUnicodify<> computer(p->machine);
	FXERRHWIN(LookupAccountSid(p->machine.empty() ? 0 : computer.buffer(), p->sid, b1, &accsize, b2, &compsize, &use));
	return SidTypeGroup==use || SidTypeWellKnownGroup==use;
#endif
#ifdef USE_POSIX
	return p->amGroup;
#endif
}
FXACLEntity FXACLEntity::group() const
{
	if(!p) return FXACLEntity();
	FXACLEntity ret;
#ifdef USE_WINAPI
	FXERRHM(ret.p=new FXACLEntityPrivate(p->group, p->group, p->machine));
#endif
#ifdef USE_POSIX
	FXERRHM(ret.p=new FXACLEntityPrivate(p->groupId, p->groupId, true, p->machine));
#endif
	return ret;
}
FXString FXACLEntity::asString(bool withId, bool withMachine) const
{
	if(!p) return FXString();
#ifdef USE_WINAPI
	TCHAR account[1024], computer[1024];
	DWORD accsize=sizeof(account)/sizeof(TCHAR), compsize=sizeof(computer)/sizeof(TCHAR);
	SID_NAME_USE use;
	FXUnicodify<> machine2(p->machine);
	if(!LookupAccountSid(p->machine.empty() ? 0 : machine2.buffer(), p->sid, account, &accsize, computer, &compsize, &use))
	{
		if(ERROR_NONE_MAPPED==GetLastError())
		{	// NT sometimes doesn't know a SID eg; if it's orphaned
			strcpy(account, FXString(QTrans::tr("FXACLEntity", "Unknown")).text());
			withId=true;
		}
		else
			FXERRHWIN(0);
	}
	FXString ret=withMachine ? FXString("%1/%2").arg(computer).arg(account) : FXString(account);
	if(withId)
	{
		ret.append(" {");
		LPTSTR _sidstr;
		FXERRHWIN(ConvertSidToStringSid(p->sid, &_sidstr));
		ret.append(_sidstr);
		FXERRHWIN(!LocalFree(_sidstr));
		ret.append("}");
	}
	return ret;
#endif
#ifdef USE_POSIX
	if(p->amOwner)
	{
		return p->amGroup ? QTrans::tr("FXACLEntity", "Owner group")
			: QTrans::tr("FXACLEntity", "Owner");
	}
	if(p->amPublic) return QTrans::tr("FXACLEntity", "Everything");
	int ret;
	QByteArray store(1024);
	struct passwd *_userinfo=0, userinfo={0};
	struct group *_groupinfo=0, groupinfo={0};
	if(!p->amGroup)
	{
		for(;;)
		{
			if(!(ret=getpwuid_r(p->userId, &userinfo, (char *) store.data(), store.size(), &_userinfo))) break;
			if(ret && ERANGE!=ret) FXERRHOS(-1);
			store.resize(store.size()+1024);
		}
		if(!_userinfo) memset(&userinfo, 0, sizeof(userinfo));
	}
	else
	{
		for(;;)
		{
			if(!(ret=getgrgid_r(p->groupId, &groupinfo, (char *) store.data(), store.size(), &_groupinfo))) break;
			if(ret && ERANGE!=ret) FXERRHOS(-1);
			store.resize(store.size()+1024);
		}
		if(!_groupinfo) memset(&groupinfo, 0, sizeof(groupinfo));
	}
	FXString retstr("%1");
	if(!p->amGroup) retstr.arg(FXString(userinfo.pw_name));
	else retstr.arg(FXString(groupinfo.gr_name));
	if(withId)
	{
		retstr+=" {%2}";
		if(!p->amGroup) retstr.arg(userinfo.pw_uid); else retstr.arg(groupinfo.gr_gid);
	}
	return retstr;
#endif
}
bool FXACLEntity::isLoginPassword(const FXchar *password) const
{
	if(!p) return false;
#ifdef USE_WINAPI
	TCHAR account[1024], computer[1024];
	DWORD accsize=sizeof(account)/sizeof(TCHAR), compsize=sizeof(computer)/sizeof(TCHAR);
	SID_NAME_USE use;
	FXUnicodify<> machine2(p->machine);
	FXERRHWIN(LookupAccountSid(p->machine.empty() ? 0 : machine2.buffer(), p->sid, account, &accsize, computer, &compsize, &use));
	if(p->token)
	{
		FXERRHWIN(CloseHandle(p->token));
		p->token=0;
	}
	/* Needs SE_TCB_NAME privs on Win2k :(
	HANDLE usertoken;
	if(LogonUser(account, computer, password, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &usertoken))
	{
		FXERRHWIN(CloseHandle(usertoken));
{'fraction_non_alphanumeric': 0.18297460478407154, 'fraction_numerical': 0.013181545835829839, 'mean_word_length': 4.567872722607134, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 129, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 24, 'profanity_word_list.json': 2, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4959105', 'n_tokens_mistral': 8616, 'n_tokens_neox': 8090, 'n_words': 1523}