I'm trying to add a local user to Windows using the Network Management API. I'm having no problems when running on Windows 7 (either on a domain or workgroup) or windows 2008 R2 server when on a domain. However, if I run this on Windows server 2008 R2 that isn't on a domain I get an error. Problem is the error code returned is -1 rather than one of the given errors in the documentation
bool CLocalUsers::AddUser(LPCTSTR lpszUserName, LPCTSTR lpszPassword)
{
// Clear error code
m_dwLastError = 0;
USER_INFO_1 ui;
ui.usri1_name = (LPTSTR)(LPCTSTR)lpszUserName;
ui.usri1_priv = USER_PRIV_USER;
ui.usri1_home_dir = NULL;
ui.usri1_comment = NULL;
ui.usri1_flags = UF_SCRIPT | UF_DONT_EXPIRE_PASSWD;
ui.usri1_script_path = NULL;
// Point to a zero character password if null
if(lpszPassword == NULL)
{
lpszPassword = _T("");
ui.usri1_flags |= UF_PASSWD_NOTREQD;
}
ui.usri1_password = (LPTSTR)(LPCTSTR)lpszPassword;
// Add the user
NET_API_STATUS nStatus = ::NetUserAdd(NULL, 1, (LPBYTE)&ui, &m_dwLastError);
if(nStatus != NERR_Success)
{
// DEBUG ONLY
CString szErrorMsg;
szErrorMsg.Format(_T("Error code %d"), m_dwLastError);
::AfxMessageBox(szErrorMsg, MB_OK);
// DEBUG ONLY
return false;
}
return true;
}
It's being run under admin privileges. I can call other Network functions with out any problems (NetUserGetInfo, NetLocalGroupAddMembers).
I've experimented with different password sizes but I can happily create the same account with the same information using the Server Manager tool that comes with Windows 2008
Thanks
After looking at the status code rather than m_dwLastError it turns out it was NERR_PasswordTooShort as the minimum password requirement on a fresh Windows 2008 server is 8 characters.
Related
I tried to read network computer names using WNetOpenEnum. I am getting only 'Microsoft Terminal Services', 'Microsoft Windows Network' and 'Web Client Network'. Not getting the other machine connected in network.
Is there any way to read the names/IP of computers connected to network?.
if(NO_ERROR == WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_ANY, 0, pnetrParent, &hEnum))
{
DWORD dwCount = 1;
char szBuffer[512];
char* psz = szBuffer;
DWORD dwBufferSize = sizeof(szBuffer);
while (NO_ERROR == WNetEnumResource(hEnum, &dwCount, &szBuffer, &dwBufferSize))
{
NETRESOURCE* pnetResource = (NETRESOURCE*)psz;
if (NULL != pnetResource->lpRemoteName && *pnetResource->lpRemoteName)
{
m_lstIPAddress.AddString(pnetResource->lpRemoteName);
}
dwBufferSize = sizeof(szBuffer);
}
DWORD retValue = WNetCloseEnum(hEnum);
}
Any help would be appreciated.
You need to call it recursively. Microsoft Windows Network has computers listed. So next call to WNetOpenEnum will have handle to Microsoft Windows Network you received as first parameter and so on.
I believe this would give you answer: https://learn.microsoft.com/en-us/windows/win32/wnet/enumerating-network-resources
Below is the code which is calling Windows SetupDiSetClassInstallParamsW
method --
bool
Util::SvmDisableNic(HDEVINFO devInfoSet, SP_DEVINFO_DATA deviceInfo)
{
SP_PROPCHANGE_PARAMS params = {0};
SP_DEVINSTALL_PARAMS_W installParams = {0};
//
// Disable device
//
params.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
params.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
params.StateChange = DICS_DISABLE;
params.Scope = DICS_FLAG_GLOBAL;
params.HwProfile = 0;
if (!SetupDiSetClassInstallParamsW(devInfoSet, &deviceInfo,
&(params.ClassInstallHeader),
sizeof params)) {
DWORD err = GetLastError();
SYSMSG_FUNC(
Debug, _T("Failed setting device params to disable: Err: 0x%X"), err);
return false;
}
This code is running successfully, however, in a couple of VMs, the
SetupDiSetClassInstallParamsW is failing, and GetLastError is returning an error code of 0xD. From microsoft doc, looks like this corresponds to ERROR_INVALID_DATA. The VMs in which this code is running successfully and in those in which it is failing, are identical in terms of hardware/software configuration. Any idea how we can debug why this windows API is failing?
I want to connect to the wireless access point. The problem is WlanConnect returns 87 error code which means the wrong parameter.
Code:
WLAN_REASON_CODE wlanReasonCode;
DWORD dwResult = 0;
DWORD dwPrevNotif = 0;
QString apName = "some SSID";
WLAN_CONNECTION_PARAMETERS connectionParameters;
memset(&connectionParameters, 0, sizeof(WLAN_CONNECTION_PARAMETERS));
connectionParameters.wlanConnectionMode = wlan_connection_mode_profile;
connectionParameters.strProfile = apName.toStdWString().c_str();
connectionParameters.dwFlags = 0;
connectionParameters.pDot11Ssid = NULL;
connectionParameters.pDesiredBssidList = 0;
connectionParameters.dot11BssType = dot11_BSS_type_any;
dwResult = WlanConnect(hClient, &pIfInfo->InterfaceGuid, &connectionParameters, NULL);
if (dwResult == ERROR_SUCCESS) {
qDebug() << "Connected";
} else {
emit apNotConnected(dwResult);
}
I think the problem somewhere in WLAN_CONNECTION_PARAMETERS structure. Any ideas or example with proper wlan connection?
OS: Windows 10
I use Qt 5.9.2 with Microsoft Visual Studio 2017 compiler.
Thanks in advance.
I have fixed the issue. The issue was that Qt does not properly cast data types, so the wlan profile was corrupted. I fixed it by combining Win API with standard C++ data types.
I create regedit key named "Language" in HKEY_LOCAL_MACHINE SOFTWARE\Company\Company\, in visual studio debug mode will be create, but I build it through Install shield, and Install it in other machine and OS (windows 7 window 8), the key can't create by application.
When step of Install shield, I create Regedit key of SOFTWARE\Company\Company\,
But I can't Change the key of Language at this code
SetMainRegeditValue(theApp.mMainRegKey, theApp.mMainRegNormal[0], theApp.g_eLanguage);
what happen with this code ?
// In the global
CRegKey mMainRegKey;
CString *mMainRegPath;
CString *mMainRegNormal;
....
theApp.mMainRegPath = new CString[1];
theApp.mMainRegPath[0] = _T("SOFTWARE\\Company\\Company\\");
theApp.mMainRegNormal = new CString[1];
theApp.mMainRegNormal[0] = _T("Language");
// Check Regedit value
if(theApp.mMainRegKey.Open(HKEY_LOCAL_MACHINE, theApp.mMainRegPath[0]) == ERROR_SUCCESS)
{
TCHAR tstrLan[_MAX_PATH];
DWORD len = _MAX_PATH;
DWORD lanlen = 8;
if(theApp.mMainRegKey.QueryStringValue(_T("Version"),tstrLan, &lanlen) != ERROR_SUCCESS)
{
RegDeleteKey(HKEY_LOCAL_MACHINE, theApp.mMainRegPath[0]);
RegDeleteKey(HKEY_LOCAL_MACHINE, theApp.mMainRegNormal[0]);
SetMainRegeditValue(theApp.mMainRegKey,_T("Version"), _T("v2.0.0"));
}
}
if(theApp.mMainRegKey.Open(HKEY_LOCAL_MACHINE,theApp.mMainRegPath[0]) != ERROR_SUCCESS)
{
theApp.mMainRegKey.Create(HKEY_LOCAL_MACHINE, theApp.mMainRegPath[0]);
SetMainRegeditValue(theApp.mMainRegKey, theApp.mMainRegNormal[0], theApp.g_eLanguage);
}
OK, I find the rule.
need administrator privileges to write anything to HKEY_LOCAL_MACHINE,
but HKEY_CURRENT_USER not necessary, so replace HKEY_LOCAL_MACHINE to HKEY_CURRENT_USER,
the problem be solved.
I wrote some code to connect with some share on a remote server. If WNetAddConnection2 returns ERROR_SESSION_CREDENTIAL_CONFLICT (1219), I will first cancel the connection by WNetCancelConnection2 (return NO_ERROR). And then reconnect. But WNetAddConnection2 still returns 1219.
Why this and how to fix it?
Here's my code
BOOL ADDirectorySearch::IPCConnect(CString strServerName, CString strDomainName, CString strUserName, CString strPassWord)
{
CString strServerNameWithSlash = _T("\\\\") + strServerName; //actually is \\klbnt
CString strFullUserName = strDomainName + _T("\\") + strUserName; //is domaintest\administrator
_bstr_t bstrServerNameWithSlash = strServerNameWithSlash;
_bstr_t bstrFullUserName = strFullUserName;
_bstr_t bstrPassWord = strPassWord;
DWORD dwResult;
NETRESOURCEW netResource;
memset(&netResource, 0, sizeof(netResource));
netResource.dwScope = RESOURCE_GLOBALNET;
netResource.dwType = RESOURCETYPE_DISK;
netResource.dwDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
netResource.dwUsage = RESOURCEUSAGE_CONNECTABLE;
netResource.lpProvider = L"";
netResource.lpRemoteName = bstrServerNameWithSlash;//Remote IP like:\\192.168.1.11
dwResult = WNetAddConnection2W(&netResource, bstrPassWord, bstrFullUserName, CONNECT_INTERACTIVE);
if (dwResult == ERROR_SESSION_CREDENTIAL_CONFLICT)
{
dwResult = WNetCancelConnection2W(bstrServerNameWithSlash, CONNECT_UPDATE_PROFILE, TRUE);
if (dwResult == NO_ERROR)
{
dwResult = WNetAddConnection2W(&netResource, bstrPassWord, bstrFullUserName, CONNECT_INTERACTIVE);
}
else
{
//MyMessageBox_Error(_T("IPCConnect Error."), _T("Error"));
return FALSE;
}
}
if (dwResult == NO_ERROR)
{
return TRUE;
}
else
{
//MyMessageBox_Error(_T("IPCConnect Error."), _T("Error"));
return FALSE;
}
}
FYI: After typing "net use" in cmd, I got this, I feel there's something with error:
Status Local Remote Network
-------------------------------------------------------------------------------
OK \\klbnt\NRDC1001 Microsoft Windows Network
The command completed successfully.
I was just having this problem now, and basically it seemed that it was due to another process still having file open, even though I specified "true" as the last parameter of WNetCancelConnection2() to force close the connection. Once I shut-down that other process, I was able to use successfully switch between credentials connecting and re-connecting to the same share. This is on Windows 2012 (64-bit), and the share was local (referenced by the machinename).
BUT...it's still a problem if you want to connect to different shares on the same machine. If I try to connect to \\mymachine\share1 as user1 then to \\mymachine\share2 as user2, I get the 1219 error (even if it's in a completely different process). I have to explicitly call WNetCancelConnnection on \\mymachine\share1 before I can connect to share2, which means at the point you connect to a share on a particular machine, you may have to first enumerate existing connections and close each one.
Rather frustrating, and I can't understand the design principle here. It seems the flags to create temporary connections etc. have no effect on this behaviour either. Really what I want to be able to do is say "for this thread, connect to this share on this machine and as this user, such that all attempts to access files on the share are done with that user's credentials". That way what other processes/threads are doing can't cause issues with the current one.