LDAP C++ how do I check that a user has a valid password? - c++

I am trying to figure out how to check if a user has a valid password with LDAP c++ code. This seems maddeningly difficult for what seems to be it's intended purpose.
The only working example code I could find was ldapsearch. I can log in as the default user and search for the user:
ldapsearch -x -D "cn=ldap,cn=Users,dc=company,dc=local" -W -H ldap://localhost:389 -b "ou=company_account,dc=company,dc=local" -s sub 'uid=my_id'
This seems to correspond to this code (note: lots of error checking removed)
LDAP *ld = NULL;
string sHostIP = session.ini["ldap_host"];
string sPort = session.ini["ldap_port"];
string sURL = sHostIP+":"+sPort;
ldap_initialize( &ld, sURL.c_str() );
int iVersion = LDAP_VERSION3;
ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &iVersion );
string sLDAPPW = session.ini["ldap_server_pw"];
struct berval pServerPassword = { 0, NULL };
pServerPassword.bv_val = ber_strdup( &sLDAPPW[0] );
pServerPassword.bv_len = strlen( pServerPassword.bv_val );
//can't bind without this code block, but what does it even do?
int iMsgid;
int nsctrls = 0;
LDAPControl c;
c.ldctl_oid = LDAP_CONTROL_PASSWORDPOLICYREQUEST;
c.ldctl_value.bv_val = NULL;
c.ldctl_value.bv_len = 0;
c.ldctl_iscritical = 0;
LDAPControl sctrl[3];
sctrl[nsctrls] = c;
LDAPControl *sctrls[4];
sctrls[nsctrls] = &sctrl[nsctrls];
sctrls[++nsctrls] = NULL;
LDAPControl **sctrlsp = NULL;
if ( nsctrls )
{
sctrlsp = sctrls;
}
KString sBindDN = session.ini["ldap_bind_dn"];
ldap_sasl_bind( ld, sBindDN.c_str(), LDAP_SASL_SIMPLE, &pServerPassword,sctrlsp, NULL, &iMsgid );
This is where, if we kept the hashed userPassword value I could search for a uid and userPassword combination. but since my company doesn't keep userPassword, that won't work.
I'm told that the other way to check the password is to bind as the user with the user password. But I need to use a different DN so I'm binding as user? Or I log in as the admin first then do a second bind as the user? And apparently this code is depreciated, but every non-depreciated example code I try to build crashes? Is there something I'm missing? Is there a good working example I use to authenticate users? I know apache can authenticate off of this LDAP server, but I don't know how.
Apache ldap.conf info here:
AuthLDAPURL "ldap://localhost:389/ou=company_account,dc=company,dc=local?sAMAccountName?sub?(objectClass=*)"
AuthLDAPBindDN "cn=ldap,cn=Users,dc=company,dc=local"
AuthLDAPBindPassword "removed"

you need just to perform ldap bind or sasl_bind
void TLDAP::sasl_simple_bind(const std::string & ldapDn, const std::string & ldapPw)
{
struct berval c_passwd = { 0, 0 };
c_passwd.bv_val = const_cast<char*>(ldapPw.c_str());
c_passwd.bv_len = ldapPw.size();
Check(ldap_sasl_bind_s(l.get(), ldapDn.c_str(), LDAP_SASL_SIMPLE, &c_passwd, NULL, NULL, NULL));
}
void TLDAP::simple_bind(const std::string & ldapDn, const std::string & ldapPw)
{
Check(ldap_simple_bind_s(l.get(), ldapDn.c_str(), ldapPw.c_str()));
}
ldap_simple_bind for non-encrypted connection, sasl_bind for encrypted
invocation example:
TLDAP::sasl_simple_bind("andrey#mydomain.local", "1234asdf%^^&");
function Check just checks the return value and throws exception

Related

Add a new password-form programatically to Chromium PasswordStore

Is there a way to clear the local passwords store and add a new password-form to it at runtime?
To be more explicit, its ideal if I can accomplish this from the newtab WebUI component that I'm working on, specifically from the instant_service messages handler that I've added to it in order to process various UI aspects of the NTP page.
Let's assume I have the following code:
autofill::FormData CreateNewLoginFormData(std::string url, std::string actionUrl, std::string formIdOrName,
std::string userField, std::string username,
std::string pwdField, std::string password) {
autofill::FormData form_data;
form_data.url = GURL(url);
form_data.action = GURL(actionUrl);
form_data.name = formIdOrName;
autofill::FormFieldData field;
field.name = userField;
field.id_attribute = field.name;
field.name_attribute = field.name;
field.value = username;
field.form_control_type = "text";
field.unique_id = field.id_attribute;
form_data.fields.push_back(field);
field.name = pwdField;
field.id_attribute = field.name;
field.name_attribute = field.name;
field.value = password;
field.form_control_type = "password";
field.unique_id = field.id_attribute;
form_data.fields.push_back(field);
return form_data;
}
How to add this new FormData to the PasswordStore inside chromium?
Found an answer myself.
The idea is to instantiate the password store for the current profile:
password_manager::PasswordStore* password_store =
static_cast<password_manager::PasswordStore*>(
PasswordStoreFactory::GetForProfile(
profile_, ServiceAccessType::IMPLICIT_ACCESS)
.get());
And later in code add a stored password like this:
password_manager::PasswordForm signin_form;
signin_form.signon_realm = GURL(theLink).spec();
signin_form.password_value = base::UTF8ToUTF16(thePassword);
signin_form.username_value = base::UTF8ToUTF16(theUsername);
signin_form.url = GURL(theLink);
signin_form.skip_zero_click = true;
password_store_->AddLogin(signin_form);

