Guest account name
Posted 05 December 2007 - 11:09
I would like to activate the guest account during my install ("net user guest /active:on") and I want to work this command in any language, as the guest account changes in localized OSs.
I already looked at the SIDLookup package, which would be the right tool, but unfortunately it doesnt have a [SID_GUEST]... :-(
(BTW, in the Security Policy (secpol.msc) under "local security options" the name can be found localized: "Accounts: Rename guest account".)
How could I get a localized string for the guest account user name (e.g. Invitado, Invité, Gast, ...) in a simple way?
Thank you in advance!
Posted 05 December 2007 - 11:36
- Try using http://www.google.com before posting.
- I answer questions only via forums. Please appreciate the time I give here and don't send me personal emails.
Posted 05 December 2007 - 13:39
Well-known OS resources (exe, registry, ...) and any DLL would be okay.
Posted 06 December 2007 - 19:51
- Try using http://www.google.com before posting.
- I answer questions only via forums. Please appreciate the time I give here and don't send me personal emails.
Posted 07 December 2007 - 11:33
This method can deal with localizations (builtin accounts have names in the language of the OS) and accounts that were renamed by an admin. On the MSDN library, look for articles on "well known SIDs" and "LookupAccountSID". I believe it even has sample code to retrieve the name of the builtin Administrators group, which is close to what you want.
Note this method fails when the account was deleted. You're better off creating a new account for your purposes.
Posted 10 January 2008 - 18:29
It gives the localized string for the guest account (RID=501) in the installer property GUEST_ACCOUNT_NAME as result.
(I start with return value 4444 for errors, the only thing I'm not 100% sure about, but these codes are not in use according to the MSDN documentation.)
#include <windows.h>
#include <tchar.h>
#include <Sddl.h>
#include <Msiquery.h>
#ifdef __cplusplus /* If used by C++ code, */
extern "C" { /* we need to export the C interface */
#endif
UINT __stdcall GuestAccountName( MSIHANDLE hInstall )
{
TCHAR computerName[MAX_COMPUTERNAME_LENGTH+1]; /* NetBIOS Computer name */
PSID NewSid = NULL;
PSID Sid = NULL;
DWORD cbSid = 0;
LPTSTR ReferencedDomainName = NULL;
DWORD cbReferencedDomainName = 0;
LPTSTR accountName = NULL;
DWORD dwSize, dwResult = 0;
SID_NAME_USE SidType;
UINT ret = 0;
/**********************************************************************
* Obtain computer name (Kernel32.lib) *
***************************************/
dwSize = MAX_COMPUTERNAME_LENGTH+1;
if( !GetComputerName(computerName, &dwSize) )
return 4444;
/**********************************************************************
* Obtain computer SID (Advapi32.lib) *
**************************************/
/* 1st call: Determine string sizes, without error handling */
LookupAccountName(
NULL, /* __in_opt Machine to lookup account on. */
computerName, /* __in Address of string for account name. */
NULL, /* __out_opt Address of security identifier. */
&cbSid, /* __inout Address of size (bytes) of security identifier. */
NULL, /* __out_opt Address of string for referenced domain. */
&cbReferencedDomainName,/* __inout Address of size (TCHARs) of domain string. */
&SidType /* __out Address of SID-type indicator. */
);
Sid = (PSID)malloc( cbSid );
ReferencedDomainName = (LPTSTR)malloc( cbReferencedDomainName * sizeof(TCHAR) );
/* 2nd call: Read strings */
if( !LookupAccountName(
NULL, /* __in_opt Machine to lookup account on. */
computerName, /* __in Address of string for account name. */
Sid, /* __out_opt Address of security identifier. */
&cbSid, /* __inout Address of size (bytes) of security identifier. */
ReferencedDomainName, /* __out_opt Address of string for referenced domain. */
&cbReferencedDomainName,/* __inout Address of size (TCHARs) of domain string. */
&SidType /* __out Address of SID-type indicator. */
))
return 4445;
/* Should never fail: Computer SID must be of type "SidTypeDomain" */
if( SidType != SidTypeDomain )
return 4446;
/**********************************************************************
* Create Guest SID (well-known) (Advapi32.lib) *
************************************************/
/* Following code taken from MSDN "CreateWellKnownSid" example */
cbSid = SECURITY_MAX_SID_SIZE;
/* Allocate enough memory for the largest possible SID. */
if( !(NewSid = LocalAlloc(LMEM_FIXED, cbSid)) )
return 4447;
/* WinBuiltinGuestsSid -> Guests (group)
* WinAccountGuestSid -> computer SID requiered
* WinAccountDomainGuestsSid -> computer SID required */
if( !CreateWellKnownSid(
WinAccountGuestSid, /* __in WELL_KNOWN_SID_TYPE member*/
Sid, /* __in_opt DomainSid, identifies domain control */
NewSid, /* __out_opt pSid, output variable */
&cbSid /* __inout cbSid, no. of bytes available for pSid */
))
return 4448;
/**********************************************************************
* Obtain Guest account name (Advapi32.lib) *
********************************************/
free((void *)ReferencedDomainName);
ReferencedDomainName = 0;
/* 1st call: Determine string sizes, without error handling */
cbReferencedDomainName = 0;
dwSize = 0;
LookupAccountSid(
NULL, /* __in_opt Machine to lookup account on. */
NewSid, /* __in Address of security identifier. */
NULL, /* __out_opt Address of string for account name. */
&dwSize, /* __inout Address of size of security identifier. */
NULL, /* __out_opt Address of string for referenced domain. */
&cbReferencedDomainName,/* __inout Address of size of domain string. */
&SidType /* __out Address of SID-type indicator. */
);
accountName = (LPTSTR)malloc( dwSize * sizeof(TCHAR) );
ReferencedDomainName = (LPSTR)malloc( cbReferencedDomainName * sizeof(TCHAR) );
/* 2nd call: Read strings */
if( !LookupAccountSid(
NULL, /* __in_opt Machine to lookup account on. */
NewSid, /* __in Address of security identifier. */
accountName, /* __out_opt Address of string for account name. */
&dwSize, /* __inout Address of size of security identifier. */
ReferencedDomainName, /* __out_opt Address of string for referenced domain. */
&cbReferencedDomainName,/* __inout Address of size of domain string. */
&SidType /* __out Address of SID-type indicator. */
))
return 4449;
/**********************************************************************
* Set MSI Property (Msi.lib) *
******************************/
ret = MsiSetProperty (hInstall, _T("GUEST_ACCOUNT_NAME"), accountName);
if(ret != ERROR_SUCCESS)
return 4450;
if (NewSid)
LocalFree( NewSid );
if (Sid)
free((void *)Sid);
if (ReferencedDomainName)
free((void *)ReferencedDomainName);
if (accountName)
free((void *)accountName);
return ERROR_SUCCESS;
}
#ifdef __cplusplus
}
#endif
Posted 11 January 2008 - 10:04
In the meantime, for us mere mortals, here's a script which could easily be adapted for this purpose. 'strUser' will contain the localised name.
Edited by VBScab, 11 January 2008 - 14:01.
- Try using http://www.google.com before posting.
- I answer questions only via forums. Please appreciate the time I give here and don't send me personal emails.
Posted 11 January 2008 - 15:29
Before writing my code, originally I had a simple dialogue prompt in my installation, where the user had to give the information.
On the other hand I would have a problem, if the script engine would not run and if the installation would fail exactly because of this. I deploy code to sensible areas as hospital systems, where "script processing" could have been switched off for some reason, or where anti-virus software could block execution.
No, I'm really better off with this rooted to the soil and robust solution!
Best regards,
Pizzero
Posted 11 January 2008 - 17:15
QUOTE |
As an experienced C programmer I did not have the trouble as you might have expected VBScab. |
QUOTE |
And script programmers surely are a bit lazy with writing code at low level. |
QUOTE |
if the script engine would not run and if the installation would fail exactly because of this. I deploy code to sensible areas as hospital systems, where "script processing" could have been switched off for some reason, or where anti-virus software could block execution. |
Anyway, the point of my post was to assist those who might search the archive and be disappointed to discover only C code, when a less complex and more easily accessible solution was sought. No slight was intended, as I'm sure you realise.
Happy coding!
- Try using http://www.google.com before posting.
- I answer questions only via forums. Please appreciate the time I give here and don't send me personal emails.
Posted 12 January 2008 - 17:13
QUOTE |
Most MSI authoring tools allow you to embed the script (strictly speaking, embedded scripts are restricted in length but in practise, they're not), meaning that normal script blocking is bypassed, because WScript isn't the host, the Windows Installer engine is. Anti-virus s/w would likely not be an issue either, as MSIExec.EXE is - we hope - trusted. |
In so-called 'locked down systems' all scripting is disabled: not just in WScript/CScript, but also in IExplore, Msiexec, etc. In fact no host can do any scripting, as I found out the hard way - I developed software with a script host, and even a script debugger, included.
The anti-virus software 'blocking' solutions are in my opinion very poor: at least a few of them re-register the 'FileSystemObject' class to a class of their own. In their implementation they forward the call to the real FileSystemObject, but known harmful calls are intercepted. Nothing else is checked, so any WMI goes ahead.
Edited by Zweitze, 12 January 2008 - 17:13.
Posted 12 January 2008 - 17:27
QUOTE |
I chanced to write some code - which I'd like to post here and to share for discussion. It's working and production quality, however it's a debut feature for me, being Linux developer... |
It appears OK, but it may not work on Domain Controllers - DCs do not have accounts of their own, only Domain accounts. Therefore you cannot use the computer name to construct the SID, instead use the domain name. In other words, on a DC you should be looking for a domain guest account instead of a local guest account.
QUOTE |
(I start with return value 4444 for errors, the only thing I'm not 100% sure about, but these codes are not in use according to the MSDN documentation.) |
Well, your code 4449 just means that the account does not exist (probably deleted). But for general reference, look up whether the failing calls support GetLastError(), in that case just return that error. And when MsiSetProperty fails, consider to just return the return value of MsiSetProperty instead of 4450.
Oh, BTW when the code does fail you're stuck with a memory leak. It's not that bad when this happens in the UI sequence, but when this happens in the Execute sequence its worse (this is hosted by a service, to recover the memory you've got to restart it).
Posted 14 January 2008 - 09:55
QUOTE |
In so-called 'locked down systems' all scripting is disabled <snip> |
Edited by VBScab, 14 January 2008 - 15:40.
- Try using http://www.google.com before posting.
- I answer questions only via forums. Please appreciate the time I give here and don't send me personal emails.