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

來源:互聯網
上載者:User

一、首先,要弄明白修改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

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.