winapi - GetServiceKeyName returns empty service name - c++

I'm trying to get service name from display name using winapi function GetServiceKeyName in C++ with the following code:
SC_HANDLE hSCManager = OpenSCManager(NULL,
NULL, // service control manager database
SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE |SC_MANAGER_QUERY_LOCK_STATUS | STANDARD_RIGHTS_READ);
LPTSTR lpServiceName;
LPCTSTR lpDisplayName = L"My service";
DWORD dwSizeNeeded = sizeof(lpDisplayName);
GetServiceKeyName(hSCManager, lpDisplayName, lpServiceName, &dwSizeNeeded);
After finish, dwSizeNeeded have 15 as value and lpServiceName have "". Where I'm wrong calling to this function? Need any special right here? The inconvenience here is that this app doesn't have admin rights so I cannot (I guess) set SC_MANAGER_ALL_ACCESS. Of course, My service is up and running in system, so I have not bad display name.

Two lines needs to be modified:
...
TCHAR lpServiceName[512];
DWORD dwSizeNeeded = sizeof lpServcieName / sizeof lpServiceName[0]; // Number of elements in buffer
...
You should also see what GetServiceKeyName returns as that is the signal if it has succeeded or not. Checking the string is only valid if GetServiceKeyName returns TRUE.

Related

FIDO2 C++ based application using WebAuthn.dll for "YUBIKEY 5 NFC" (External authenticator) gives "The parameter is incorrect"

I am writing FIDO2 C++ based application using WebAuthn.dll for "YUBIKEY 5 NFC" (External authenticator) using the following WebAuthN APIs of Microsoft from the
https://github.com/microsoft/webauthn/blob/master/webauthn.h
I'm trying to Authenticate with the api WebAuthNAuthenticatorGetAssertion(). I get the error "The parameter is incorrect"
HWND hWnd = GetForegroundWindow();
LPCWSTR pwszRpId = nullptr;
std::string sClientData64 = {"type":"webauthn.get","challenge":"<< base64 Encoded
challenge","crossOrigin":true};
WEBAUTHN_CLIENT_DATA oClientData_in = { WEBAUTHN_CLIENT_DATA_CURRENT_VERSION,
static_cast<DWORD>(sClientData64.length()),
(PBYTE)(sClientData64.data()),
WEBAUTHN_HASH_ALGORITHM_SHA_256
};
WEBAUTHN_CREDENTIAL_EX webCredEx = { WEBAUTHN_CREDENTIAL_EX_CURRENT_VERSION,
static_cast<DWORD>(CredentialId.length()),
((BYTE*)(CredentialId.c_str())),
WEBAUTHN_CREDENTIAL_TYPE_PUBLIC_KEY,
WEBAUTHN_CTAP_TRANSPORT_USB
};
WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS webAuthNGetAssertionOptions = {
WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_CURRENT_VERSION, // version
timeOut, // time in milliseconds
{0, NULL}, //WEBAUTHN_CREDENTIALS
{0, NULL}, //WEBAUTHN_EXTENSIONS
WEBAUTHN_AUTHENTICATOR_ATTACHMENT_ANY, // for Platform (Windows Hello) vs
Cross platform authenticator (Yubikey)
WEBAUTHN_USER_VERIFICATION_REQUIREMENT_ANY, // user Verification
Required (preferred)
0, // dwFlags
NULL, // as json data received it is null
nullptr, //(FALSE) this is a pointer
NULL, // pCancellationId
pAllowCredentialList // dwversion = 4) allowlist is not null
};
WEBAUTHN_ASSERTION* pWebAuthNAssertion = nullptr; // this is an output parameter,
// on calling, I get a dialog popup saying " The parameter is incorrect."
hResult = WebAuthNAuthenticatorGetAssertion(hWnd, pwszRpId &oClientData_in,
&webAuthNAssertionOptions, &pWebAuthNAssertion);
Please let me know, if any thing has to added in my code.
My guess is pAllowCredentialList in the webAuthNGetAssertionOptions is the culprit. Does it work with NULL instead?
I have a similar very simple sample at https://github.com/aseigler/HelloSample/blob/master/hello/hello.cpp that worked last time I checked.

Append to a User Environment Variable with RegSetValueEx() in C++

I want to append a new path to an existing environment variable with c++. This should be for the current user (if you can provide an example for the Local_Machine, that will also be acceptable).
The path(new) and the variable(already existing) are
variable = Cur
path = E:\Softwares\Setup
What i have tried
void SetUserVariablePath(){
HKEY hkey;
long regOpenResult;
const char key_name[] = "Environment";
const char path[]="E:\\Softwares\\Setup;"; //new path
LPCSTR stuff = "Cur"; //Variable Name
// here we open the variable and set the value
regOpenResult = RegOpenKeyEx(HKEY_CURRENT_USER,key_name, 0, KEY_ALL_ACCESS, &hkey);
RegSetValueEx(hkey,stuff,0,REG_EXPAND_SZ,(BYTE*) path, strlen(path)+1);
// tell other process to update their env values
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM)"Environment", SMTO_BLOCK, 100, NULL);
// close the registery key
RegCloseKey(hkey);
}
I have followed how-to-add-environment-variable-in-c for the above code.The code does work and sets the environment variable for the current user but it also over-rides any existing paths already present, What i want to do is to append to the existing paths.
Things that dont answer my question
I am not taking about setting the variable for the current/child process(that can be done with setenv() or _putenv() function).
I have already looked at these questions and they don't answer my question. Update system environment variable from c++ and Set system variable from C++
I followed up to #john recommendations and got the working code as follows
void appendReg()
{
// commons
static const char sysVar[] = "Cur" ; // Variable Name
const char key_name[] = "Environment";
// first read the current value of registery
static BYTE curRegVal[1000000]; // will store the reg value
DWORD curRegValCP = sizeof(curRegVal) ;
HKEY readKey;
RegOpenKeyExA( HKEY_CURRENT_USER, key_name, 0, KEY_QUERY_VALUE, &readKey);
RegQueryValueExA( readKey, sysVar, nullptr, nullptr, curRegVal, &curRegValCP);
RegCloseKey(readKey);
// curRegVal now has the current reg value
std::cout<<"\nCurrent Reg value is = > "<< reinterpret_cast<const char*>(curRegVal);
// second append the new path value to current value
const char appendedVal[1000000]="C:\\New\\Dir\\To\\Be\\Appended;"; // to be appended
strcat(appendedVal,curRegVal); // concatenate the current and new values
std::cout<<"\nAppended Reg value is => "<<appendedVal;
// third set the new(appended) value for registery and broadcast changes to other processes
HKEY writeKey;
RegOpenKeyEx(HKEY_CURRENT_USER,key_name, 0, KEY_ALL_ACCESS, &writeKey);
RegSetValueEx(writeKey,(LPCSTR)sysVar,0,REG_EXPAND_SZ,(BYTE*) appendedVal, strlen(appendedVal)+1);
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM)key_name, SMTO_BLOCK, 100, NULL); // tell other process to update their env values
RegCloseKey(writeKey);
}
This will append the new path to environment variable of current user.