C++ LDAP Checking if a user is a member of a specific group

Been trying this for a while so far with no success, so hoping someone can help out (and that I'm not far off!). I just want to return whether a user is a member of a specific group through LDAP. So far I have the below code;
int authMethod = LDAP_AUTH_SIMPLE;
LDAP* pLdapConnection = NULL;
ULONG version = LDAP_VERSION3;
ULONG getOptSuccess = 0;
ULONG connectSuccess = 0;
INT returnCode = 0;
int retSearch = 0;
LDAPMessage *res;
int num_entries = 0, num_refs = 0;
pLdapConnection = ldap_init((char*)m_Hostname.GetString(), LDAP_PORT);
returnCode = ldap_set_option(pLdapConnection,
LDAP_OPT_PROTOCOL_VERSION,
(void*)&version);
// Connect to the server.
connectSuccess = ldap_connect(pLdapConnection, NULL);
// Bind
returnCode = ldap_bind_s(pLdapConnection, (char*)m_Username.GetString(), (char*)m_Password.GetString(), authMethod);
// Attempt to search for user
retSearch = ldap_search_s(pLdapConnection, "dc=as,dc=local", LDAP_SCOPE_SUBTREE, "(&(sAMAccountName = examplename))", NULL, NULL, &res);
All of this works so far, up until the searching part, for example - I want to search for a user "username" in group "Technical". I've tried things like the below;
retSearch = ldap_search_s(pLdapConnection, "dc=as,dc=local", LDAP_SCOPE_SUBTREE, "(&(sAMAccountName=username)(memberof=CN=Technical))",
nullptr, 0, &pSearchResult);
That does not return anything, so I've tried searching more and the only thing similar I've found is - LDAP Finding Members of a group PHP but it's in PHP and I cannot seem to transfer that over to C++ so far.
Any help in the right direction would be helpful as I cannot work it out. :-)
Your filter should be something like:
(&(objectClass=user)(sAMAccountName=yourUserName)
(memberOf=CN=YourGroup,OU=Users,DC=YourDomain,DC=com))
To include membership due to group nesting:
(&(objectClass=user)(sAMAccountName=yourUserName)
(memberOf:1.2.840.113556.1.4.1941:=cn=YourGroup,ou=Users,dc=YourDomain,dc=com))
The numbers 1.2.840.113556.1.4.1941 are an extended match.

About get event log use EvtOpenSession (Why filling the domain parameter with any text can be success?)

I need to connect to the remote server to read the event log. I use EvtOpenSession function to connect and connect successfully.
My question is: why setting the parameter of Domain to any string will connect successfully?(The actual domain is "testad.com" ex:Set Credentials.Domain = L"123"; or Credentials.Domain = NULL;)
void main()
{
const wchar_t *channelPath = L"Security";
const wchar_t *query = L"Event/System[((EventID=4728) or (EventID = 4729))]";
//Remote handle
EVT_HANDLE hRemoteHandle;
EVT_RPC_LOGIN Credentials;
RtlZeroMemory(&Credentials, sizeof(EVT_RPC_LOGIN));
wstring comp_name = L"TEST-AD"; //server name
wstring user_name = L"<username>";
wstring password = L"<password>";
Credentials.Server = &comp_name[0];
Credentials.Domain = L"testad.com"; //NULL; //L"123"; //Will be connected successfully, No matter what string is
Credentials.User = &user_name[0];
Credentials.Password = &password[0];
Credentials.Flags = EvtRpcLoginAuthNTLM;
hRemoteHandle = EvtOpenSession(EvtRpcLogin, &Credentials, 0, 0);
hResults = EvtQuery(hRemoteHandle , channelPath, query, EvtQueryChannelPath|
EvtQueryForwardDirection);
}

SQLite UPDATE fails to overwrite existing value

