当前位置: 首页 > 知识库问答 >
问题:

使用Openldap C库在linux中的Active directory中设置下一次登录时重置密码时更改密码

应和悦
2023-03-14
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

是否可以在Linux中使用C语言中的ldap协议重置此Active directory用户的密码(下一次登录时重置密码已设置)?

    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.";
}

共有1个答案

万俟均
2023-03-14

请注意,“更改”密码和“重置”密码被认为是两件不同的事情。

  • 更改密码是当用户提供旧密码和新密码时
  • 重置密码是指用户在不知道旧密码的情况下提供新密码。用户必须对目标帐户具有“重置密码”权限。

UnicodePwd属性的文档中描述了这两种方法的过程。

因此您需要为unicodePwd属性发送LDAP替换操作,并使用所需格式的新密码。所需格式为:

DC要求在UTF-16编码的Unicode字符串中指定密码值,该字符串包含由引号包围的密码,该字符串已按照对象(副本链接)语法被BER编码为二进制八位数字符串。

更改密码

如果Modify请求包含包含unicodePwd值Vdel的delete操作和包含unicodePwd值Vadd的add操作,则服务器将该请求视为更改密码的请求。服务器使用本节后面介绍的密码解码过程对Vadd和Vdel进行解码。Vdel是旧密码,而Vadd是新密码。

为了澄清,您需要发送一个LDAP请求来修改UnicodePwd属性,该属性在同一请求中包含两个操作:

  1. 包含旧密码值的删除操作。知道旧密码后,您才有权更改密码。
  2. 包含新密码值的添加操作。
 类似资料:
  • 我正在尝试通过使用LDAP以编程方式更改用户密码。用户在Active Directory中具有标志“用户必须在下一次登录时更改密码”。但无法通过此用户对Active Directory进行身份验证。我使用了两种LDAP身份验证类型--simple和GSSAPI(Kerberos)。有人能解释一下,当检查“用户必须更改密码”时,Windows自己是如何更改密码的吗?在身份验证时,Kerberos落在

  • 唯一的区别是异常消息中word数据的值。我不想依赖这个消息。如何区分“用户下次登录时必须更改密码”和“密码错误”用例?

  • 本文向大家介绍Linux下SSH免密码登录配置详解,包括了Linux下SSH免密码登录配置详解的使用技巧和注意事项,需要的朋友参考一下 假设有 A、 B 两台 Linux 服务器,我们希望能够从其中一台服务器通过 SSH 免密码登录到另一台服务器。 两台服务器的信息如下:  主机名 IP地址 免密码登录用户名 server1 192.168.12.11 guest1 server2 192.168

  • 本文向大家介绍Linux中禁止用户修改/重置密码,包括了Linux中禁止用户修改/重置密码的使用技巧和注意事项,需要的朋友参考一下 前言 Linux用户的用户名保存在/etc/passwd文件中,密码保存在/etc/shadow中。要禁止用户修改/重置密码,将这两个文件设置为只读即可。 方法如下 要允许修改密码,取消文件上的只读标记: 注意 将这两个文件设置为只读后,附加效果是无法新建新用户。例如

  • 本文向大家介绍Linux配置远程SSH无密码登录,包括了Linux配置远程SSH无密码登录的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了jaLinux配置远程SSH无密码登录的方法,供大家参考,具体内容如下 系统:CentOS 6.8 主机1:192.168.0.177 主机2:192.168.0.178 工具介绍: ssh-keygen:创建公钥和密钥 ssh-copy-id:把

  • 本文向大家介绍在Linux中更改MySQL根密码,包括了在Linux中更改MySQL根密码的使用技巧和注意事项,需要的朋友参考一下 示例 要更改MySQL的root用户密码: 步骤1:停止MySQL服务器。 在Ubuntu或Debian中: sudo /etc/init.d/mysql stop 在CentOS,Fedora或Red Hat Enterprise Linux中: sudo /etc