I need to determine if my program is running with full administrator rights. By that I mean if uac is turned on (for win vista/7) that I need to determine if the program actually has admin rights (like if the user right clicked and selected "run as administator") and not limited by uac. How do I do this in C++?
Win9x: Everyone is "admin"
NT4: OpenThreadToken/OpenProcessToken + GetTokenInformation(...,TokenGroups,...) on DOMAIN_ALIAS_RID_ADMINS SID in a loop
2000+: OpenThreadToken/OpenProcessToken + CheckTokenMembership on DOMAIN_ALIAS_RID_ADMINS SID
Other alternatives are: IsUserAnAdmin or AccessCheck
Checking the TOKEN_ELEVATION* stuff in the token is not required for testing the current process but it is useful if you need to find out if the user could elevate because they have a split token etc.
An expansion on Anders' answer for those (like me) who are less Windows literate:
BOOL isMember;
PSID administratorsGroup = NULL;
SID_IDENTIFIER_AUTHORITY SIDAuthNT =
SECURITY_NT_AUTHORITY;
if (!AllocateAndInitializeSid(&SIDAuthNT, 2,
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&administratorsGroup))
{
throw(oops_t(GetLastError(), "AllocateAndInitializeSid"));
}
if (!CheckTokenMembership(nullptr, administratorsGroup, &isMember))
{
throw(oops_t(GetLastError(), "CheckTokenMembership"));
}
if (!isMember)
{
throw(oops_t(ERROR_ACCESS_DENIED, "Test for Admin privileges"));
}
Related
stack, I need help, JetAttachDatabase returning error -550. JET_paramRecovery is switched off. What should I do that it starts work?
I've already tried to restore instance, but I have no restore file... I don't know what should I do. Now I have code like that
sWebDataBase.err = JetGetDatabaseFileInfo(sWebDataBase.path,
&sWebDataBase.dbPageSize,
sizeof(sWebDataBase.dbPageSize),
JET_DbInfoPageSize);
ErrCheck(sWebDataBase.err, "JetSetSystemParameter, JetGetDatabaseFileInfo");
sWebDataBase.err = JetSetSystemParameter (&sWebDataBase.instance,
JET_sesidNil,
JET_paramDatabasePageSize,
sWebDataBase.dbPageSize,
NULL);
ErrCheck(sWebDataBase.err, "JetSetSystemParameter, JET_paramDatabasePageSize");
sWebDataBase.err = JetSetSystemParameterW(&sWebDataBase.instance,
JET_sesidNil,
JET_paramAlternateDatabaseRecoveryPath,
NULL,
L"C:\\Users\\Chrnykh\\AppData\\Local\\Microsoft\\Windows\\WebCache\\test1.dat");
ErrCheck(sWebDataBase.err, "JetSetSystemParameter, JET_paramAlternateDatabaseRecoveryPath");
sWebDataBase.err = JetSetSystemParameter (&sWebDataBase.instance,
JET_sesidNil,
JET_paramRecovery,
NULL,
(JET_PCWSTR)"On");
ErrCheck(sWebDataBase.err, "JetSetSystemParameter, JET_paramRecovery");
sWebDataBase.err = JetInit (&sWebDataBase.instance); //------------------------------------JetInit
ErrCheck(sWebDataBase.err, "JetInit");
sWebDataBase.err = JetBeginSession (sWebDataBase.instance,
&sWebDataBase.sesId,
NULL,
NULL);
ErrCheck(sWebDataBase.err, "JetBeginSession");
ErrCheck(sWebDataBase.err, "JetRestoreInstanceW");
sWebDataBase.err = JetAttachDatabase(sWebDataBase.sesId,
sWebDataBase.path,
JET_bitDbReadOnly);
ErrCheck(sWebDataBase.err, "JetAttachDatabaseW");
sWebDataBase.err = JetOpenDatabaseW(sWebDataBase.sesId,
sWebDataBase.path,
NULL,
&sWebDataBase.dbId,
JET_bitDbReadOnly);
ErrCheck(sWebDataBase.err, "JetOpenDatabaseW");
You shouldn't have to set JET_paramRecovery. It defaults to on. Try removing that. You also set it to "On" in the code, but your question says it was set off. It's also not a good idea to disable it, because if you modify the database and crash, then the entire database is unusable at that point. This is acceptable for a very small minority of people.
Instead of setting JET_paramAlternateDatabaseRecoveryPath, you should set the Logging path.
When you call JetInit, the database engine will examine the current log stream, and replay the operations if necessary. You'll need to set the logging directory, as well as the Checkpoint file location (confusingly called "System Path"). Then it should be able to replay the log files successfully. You may also need to set the "Log file base name", which defaults to "edb", but it can be set to any 3-character sequence.
You can also use the command-line utility esentutl.exe to replay the logs first. Use it by changing in to the directory of the log files, and running a command like esentutl.exe -r edb.
Does that make sense?
I am trying to write a program that interfaces with Windows Core Audio and WASAPI. I am having difficulty with the following couple lines.
CComHeapPtr<WCHAR> name;
hr = pAudioSessionControl->GetDisplayName(&name);
if (FAILED(hr)) {
LOG(L"IAudioSessionControl::GetDisplayName() failed: hr = 0x%08x", hr);
return -__LINE__; }
_tprintf(_T("Session Index %d, \"%s\"\n"), i, CString(name));
Outputs:
Session Index 0, "#%SystemRoot%\System32\AudioSrv.Dll,-202"
Session Index 1, ""
Session Index 2, ""
Session Index 3, ""
Press any key to continue . . .
This is with 3 programs all active and making noise. It seems i can see the system sounds program but nothing else.
Thanks for the help.
An idea from another question.
The problem should be about sessions themselves. Most programs never name their sessions, so usually sessions don't have names, and the name shown on audio mixer might be the name of the window title of sessions' owner process.
Using IAudioSessionControl2::GetProcessID and get the window title of the process through other APIs should give a reasonable name similar to the one from audio mixer.
IAudioSessionControl::GetDisplayName is proper API and it might return non-empty strings, however you might also see inactive sessions for which the strings are indeed empty. In your case you might hit inactive sessions, error code which you did not provide or otherwise incorrect API use.
This code snippet/application enumerates sessions and polls for volume changes - it prints non-empty strings.
CComHeapPtr<WCHAR> pszDisplayName;
ATLENSURE_SUCCEEDED(pSessionControl->GetDisplayName(&pszDisplayName));
_tprintf(_T("nSessionIndex %d, pszDisplayName \"%s\"\n"),
nSessionIndex, CString(pszDisplayName));
C:\AudioSessionVolumeNotification\Debug>AudioSessionVolumeNotification.exe
nSessionCount 5
nSessionIndex 0, pszDisplayName "#%SystemRoot%\System32\AudioSrv.Dll,-202"
nSessionIndex 1, pszDisplayName "Mozilla Firefox"
nSessionIndex 2, pszDisplayName "Mozilla Thunderbird"
nSessionIndex 3, pszDisplayName "Mozilla Firefox"
nSessionIndex 4, pszDisplayName ""
I'm creating a user with the NetUserAdd API. It returns successfully, the user has a User folder and I can see the username with wmic useraccount get name. However, the created user is not visible under the control panel, nor on the logon screen. I assume that I need to add the user to some group but I don't know which or how.
Here is how I create the user:
USER_INFO_1 user_info;
ZeroMemory(&user_info, sizeof(user_info));
user_info.usri1_name = userName;
user_info.usri1_password = password;
user_info.usri1_priv = USER_PRIV_USER;
user_info.usri1_flags = UF_SCRIPT | UF_DONT_EXPIRE_PASSWD;
DWORD dwLevel = 1;
DWORD dwError = 0;
NET_API_STATUS nStatus = NetUserAdd(NULL, dwLevel, (LPBYTE)&user_info, &dwError);
How can I make the user visible on the logon screen?
You have created the user but you need to add it to the users group using NetLocalGroupAddMembers.
EDIT: Just realized I was providing the method for .NET. See this example for C++.
The user was not showing up on the welcome screen because it was not added to the Users group. This is how to do it:
LOCALGROUP_MEMBERS_INFO_3 lmi3;
ZeroMemory(&lmi3, sizeof lmi3);
lmi3.lgrmi3_domainandname = user_info.usri1_name;
DWORD err = NetLocalGroupAddMembers(NULL, L"Users", 3, (LPBYTE) &lmi3, 1);
I'm trying to open the MessageStore of a user using MAPI. The weird thing is, when I run this a console application, while I'm logged with the user, everything works fine.
But when I run this as a Windows Service I get MAPI_E_NOT_FOUND when trying to open the MessageStore.
I already configured the service to run as the user.
MapiLogonEx seems to work fine and GetMsgStoreTables also gives me the correct results (I verfied that the EntryID of the MessageStore is correct).
Here's my code:
LPMAPITABLE pStoresTbl = NULL;
m_lpMAPISession->GetMsgStoresTable(0, &pStoresTbl);
// Query Collumns
LPSPropTagArray pTags = NULL;
LPSRowSet pRows = NULL;
pStoresTbl->SeekRow(BOOKMARK_BEGINNING,0,NULL);
pStoresTbl->QueryRows(
LONG_MAX,
NULL,
&pRows);
LPSBinary lpEntryID = NULL;
ULONG iprops;
for (iprops = 0; iprops < pRows->aRow[0].cValues; iprops++)
{
SPropValue sProp = pRows->aRow[0].lpProps[iprops];
if (PROP_ID(sProp.ulPropTag) == PROP_ID(PR_ENTRYID))
{
lpEntryID = &sProp.Value.bin;
break;
}
}
lpMDB = NULL;
HRESULT hres = m_lpMAPISession->OpenMsgStore(NULL,
lpEntryID->cb,
(LPENTRYID) lpEntryID->lpb,
NULL,
MDB_NO_DIALOG |
MDB_NO_MAIL | // spooler not notified of our presence
MDB_TEMPORARY | // message store not added to MAPI profile
MAPI_BEST_ACCESS,
&lpMDB);
Is that an Exchange profile? Are you sure you are opening the primary mailbox rather than the PF store?
Dmitry Streblechenko (MVP)
http://www.dimastr.com/
OutlookSpy - Outlook, CDO
and MAPI Developer Tool
Do you pass in the MAPI_NT_SERVICE flag in the MAPIINIT_0 structure when calling MAPIInitialize? I've never not passed it in when running in a service, so I'm not exactly sure what happens if you don't. The MSDN docs say it is required.
MAPI_NT_SERVICE
The caller is
running as a Windows service. Callers
that are not running as a Windows
service should not set this flag;
callers that are running as a service
must set this flag.
I want to get the process's user name and check if it is a local administrator . Or check directly if the current procees user is a local administrator
Get the current username with GetUserName(), then call NetUserGetInfo() with the server name (NULL for local) and username you just got. Pass it a USER_INFO_1 structure, and then access usri1_priv in the structure. If the value is USER_PRIV_ADMIN, then you'll know that the username is an admin.
Tested on Windows XP SP3, Windows 7 32 bit and 64 bit with admin user and non-admin user.
Code ported from equivalent C# and uses ATL windows security wrapper classes.
#include <atlbase.h>
#include <atlsecurity.h>
// The function returns true if the user who is running the
// application is a member of the Administrators group,
// which does not necessarily mean the process has admin privileges.
bool IsAdministrator(HRESULT &rHr)
{
bool bIsAdmin = false;
try
{
// Open the access token of the current process.
ATL::CAccessToken aToken;
if (!aToken.GetProcessToken(TOKEN_QUERY))
{
throw MAKE_SCODE(SEVERITY_ERROR, FACILITY_WIN32,
::GetLastError());
}
// Query for the access token's group information.
ATL::CTokenGroups groups;
if (!aToken.GetGroups(&groups))
{
throw MAKE_SCODE(SEVERITY_ERROR, FACILITY_WIN32,
::GetLastError());
}
// Iterate through the access token's groups
// looking for a match against the builtin admins group.
ATL::CSid::CSidArray groupSids;
ATL::CAtlArray<DWORD> groupAttribs;
groups.GetSidsAndAttributes(&groupSids, &groupAttribs);
for (UINT i = 0; !bIsAdmin && i < groupSids.GetCount(); ++i)
{
bIsAdmin = groupSids.GetAt(i) == ATL::Sids::Admins();
}
rHr = S_OK;
}
catch (HRESULT hr)
{
rHr = hr;
}
return bIsAdmin;
}
Presuming you're on a Window OS there's a shell function: IsUserAnAdmin
See MSDN article
This article does suggest rolling your own function though, use CheckTokenMembership. There is even a code example to help you along.