使用LDAP C API修改a user's password in MS Active Directory

    技术2022-05-20  47

    一、首先,要弄明白修改Windows活动目录中用户的密码需要注意的地方: 1.在活动目录中,用户的密码是unicode编码,所以密码必须由ascii转换成为unicode编码,如下shell命令转换

    [root@local~]echo -n "/"ppAA1234/"" | iconv -f UTF8 -t UTF16LE | base64 -w 0 IgBwAHAAQQBBADEAMgAzADQAIgA=

    2.为了与AD 服务器能正常通信,必须使用SSL连接

    二、示例 #include <stdio.h> #include <stdlib.h> #include <ldap.h> #include <unistd.h>

    using namespace std; #ifndef PASS_LOG #define PASS_LOG(fmt, arg...) printf(fmt, ##arg) #endif

    #define BUF_MAX_LEN 1024 #define PASSWD_MAX_LEN 512 #define AD_LDAP_PORT 636 #define AD_LDAP_URL "ldaps://ad02.example.com:636"

    char g_admin_dn[BUF_MAX_LEN]= "cn=admin,ou=finance,dc=example,dc=com"; char g_admin_pass[BUF_MAX_LEN]= "123456"; //char g_user_dn[BUF_MAX_LEN]= "CN=user_test,OU=finance,DC=example,DC=com"; char g_base_dn[BUF_MAX_LEN]= "ou=finance,dc=example,dc=com";

    int modifyAccountAttributeInActivityDirectory(char *admin_dn, char *admin_pass, char* username, char *user_pass) {     char filter[BUF_MAX_LEN];     char * user_dn = NULL;     LDAP          *ld = NULL;     LDAPMessage   *result = NULL, *element = NULL;     LDAPMod mod, mod2;     LDAPMod *mods[3];     struct berval bvalold;     struct berval bvalnew;     struct berval *bvalsold[2];     struct berval *bvalsnew[2];     char old_password_with_quotes[PASSWD_MAX_LEN], new_password_with_quotes[PASSWD_MAX_LEN];     char old_unicode_password[PASSWD_MAX_LEN *2], new_unicode_password[PASSWD_MAX_LEN* 2];     const char *new_password = NULL;     const char *old_password = "1234PPmm";     int ldap_version = LDAP_VERSION3;     int rc = -1, err_code = -1;     int i = 0;

        if (NULL == admin_dn || NULL == admin_pass || NULL == username || NULL == user_pass)     {         PASS_LOG("modifyAccountAttributeInActivityDirectory: Parameters is NULL/n");         err_code = -1;         goto clean;     }     rc = ldap_initialize(&ld, AD_LDAP_URL);     if ( rc != LDAP_SUCCESS)     {

            ldap_perror( ld, "ldap_initialize" );         PASS_LOG("ldap_initialize: %s/n", ldap_err2string (rc));         err_code = rc;         goto clean;     }     rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ldap_version);     if ( rc != LDAP_SUCCESS)     {         ldap_perror( ld, "ldap_set_option" );         PASS_LOG("ldap_set_option: %s/n", ldap_err2string (rc));         err_code = rc;         goto unbind_ld;     }     rc = ldap_simple_bind_s( ld, admin_dn, admin_pass);     if ( rc != LDAP_SUCCESS  )     {         ldap_perror(ld, "ldap_simple_bind_s" );         PASS_LOG("ldap_simple_bind_s: %s/n", ldap_err2string (rc));         err_code = rc;         goto unbind_ld;     }       memset(filter,0,sizeof(filter));     sprintf(filter,"cn=%s", username);     rc = ldap_search_s(ld,                          g_base_dn,                          LDAP_SCOPE_SUBTREE,                          filter,                          NULL,                          0,                          &result);      if (rc  != LDAP_SUCCESS)      {         ldap_perror( ld, "ldap_search_s" );         PASS_LOG("ldap_search_s: %s/n", ldap_err2string (rc));         err_code = rc;         goto unbind_ld;      }

        for ( element= ldap_first_entry( ld, result ); element != NULL;  element = ldap_next_entry( ld, element ) )     {             user_dn = ldap_get_dn(ld, element);                  PASS_LOG("dn:%s/n", user_dn);        }     if (user_dn == NULL)     {       PASS_LOG("dn is NULL/n");       err_code = -1;       goto free_msg;     }

        new_password = user_pass;     memset(new_password_with_quotes, 0, sizeof(new_password_with_quotes));     snprintf (new_password_with_quotes, sizeof (new_password_with_quotes), "/"%s/"", new_password);     memset (new_unicode_password, 0, sizeof (new_unicode_password));     for (i = 0; i < strlen (new_password_with_quotes); i++)     {         new_unicode_password[i * 2] = new_password_with_quotes[i];     }     bvalnew.bv_val = new_unicode_password;     bvalnew.bv_len = strlen (new_password_with_quotes) * 2;

        bvalsnew[0] = &bvalnew;     bvalsnew[1] = NULL;     mod.mod_vals.modv_bvals = bvalsnew;     mod.mod_type = (char *) "unicodePwd";     #if 0     /* user must supply old password */     memset(old_password_with_quotes, 0, sizeof(old_password_with_quotes));     snprintf (old_password_with_quotes,             sizeof (old_password_with_quotes), "/"%s/"",             old_password);     memset (old_unicode_password, 0, sizeof (old_unicode_password));     for (i = 0; i < strlen (old_password_with_quotes); i++)     {     old_unicode_password[i * 2] = old_password_with_quotes[i];     }     bvalold.bv_val = old_unicode_password;     bvalold.bv_len = strlen (old_password_with_quotes) * 2;

        bvalsold[0] = &bvalold;     bvalsold[1] = NULL;     mod2.mod_vals.modv_bvals = bvalsold;     mod2.mod_type = (char *) "unicodePwd";     mod2.mod_op = LDAP_MOD_DELETE | LDAP_MOD_BVALUES;

        mod.mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;

        mods[0] = &mod2;     mods[1] = &mod;     mods[2] = NULL;

    #else     mod.mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;     mods[0] = &mod;     mods[1] = NULL; #endif

        rc = ldap_modify_s(ld, user_dn, mods);     if (rc  != LDAP_SUCCESS)     {         ldap_perror( ld, "ldap_modify_s" );         PASS_LOG("ldap_modify_s: %s/n", ldap_err2string (rc));     }     err_code = rc;     PASS_LOG("Modify account's attribute in activity directory Ok/n");     if (NULL != ld)     {         free(user_dn);     }

    free_msg:       if (NULL != result)     {         ldap_msgfree(result);     } unbind_ld:     if (NULL != ld)     {         ldap_unbind(ld);     } clean:     return err_code; }

    int main(int argc, char *argv[]) {     char *new_password = "ooXX1234";     if (modifyAccountAttributeInActivityDirectory(g_admin_dn, g_admin_pass, "user_test", new_password) < 0)     {         PASS_LOG("Failed to modify account's attribute in activity directory");         return -1;     }

        return 0; }

    [root@local~]g++ change_passwd.cpp -lldap -g  -DLDAP_DEPRECATED=1  -o change_passwd

    三、CA证书

    [root@local~]# ./change_passwd  ldap_simple_bind_s: Can't contact LDAP server (-1)         additional info: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed 解决方法: 1. 从域控导出.cer文件 2. 把该cer文件格式改为pem        [root@local~]#openssl x509 -inform DER -in /root/ad02.cer -out /root/ad02.pem -outform PEM 3.配置/etc/openldap/ldap.conf [root@local~]#vim /etc/openldap/ldap.conf use_sasl        on ssl             on sasl            start_tls SASL_MECH       GSSAPI tls_checkpeer   no tls_ciphers     TLSv1 TLS_REQCERT     never chasereferrals  yes deref           always uri             ldaps://ad02.example.com:636 binddn          cn=admin,ou=finance,dc=example,dc=com

    # Tell GSSAPI not to negotiate a security or privacy layer since # AD doesn't support nested security or privacy layers sasl_secprops   minssf=0,maxssf=0 tls_cacertfile  /root/ad02.pem [root@local~]#./change_passwd Modify account's attribute in activity directory Ok

    Creating Active Directory Accounts

    四、参考资料

    OpenLDAP Server With Server-Side SSL/TLS and Client Authentication(最具价值参考ldap_initialize)

    pam_ldap.c中_get_authtok(最具价值参考 unicode转换)

    LDAP Authentication and Password Management

    如何更改通过 LDAP 的 Windows 2000 用户的密码

    启用 LDAP 客户端通过 SSL 与 LDAP 服务器进行通信的说明

    LDAP C programming development - SDK Man Pages

    Mozilla LDAP C SDK Programmer's Guide

    ldap 636   Java Python  C# Cold Fusion Perl PHP Ruby


    最新回复(0)