Я пытаюсь сбросить пароль для пользователя активного каталога, для которого установлен «сброс пароля при следующем входе в систему», используя открытый код ldap c, который похож на код ldapmodify. Но ldap_bind завершается неудачно с неверными учетными данными, с данными 773 (код ошибки истек срок действия пароля).
ldapmodify -v -x -ZZ -H ldap://<ldap> -D "cn=fi_user,cn=users,dc=qa01,dc=eng,dc=user,dc=com" -w oldpassword -f ~/old_to_new.ldif
ldap_initialize( ldap://<ldap>/??base )
ldap_bind: Invalid credentials (49)
additional info: 80090308: LdapErr: DSID-0C09042F, comment: AcceptSecurityContext error, data 773, v2580
Возможно ли сбросить пароль для этого пользователя Active Directory (задан сброс пароля при следующем входе в систему) с использованием протокола ldap в C в linux?
vector<string> Split(string& s, string delim) {
vector<string> ret;
auto start = 0U;
auto end = s.find(delim);
while (end != std::string::npos) {
ret.push_back(s.substr(start, end - start));
start = end + delim.length();
end = s.find(delim, start);
}
ret.push_back(s.substr(start));
return ret;
}
void SetLDAPModPassword(LDAPMod* ldap_mod, string& password) {
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
std::u16string utf16_curr_pass = convert.from_bytes("\"" + password + "\"");
struct berval** ber_arr = new struct berval*[2];
ber_arr[1] = NULL;
ber_arr[0] = new struct berval;
ber_arr[0]->bv_val = new char[utf16_curr_pass.size() * 2];
memcpy(ber_arr[0]->bv_val,
utf16_curr_pass.data(),
utf16_curr_pass.size() * 2);
ber_arr[0]->bv_len = utf16_curr_pass.size() * 2;
ldap_mod->mod_vals.modv_bvals = ber_arr;
}
string SetLdapOptions(LDAP* ldap_handle) {
stringstream ss;
int ret = ldap_set_option(ldap_handle, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
if (ret != LDAP_OPT_SUCCESS) {
ss << "ldap_set_option LDAP_OPT_REFERRALS to LDAP_OPT_OFF failed: "
<< ldap_err2string(ret);
return ss.str();
}
const int ldap_version = LDAP_VERSION3;
ret = ldap_set_option(ldap_handle, LDAP_OPT_PROTOCOL_VERSION, &ldap_version);
if (ret != LDAP_OPT_SUCCESS) {
ss << "ldap_set_option LDAP_OPT_PROTOCOL_VERSION to " << ldap_version
<< " failed: " << ldap_err2string(ret);
return ss.str();
}
const int cert_flag = LDAP_OPT_X_TLS_NEVER;
ret = ldap_set_option(nullptr, LDAP_OPT_X_TLS_REQUIRE_CERT, &cert_flag);
if (ret != LDAP_OPT_SUCCESS) {
ss << "ldap_set_option LDAP_OPT_X_TLS_REQUIRE_CERT to "
"LDAP_OPT_X_TLS_NEVER failed: "
<< ldap_err2string(ret);
return ss.str();
}
ret = ldap_start_tls_s(ldap_handle, NULL, NULL );
if (ret != LDAP_SUCCESS) {
ss << "ldap_start_tls_s failed: " << ldap_err2string(ret);
return ss.str();
}
int timelimit = 15;
struct timeval timeout = {.tv_sec = timelimit, .tv_usec = 0};
ret = ldap_set_option(ldap_handle, LDAP_OPT_NETWORK_TIMEOUT, &timeout);
if (ret != LDAP_OPT_SUCCESS) {
ss << "ldap_set_option LDAP_OPT_NETWORK_TIMEOUT to "
"LDAP_OPT_X_TLS_NEVER failed: "
<< ldap_err2string(ret);
return ss.str();
}
ret = ldap_set_option(ldap_handle, LDAP_OPT_TIMELIMIT, &timelimit);
if (ret != LDAP_OPT_SUCCESS) {
ss << "ldap_set_option LDAP_OPT_TIMELIMIT to " << timelimit
<< " failed: " << ldap_err2string(ret);
return ss.str();
}
ret = ldap_set_option(ldap_handle, LDAP_OPT_TIMEOUT, &timeout);
if (ret != LDAP_OPT_SUCCESS) {
ss << "ldap_set_option LDAP_OPT_TIMEOUT to "
<< timeout.tv_sec << " failed: " << ldap_err2string(ret);
}
return ss.str();
}
string ChangeActiveDirectoryPassword(string domain_controller,
string domain,
string username,
string curr_password,
string new_password) {
int ret;
LDAP* ldap_handle = nullptr;
char passwd_attr[16] = "unicodePwd";
std::stringstream ss;
ss << "ldap://" << domain_controller << ":389";
LOG(INFO) << ss.str();
ret = ldap_initialize(&ldap_handle, ss.str().c_str());
ss.str(std::string());
if (ret != LDAP_SUCCESS) {
ss << "ldap_initialize failed: " << ldap_err2string(ret);
return ss.str();
}
string ret_err = SetLdapOptions(ldap_handle);
if (!ret_err.empty()) {
return ret_err;
}
stringstream domain_stream;
domain_stream << "CN=" << FLAGS_username << ",CN=Users,";
vector<string> split_string_vec = Split(domain, ".");
int ii = 0;
for (auto subdomain : split_string_vec) {
if (ii != 0) {
domain_stream << ",";
}
domain_stream << string("DC=") << subdomain;
ii++;
}
string domain_string = domain_stream.str();
struct berval passwd_berval;
passwd_berval.bv_len = curr_password.size();
passwd_berval.bv_val = new char[curr_password.size() + 1];
strcpy(passwd_berval.bv_val, curr_password.c_str());
LOG(INFO) << domain_string;
struct berval* servercredp;
ret = ldap_sasl_bind_s(ldap_handle,
domain_string.c_str(),
LDAP_SASL_SIMPLE,
&passwd_berval,
NULL,
NULL,
&servercredp);
delete[] passwd_berval.bv_val;
if (ret != LDAP_SUCCESS) {
ss << "ldap_sasl_bind_s failed: " << ldap_err2string(ret);
//return ss.str();
}
LDAPMod delete_old_pass;
memset(&delete_old_pass, 0, sizeof(LDAPMod));
char unicode_str[16] = "unicodePwd";;
delete_old_pass.mod_op = LDAP_MOD_DELETE | LDAP_MOD_BVALUES;
delete_old_pass.mod_type = unicode_str;
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
std::u16string utf16_curr_pass =
convert.from_bytes("\"" + FLAGS_curr_passwd + "\"");
struct berval** del_ber_arr = new struct berval*[2];
del_ber_arr[1] = NULL;
del_ber_arr[0] = new struct berval;
del_ber_arr[0]->bv_val = new char[utf16_curr_pass.size() * 2];
memcpy(del_ber_arr[0]->bv_val,
utf16_curr_pass.data(),
utf16_curr_pass.size() * 2);
del_ber_arr[0]->bv_len = utf16_curr_pass.size() * 2;
delete_old_pass.mod_vals.modv_bvals = del_ber_arr;
LDAPMod add_new_pass;
LDAPMod *add_new_pass_pointer = &add_new_pass;
memset(&add_new_pass, 0, sizeof(LDAPMod));
add_new_pass.mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
add_new_pass.mod_type = unicode_str;
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert1;
std::u16string utf16_new_pass =
convert1.from_bytes("\"" + FLAGS_new_passwd + "\"");
struct berval** add_ber_arr = new struct berval*[2];
add_ber_arr[1] = NULL;
add_ber_arr[0] = new struct berval;
add_ber_arr[0]->bv_val = new char[utf16_new_pass.size() * 2];
memcpy(add_ber_arr[0]->bv_val,
utf16_new_pass.data(),
utf16_new_pass.size() * 2);
add_ber_arr[0]->bv_len = utf16_new_pass.size() * 2;
add_new_pass.mod_vals.modv_bvals = add_ber_arr;
LDAPMod *mods[3];
mods[0] = &delete_old_pass;
mods[1] = &add_new_pass;
mods[2] = NULL;
ret = ldap_modify_ext_s(
ldap_handle,
domain.c_str(),
mods,
NULL,
NULL);
CHECK_EQ(ret, LDAP_SUCCESS)
<< "ldap_modify_ext_s() failed." << ldap_err2string(ret) << " dn "
<< domain << " pass " << curr_passwd.bv_val;
ldap_destroy(ldap_handle);
LOG(INFO) << "LDAP password changed.";
}