I have setup an Active Directory service on my Windows 2008 server.
I have added an user and here is the DN (DistingushedName) CN=ashwin,CN=Users,DC=test,DC=com
There is no password set for the DN and anonymous binds are allowed. I have a sample (test code) C++ program that connects to AD and searches the user.
#include "windows.h"
#include "winldap.h"
#include "stdio.h"
// Entry point for your application
int main(int argc, char* argv[])
{
LDAP* pLdapConnection = NULL;
INT returnCode = 0;
INT connectSuccess = 0;
ULONG version = LDAP_VERSION3;
LONG lv = 0;
int option(0);
LDAPMessage *vLdapMessage;
// Initialize an LDAP session without SSL.
pLdapConnection = ldap_init("192.168.56.128",389);
if (pLdapConnection == NULL)
{
printf( "ldap_init failed with 0x%x.\n",hr);
return -1;
}
// Specify version 3; the default is version 2.
returnCode = ldap_set_option(pLdapConnection,
LDAP_OPT_PROTOCOL_VERSION,
(void*)&version);
if (returnCode != LDAP_SUCCESS)
goto FatalExit;
//Turning off referrals
ldap_set_option(pLdapConnection, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); // required
// Connect to the server.
connectSuccess = ldap_connect(pLdapConnection, NULL);
if(connectSuccess != LDAP_SUCCESS)
{
printf("ldap_connect failed with 0x%x.\n",connectSuccess);
goto FatalExit;
}
// Bind with current credentials.
printf("Binding ...\n");
returnCode = ldap_bind_s(pLdapConnection,NULL, NULL, LDAP_AUTH_SIMPLE);
if (returnCode != LDAP_SUCCESS)
goto FatalExit;
returnCode = ldap_search_s(pLdapConnection, "DC=test, DC=com", LDAP_SCOPE_SUBTREE, "CN=ashwin", NULL, 0, &vLdapMessage);
if (returnCode != LDAP_SUCCESS)
goto FatalExit;
NormalExit:
if (pLdapConnection != NULL)
ldap_unbind_s(pLdapConnection);
return 0;
FatalExit:
if( pLdapConnection != NULL )
ldap_unbind_s(pLdapConnection);
printf( "\n\nERROR: 0x%x\n", returnCode);
return returnCode;
}
The search fails. ldap_search_s always returns 1.
The same setup testing on Apache directory service works fine.
Could someone point why this does not work with Windows AD? what is wrong in the program?
Active Directory filtering syntax can be quite verbose. From what I can tell, you just need to modify your filter slightly. Try this :
(&(objectClass=user)(distinguishedName=CN=ashwin,CN=Users,DC=test,DC=com))
However, for single user filtering, I'd try using the sAMAccountName. This generally follows a {FirstInitial}{LastName} format, and would be unique to the user (Ex. JSmith) :
(&(objectClass=user)(sAMAccountName=JSmith))
Related
I'm trying to add a AD user or group to my local group using OSX Core services and Objective-C
Currently this code gives me error code -2 which I guess is kCSIdentityAuthorityNotAccessibleErr. I couldn't find any good examples on how to do that so any help is welcome.
RetCode NixUtils::AddGroupMember(const std::string& sGroupName, const std::string& sMemberName)
{
RetCode retCode = ERROR_FUNCTION_FAILED;
CSIdentityRef userRef = NULL;
CSIdentityRef groupRef = NULL;
AuthorizationRef auth = NULL;
retCode = GetLocalIdentity(sGroupName, NULL, groupRef); //getting local group
if(retCode)
{
retCode = GetNetworkIdentity(sMemberName, NULL, userRef); //getting AD user
if(retCode)
{
CSIdentityAddMember(groupRef, userRef);
//not quite sure I'm using the right Authorization initialization for this operation
OSStatus status = AuthorizationCreate(NULL, NULL, kAuthorizationFlagDefaults, &auth);
if(status != errAuthorizationSuccess)
{
retCode = ERROR_FUNCTION_FAILED;
}
else{
CFErrorRef errorRef;
bool success = CSIdentityCommit(groupRef, auth, &errorRef);
if(!success)
{
retCode = ERROR_FUNCTION_FAILED;
CFIndex errCode = CFErrorGetCode(errorRef);
if(errorRef)
{
EMgr::ReportDebugTrace("NixUtils::AddGroupMember() error code %d! ", (long)errCode); // error code -2
}
}
else{
EMgr::ReportDebugTrace("NixUtils::AddGroupMember() Commit Success!");
}
}
}
}
if(auth) CFRelease(auth);
if(userRef) CFRelease(userRef);
if(groupRef) CFRelease(groupRef);
return retCode;
}```
I've got a service running on all the computers in my lab, and need to be able to simultaneously log on to all the computers.
All the computers have the same username, so that's not a problem.
But I'm having trouble finding a way to programmatically initiate the logon. I've read about LogonUser() and its counterparts, but they don't seem to have the functionality I need.
Does anyone have any suggestions as to how I could do this from a c++ service?
The only straightforward, supported way to do this is to use the autologon functionality. The main disadvantage is that it requires rebooting the machines.
Here's the code I use (note that our account domain "scms" is hardcoded, so you'll need to change that bit):
#define _WIN32_WINNT 0x0601
#include <windows.h>
#include <Ntsecapi.h>
#include <stdio.h>
#include <wchar.h>
void setAutologon(void);
void clearAutologon(void);
WCHAR username[128];
WCHAR password[128];
int main(int argc, char ** argv)
{
if (argc == 2 && _stricmp(argv[1], "-clear") == 0)
{
clearAutologon();
return 0;
}
if (argc != 3)
{
printf("Syntax: autologon username password\n");
return 1;
}
swprintf_s(username, _countof(username), L"%hs", argv[1]);
swprintf_s(password, _countof(password), L"%hs", argv[2]);
setAutologon();
return 0;
}
void fail(char * errmsg, DWORD err)
{
// Oops. It didn't work.
printf(errmsg, err);
if (err == 0) err = 1;
exit(err);
}
void storePassword(BOOL store_password)
{
LSA_OBJECT_ATTRIBUTES loa;
LSA_HANDLE lh;
LSA_UNICODE_STRING name;
static const wchar_t name_buffer[] = L"DefaultPassword";
LSA_UNICODE_STRING data;
DWORD dw;
loa.Length = sizeof(loa);
loa.RootDirectory = NULL;
loa.ObjectName = NULL;
loa.Attributes = 0;
loa.SecurityDescriptor = NULL;
loa.SecurityQualityOfService = NULL;
if ((dw = LsaOpenPolicy(NULL, &loa, POLICY_CREATE_SECRET, &lh)) != 0) fail("Error %u opening LSA policy.", LsaNtStatusToWinError(dw));
name.Buffer = (wchar_t *)name_buffer;
name.MaximumLength = name.Length = sizeof(name_buffer) - sizeof(*name_buffer);
if (!store_password)
{
if ((dw = LsaStorePrivateData(lh, &name, NULL)) != 0) fail("Error %u clearing stored password.", LsaNtStatusToWinError(dw));
return;
}
data.Buffer = password;
data.MaximumLength = data.Length = wcslen(password) * sizeof(*password);
if ((dw = LsaStorePrivateData(lh, &name, &data)) != 0) fail("Error %u storing password.", LsaNtStatusToWinError(dw));
LsaClose(lh);
return;
}
void setAutologon()
{
LONG i;
HKEY h;
i = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", 0, KEY_WOW64_64KEY | KEY_SET_VALUE, &h);
if (i != ERROR_SUCCESS) fail("Unable to open Winlogon subkey (error %u).", i);
i = RegSetValueEx(h, L"DefaultUserName", 0, REG_SZ, (CONST BYTE *)username, (wcslen(username)+1)*2);
if (i != ERROR_SUCCESS) fail("Unable to set default logon user name (error %u).", i);
storePassword(TRUE);
i = RegSetValueEx(h, L"DefaultDomainName", 0, REG_SZ, (CONST BYTE *)L"scms", 10);
if (i != ERROR_SUCCESS) fail("Unable to set default domain name (error %u).", i);
i = RegSetValueEx(h, L"AutoAdminLogon", 0, REG_SZ, (CONST BYTE *)L"1", 2);
if (i != ERROR_SUCCESS) fail("Unable to set automatic logon flag (error %u).", i);
i = RegSetValueEx(h, L"ForceAutoLogon", 0, REG_SZ, (CONST BYTE *)L"1", 2);
if (i != ERROR_SUCCESS) fail("Unable to set forced automatic logon flag (error %u).", i);
}
void clearAutologon(void)
{
LONG i;
HKEY h;
i = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", 0, KEY_WOW64_64KEY | KEY_SET_VALUE, &h);
if (i != ERROR_SUCCESS) fail("Unable to open Winlogon subkey (error %u).", i);
i = RegSetValueEx(h, L"DefaultUserName", 0, REG_SZ, "", 1);
if (i != ERROR_SUCCESS) fail("Unable to set default logon user name (error %u).", i);
storePassword(FALSE);
// In case the automatic logon was set by the previous version of rpwd or by
// some other means, we clear the registry setting for DefaultPassword as well.
i = RegDeleteValue(h, L"DefaultPassword");
if (i != ERROR_SUCCESS && i != ERROR_FILE_NOT_FOUND) fail("Unable to remove default logon password (error %u).", i);
i = RegDeleteValue(h, L"ForceAutoLogon");
if (i != ERROR_SUCCESS && i != ERROR_FILE_NOT_FOUND) fail("Unable to remove force logon flag (error %u).", i);
i = RegSetValueEx(h, L"AutoAdminLogon", 0, REG_SZ, (CONST BYTE *)"0", 2);
if (i != ERROR_SUCCESS) fail("Unable to clear automatic logon flag (error %u).", i);
}
I use psexec (available from the MS web site) to run the code on all of the lab machines, and psshutdown (ditto) to reboot them. Once they've started the logon process, you can clear the autologon.
No doubt you could adapt the same approach into a service easily enough.
If you want to avoid the reboot, you would need to implement a credential provider. The last time I looked into this the documentation was distressingly sparse, but this may have improved. You might also be interested in pGINA, an open source credential provider that may be useful as an example. (Or, for all I know, may already contain the functionality you want!)
I'm plying with HttpCalculatorServiceExample located in MSDN. What endpoint address should be defined in WS_SERVICE_ENDPOINT structure. Expression L"http://+:80/example" looks strange for me. What +:80 means? I suppose 80 is port number. But why +?
int __cdecl wmain(int argc, __in_ecount(argc) wchar_t **argv)
{
UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARAMETER(argv);
HRESULT hr = NOERROR;
WS_SERVICE_HOST* host = NULL;
WS_SERVICE_ENDPOINT serviceEndpoint = {};
const WS_SERVICE_ENDPOINT* serviceEndpoints[1];
serviceEndpoints[0] = &serviceEndpoint;
WS_ERROR* error = NULL;
WS_SERVICE_ENDPOINT_PROPERTY serviceEndpointProperties[1];
WS_SERVICE_PROPERTY_CLOSE_CALLBACK closeCallbackProperty = {CloseChannelCallback};
serviceEndpointProperties[0].id = WS_SERVICE_ENDPOINT_PROPERTY_CLOSE_CHANNEL_CALLBACK;
serviceEndpointProperties[0].value = &closeCallbackProperty;
serviceEndpointProperties[0].valueSize = sizeof(closeCallbackProperty);
// Initialize service endpoint
serviceEndpoint.address.url.chars = L"http://+:80/example"; // address given as uri
serviceEndpoint.address.url.length = (ULONG)wcslen(serviceEndpoint.address.url.chars);
serviceEndpoint.channelBinding = WS_HTTP_CHANNEL_BINDING; // channel binding for the endpoint
serviceEndpoint.channelType = WS_CHANNEL_TYPE_REPLY; // the channel type
serviceEndpoint.contract = &calculatorContract; // the contract
serviceEndpoint.properties = serviceEndpointProperties;
serviceEndpoint.propertyCount = WsCountOf(serviceEndpointProperties);
// Create an error object for storing rich error information
hr = WsCreateError(
NULL,
0,
&error);
if (FAILED(hr))
{
goto Exit;
}
// Create Event object for closing the server
closeServer = CreateEvent(
NULL,
TRUE,
FALSE,
NULL);
if (closeServer == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Exit;
}
// Creating a service host
hr = WsCreateServiceHost(
serviceEndpoints,
1,
NULL,
0,
&host,
error);
if (FAILED(hr))
{
goto Exit;
}
// WsOpenServiceHost to start the listeners in the service host
hr = WsOpenServiceHost(
host,
NULL,
error);
if (FAILED(hr))
{
goto Exit;
}
WaitForSingleObject(closeServer, INFINITE);
// Close the service host
hr = WsCloseServiceHost(host, NULL, error);
if (FAILED(hr))
{
goto Exit;
}
Exit:
if (FAILED(hr))
{
// Print out the error
PrintError(hr, error);
}
fflush(
stdout);
if (host != NULL)
{
WsFreeServiceHost(host);
}
if (error != NULL)
{
WsFreeError(error);
}
if (closeServer != NULL)
{
CloseHandle(closeServer);
}
fflush(stdout);
return SUCCEEDED(hr) ? 0 : -1;
}
I'm tryind to run HttpCalculatorServiceExample located in MSDN. Function WsOpenServiceHost returns error code 0x803d0021. This error means
MessageId: WS_E_OTHER
Unrecognized error occurred in the Windows Web Services framework.
Printed error:
Unable to add URL to HTTP URL group.
Unrecognized error occurred in the Windows Web Services framework.
The process cannot access the file because it is being used by another process.
How to solve this problem?
int __cdecl wmain(int argc, __in_ecount(argc) wchar_t **argv)
{
UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARAMETER(argv);
HRESULT hr = NOERROR;
WS_SERVICE_HOST* host = NULL;
WS_SERVICE_ENDPOINT serviceEndpoint = {};
const WS_SERVICE_ENDPOINT* serviceEndpoints[1];
serviceEndpoints[0] = &serviceEndpoint;
WS_ERROR* error = NULL;
WS_SERVICE_ENDPOINT_PROPERTY serviceEndpointProperties[1];
WS_SERVICE_PROPERTY_CLOSE_CALLBACK closeCallbackProperty = {CloseChannelCallback};
serviceEndpointProperties[0].id = WS_SERVICE_ENDPOINT_PROPERTY_CLOSE_CHANNEL_CALLBACK;
serviceEndpointProperties[0].value = &closeCallbackProperty;
serviceEndpointProperties[0].valueSize = sizeof(closeCallbackProperty);
// Initialize service endpoint
serviceEndpoint.address.url.chars = L"http://+:80/example"; // address given as uri
serviceEndpoint.address.url.length = (ULONG)wcslen(serviceEndpoint.address.url.chars);
serviceEndpoint.channelBinding = WS_HTTP_CHANNEL_BINDING; // channel binding for the endpoint
serviceEndpoint.channelType = WS_CHANNEL_TYPE_REPLY; // the channel type
serviceEndpoint.contract = &calculatorContract; // the contract
serviceEndpoint.properties = serviceEndpointProperties;
serviceEndpoint.propertyCount = WsCountOf(serviceEndpointProperties);
// Create an error object for storing rich error information
hr = WsCreateError(
NULL,
0,
&error);
if (FAILED(hr))
{
goto Exit;
}
// Create Event object for closing the server
closeServer = CreateEvent(
NULL,
TRUE,
FALSE,
NULL);
if (closeServer == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Exit;
}
// Creating a service host
hr = WsCreateServiceHost(
serviceEndpoints,
1,
NULL,
0,
&host,
error);
if (FAILED(hr))
{
goto Exit;
}
// WsOpenServiceHost to start the listeners in the service host
hr = WsOpenServiceHost(
host,
NULL,
error);
if (FAILED(hr))
{
goto Exit;
}
WaitForSingleObject(closeServer, INFINITE);
// Close the service host
hr = WsCloseServiceHost(host, NULL, error);
if (FAILED(hr))
{
goto Exit;
}
Exit:
if (FAILED(hr))
{
// Print out the error
PrintError(hr, error);
}
fflush(
stdout);
if (host != NULL)
{
WsFreeServiceHost(host);
}
if (error != NULL)
{
WsFreeError(error);
}
if (closeServer != NULL)
{
CloseHandle(closeServer);
}
fflush(stdout);
return SUCCEEDED(hr) ? 0 : -1;
}
I had the same error "Unrecognized error occurred in the Windows Web Services framework", while tried to debug remote target (C++ project).
I've tried all possible solutions, which I've found over internet: turn-off/uninstall antivirus(I use MS Essentials), turnoff firewall, reinstall VS etc.
But it didn't help.
So, I've deleted all programms (not windows updates) which I've installed last month, reboot computer, and the bug went away.
Uninstalled software:
Foxit PhantomPDF Standard. Версия: 7.0.5.1021.
widecap
CCleaner
Uninstall Tool
just in case, I've also uninstalled Microsoft Security Essentials and after the bug went away I've installed it again and had no problems.
Hope, this helps
I'm trying to use one of the windows examples to have some CPU data. When I try to debug the below code I receive the message "The command line must include a valid log file name" I am using MS Visual studio 2013 and I am intrested in Total Processor time%.
Pls advise.
More details about the code:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa373228(v=vs.85).aspx
The Code:
#include <windows.h>
#include <stdio.h>
#include <pdh.h>
#include <pdhmsg.h>
#pragma comment(lib, "pdh.lib")
CONST PWSTR COUNTER_PATH = L"\\Processor(0)\\% Processor Time";
CONST ULONG SAMPLE_INTERVAL_MS = 1000;
void DisplayCommandLineHelp(void)
{
wprintf(L"The command line must include a valid log file name.\n");
}
void wmain(int argc, WCHAR **argv)
{
HQUERY hQuery = NULL;
HLOG hLog = NULL;
PDH_STATUS pdhStatus;
DWORD dwLogType = PDH_LOG_TYPE_CSV;
HCOUNTER hCounter;
DWORD dwCount;
if (argc != 2)
{
DisplayCommandLineHelp();
goto cleanup;
}
// Open a query object.
pdhStatus = PdhOpenQuery(NULL, 0, &hQuery);
if (pdhStatus != ERROR_SUCCESS)
{
wprintf(L"PdhOpenQuery failed with 0x%x\n", pdhStatus);
goto cleanup;
}
// Add one counter that will provide the data.
pdhStatus = PdhAddCounter(hQuery,
COUNTER_PATH,
0,
&hCounter);
if (pdhStatus != ERROR_SUCCESS)
{
wprintf(L"PdhAddCounter failed with 0x%x\n", pdhStatus);
goto cleanup;
}
// Open the log file for write access.
pdhStatus = PdhOpenLog(argv[1],
PDH_LOG_WRITE_ACCESS | PDH_LOG_CREATE_ALWAYS,
&dwLogType,
hQuery,
0,
NULL,
&hLog);
if (pdhStatus != ERROR_SUCCESS)
{
wprintf(L"PdhOpenLog failed with 0x%x\n", pdhStatus);
goto cleanup;
}
// Write 10 records to the log file.
for (dwCount = 0; dwCount < 10; dwCount++)
{
wprintf(L"Writing record %d\n", dwCount);
pdhStatus = PdhUpdateLog(hLog, NULL);
if (ERROR_SUCCESS != pdhStatus)
{
wprintf(L"PdhUpdateLog failed with 0x%x\n", pdhStatus);
goto cleanup;
}
// Wait one second between samples for a counter update.
Sleep(SAMPLE_INTERVAL_MS);
}
cleanup:
// Close the log file.
if (hLog)
PdhCloseLog(hLog, 0);
// Close the query object.
if (hQuery)
PdhCloseQuery(hQuery);
}
if (argc != 2)
{
DisplayCommandLineHelp();
goto cleanup;
}
This is your answer right here. You need to set your project up to pass a filename to the program when it runs.
argc counts how many command-line arguments your program has received. It always gets at least one, the name of the program itself. But this program needs a second one, the name of the logfile to write to.