Access violation reading from location in C++

Why is the last statement throwing Access Violation?
I wanted to write the status of a service into an XML file.
#define STR_SERVICE_STATUS_INPUT__XML_CONTENT _T("<SERVICE NAME = \"%s\" STARTUP_TYPE = \"0x%d\" />\r\n\r\n")
CString csWriteBufferTemp;
DWORD dwBufferSize;
DWORD dwBytesNeeded;
SC_HANDLE schHandle;
LPQUERY_SERVICE_CONFIG st_lpqscServiceInfo;
schHandle = OpenService(IN_schHandle, (CString)cArgentServices[i], SERVICE_QUERY_CONFIG);
bRC = QueryServiceConfig(schHandle, NULL, 0, &dwBytesNeeded);
dwBufferSize = dwBytesNeeded; //Size needed.
st_lpqscServiceInfo = (LPQUERY_SERVICE_CONFIG) LocalAlloc(LMEM_FIXED, dwBufferSize);
bRC = QueryServiceConfig(schHandle, st_lpqscServiceInfo, dwBufferSize, &dwBytesNeeded);
csWriteBufferTemp.Format(STR_SERVICE_STATUS_INPUT__XML_CONTENT__,st_lpqscServiceInfo->lpDisplayName,0);
You are almost certainly using the wrong string format parameter in _T("<SERVICE NAME = \"%S\" STARTUP_TYPE = \"0x%d\" />\r\n\r\n"). The lpServiceStartName member of SERVICE_QUERY_CONFIG and CString are both TCHAR-based so they should have matching character types regardless of whether your compiling in Unicode mode or not. In that case, you should be using %s instead of %S.
Thanks for all your replies and suggestions, I found the answer on another site. I don't know if this is the correct way but it works!
LPQUERY_SERVICE_CONFIG
st_lpqscServiceInfo;
SC_HANDLE schHandle;
st_lpqscServiceInfo = (LPQUERY_SERVICE_CONFIG) LocalAlloc(LPTR, 4096);
schHandle = OpenSCManager(IN_pszMachineName,SERVICES_ACTIVE_DATABASE, SERVICE_QUERY_CONFIG);
bRC = QueryServiceConfig(schHandle, st_lpqscServiceInfo, dwBufferSize, &dwBytesNeeded);
csWriteBufferTemp.Format(STR_SERVICE_STATUS_INPUT__XML_CONTENT__,st_lpqscServiceInfo->lpDisplayName,0);

CreateProcess # Unhandled exception when not using directly a string