I have the following problem that has me stumped. As a note to keep in mind, I am using a precompiled sqlite3.dll rather than Qt's built-in SQLite support.
Table creation code:
CREATE TABLE STUDY(
Name NOT NULL,
UserName NOT NULL REFERENCES USERS(UserName),
Description DEFAULT NULL,
PathToOsirixDB DEFAULT NULL,
PRIMARY KEY(Name, UserName)
)
The following C++ code fails to update the value in column PathToOsirixDB if it already contains a value.
It fails silently, with no error returned. That would imply that no rows are matched in the UPDATE. However, if I take the same UPDATE with valid entries for user and study to match a row and run it via either the SQLite Manager Firefox plugin, or the command line tool, it works properly.
void CStudyDatabase::SetOsirixDBForStudy(const QString user, const QString study, const QString path)
{
if (mp_db)
{
int before = sqlite3_total_changes(mp_db);
QString insert = QString("UPDATE STUDY SET PathToOsirixDB = '%1' WHERE Name = '%2' AND UserName = '%3'").arg(path, study, user);
if (!InsertData(insert))
{
int after = sqlite3_total_changes(mp_db);
if (after - before >= 1)
{
SetOsirixDB(path.toAscii().data());
emit ReturnOsirixDB(osirix_db);
}
else
{
emit DatabaseError(QString("Failed to update the target path."));
}
}
}
}
And for Insert Data
int CStudyDatabase::InsertData(const QString insert)
{
char *err_msg = 0;
int rc = sqlite3_exec(mp_db,
insert.toStdString().c_str(),
NULL,
this,
&err_msg);
if (rc)
SignalDatabaseError(&err_msg);
return rc;
}
Any insights are appreciated. Thank you.
UPDATE: added the following code to SetOsiriXDBForStudy to see if we actually find a row to update:
osirix_db = QString("");
QString query = QString("SELECT PathToOsirixDB FROM STUDY WHERE Name = '%1' AND UserName = '%2'").arg(study, user);
int rc = 0;
char *err_msg = 0;
rc = sqlite3_exec(mp_db,
query.toStdString().c_str(),
&OsirixDBCallback,
this,
&err_msg);
if (rc)
SignalDatabaseError(&err_msg);
if (!(QString(osirix_db).isEmpty()))
studyrowfound = true;
In this case, it leaves osirix_db as an empty string.
But, if I execute this function:
void CStudyDatabase::QueryOsirixDB(const QString user, const QString study)
{
int rc = 0;
char *err_msg = 0;
// we query the OrisixDB via the callback and then emit the signal if all went well
QString query = QString("SELECT PathToOsirixDB FROM STUDY WHERE Name = '%1' AND UserName = '%2'").arg(study, user);
rc = sqlite3_exec(mp_db,
query.toStdString().c_str(),
&OsirixDBCallback,
this,
&err_msg);
if (rc)
SignalDatabaseError(&err_msg);
if (QString(osirix_db).isEmpty())
emit NeedToSetOsirixDB(user, study, QString());
else
emit ReturnOsirixDB(osirix_db);
}
Then it does correctly retrieve the expected value into osirix_db.
Last update: found the problem. It was leading spaces on user and study. Had been staring at the same debugger statements for too long and glossed over the extra spaces. The failing SELECT was a big clue that there was something wrong in the construction of the SQL.
There were leading spaces on user and study. Had been staring at the same debugger statements for too long and glossed over the extra spaces. The failing SELECT was a big clue that there was something wrong in the construction of the SQL.

gsoap c++ android device encoding

8.15,
I can connect my microsoft web service and I can insert record with this service easily.
I get a confirmation code as a response for record insert. But I have a problem with encoding. The response message must like this 1Exa9GwOIO6pP35l4TJ1Bw== but instead of this I get a response like this 4�� u #
When I try this service on a browser I get the expected response as
in 1Exa9GwOIO6pP35l4TJ1Bw==
But when I try it on an android device with gsoap I get a response such as this one 4�� u #
How can I solve this encoding problem?
TheGameSoapProxy service;
_ns1__PlayerRegisterResponse* response = new _ns1__PlayerRegisterResponse();
std::string telNO =m_pEditTel->getText();
std::string telefonIME = "111";
std::string simCardID = "222";
std::string Username = m_pEditName->getText();
std::string takim = Takim.c_str();
_ns1__PlayerRegister* ps = new _ns1__PlayerRegister();
ps->telefonNumarasi = &telNO;
ps->telefonIME = &telefonIME;
ps->simCardID = &simCardID;
ps->Username = &Username;
ps->takim = &takim;
if (service.PlayerRegister(ps, response) == SOAP_OK)
{
string *ptrSonuc = response->PlayerRegisterResult;
CCLog( (char*)ptrSonuc );
}
As per other question here on SO:
add the line below to your typemap.dat file:
xsd__string = | wchar_t* | wchar_t*
And then use wstrings instead of strings.