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

一、首先,要弄明白修改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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值