I'm trying to use CreateProcess to open a game .exe but I'm having the unhandled exception error. I already figured out the problem and the solution, but I need to get the path for the second parameter of CreateProcess from a file dialog box (that part is done and works). The problem is:
For the second parameter of CreateProcess, I need to declare a variable with the value to it (the 2nd param), but if I "point" it to the variable of the path to the file selected in the file dialog box, it doesn't work anymore.
I'm sorry if this is a really dumb question, but I'm starting in C++.
The code that works is here:
wchar_t szGameDir[] = L"PATH_TO_EXE";
if ( CreateProcess (
NULL,
szGameDir, NULL, NULL, FALSE,
CREATE_UNICODE_ENVIRONMENT,
NULL, NULL,
&pstStartupInfo, &pstProcInfo ) )
But when I set szGameDir to the value of 'pszGameDir' (path to the EXE selected by the user), it gives the unhandled exception error...
wchar_t* szGameDir = pszGameDir;
if ( CreateProcess (
NULL,
szGameDir, NULL, NULL, FALSE,
CREATE_UNICODE_ENVIRONMENT,
NULL, NULL,
&pstStartupInfo, &pstProcInfo ) )
And this is where I initialize 'pszGameDir':
OPENFILENAME DialogBox;
ZeroMemory ( &DialogBox, sizeof(DialogBox) );
DialogBox.lStructSize = sizeof(OPENFILENAME);
DialogBox.hwndOwner = NULL;
DialogBox.lpstrFilter = L"Grand Theft Auto: Vice City (*.exe)\0*.exe\0";
DialogBox.lpstrFile = (LPTSTR)this->pszGameDir;
DialogBox.nMaxFile = MAX_PATH;
DialogBox.nMaxFileTitle = sizeof ( L"gta-vc.exe" );
DialogBox.lpstrTitle = L"Please, select 'gta-vc.exe'";
DialogBox.Flags = 0x02000000 | 0x00001000 | 0x00000400 | 0x10000000 | 0x00020000 | 0x00000800 | 0x0000008;
DialogBox.nFileExtension = (WORD)"exe";
DialogBox.lpstrDefExt = L"exe";
return GetOpenFileName ( &DialogBox ) != 0 ? 1 : NULL;
Can someone help me? (Yes, I did search already, but honestly I haven't found about this specific thing, I wasn't able to fix it either..)
CreateProcess needs the command line parameter to be writeable. Read the description of the argument at MSDN:
The Unicode version of this function, CreateProcessW, can modify the contents of this string. Therefore, this parameter cannot be a pointer to read-only memory (such as a const variable or a literal string). If this parameter is a constant string, the function may cause an access violation.
It has to be writeable, I am afraid.

Registry: Delete key for each local user within system

I got a certain registry key (created by our software) which needs to be removed on each local user account at some point.
Thus, I try to load the users hive and then use SHDeleteKey (as the key is not empty) to get the job done.
However, SHDeleteKey always returns LSTATUS 2 (ERROR_FILE_NOT_FOUND).
The Registry key for each user is placed under
HKCU\Software\XYZ
First, I set the required privileges within my code, which seems to work (return val is TRUE):
(...)
HANDLE th;
LUID rsto;
LUID bckp;
TOKEN_PRIVILEGES tp;
TOKEN_PRIVILEGES tp2;
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &th);
LookupPrivilegeValue(NULL, SE_RESTORE_NAME, &rsto);
LookupPrivilegeValue(NULL, SE_BACKUP_NAME, &bckp);
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
tp.Privileges[0].Luid = rsto;
tp2.PrivilegeCount = 1;
tp2.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
tp2.Privileges[0].Luid = bckp;
BOOL p = AdjustTokenPrivileges(th, 0, &tp, 1024, 0, 0);
BOOL p2 = AdjustTokenPrivileges(th, 0, &tp2, 1024, 0, 0);
(...)
Then I use RegloadKey to load the users hive.
std::string connection contains the path to the respective ntuser.dat file. username is the local user account name.
So the hive should be loaded under HKEY_USERS\username:
(...)
DWORD result = RegLoadKey(HKEY_USERS, username.c_str(), connection.c_str());
return result == ERROR_SUCCESS;
(...)
Now, I try to delete:
(...)
k = username + "\\Software\\XYZ";
result = SHDeleteKey(HKEY_USERS, k.c_str());
And now result has value of 2.
But the key exists.
What am I doing wrong?
Thank you in advance...
UPDATED INFO:
I realized the problem needs to be somewhere on RegLoadKey.
When I load the hive via command line (REG.exe load "HKU\username" ...), I can see the node "username" under HKEY_USERS within regedit.exe. All child nodes are loaded under that node.
When I pause my program after RegLoadKey, the node "username" is also shown under HKEY_USERS, but the node is visualized as empty, so no child nodes are available.
How can this happen? This problem is driving me nuts.
Looked at my code again today and I just saw that I loaded "ntuser.BAT" instead of "ntuser.DAT" (both files exist).
I'm really sorry that I wasted your time. :-/