diff options
Diffstat (limited to 'ldap/servers/slapd/bind.c')
-rw-r--r-- | ldap/servers/slapd/bind.c | 710 |
1 files changed, 710 insertions, 0 deletions
diff --git a/ldap/servers/slapd/bind.c b/ldap/servers/slapd/bind.c new file mode 100644 index 00000000..ab9ca89d --- /dev/null +++ b/ldap/servers/slapd/bind.c @@ -0,0 +1,710 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* bind.c - decode an ldap bind operation and pass it to a backend db */ + +/* + * Copyright (c) 1995 Regents of the University of Michigan. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and that due credit is given + * to the University of Michigan at Ann Arbor. The name of the University + * may not be used to endorse or promote products derived from this + * software without specific prior written permission. This software + * is provided ``as is'' without express or implied warranty. + */ + +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#ifndef _WIN32 +#include <sys/socket.h> +#endif +#include "slap.h" +#include "fe.h" + +#include "pratom.h" +#include <sasl.h> + +static void log_bind_access( + Slapi_PBlock *pb, + const char* dn, + int method, + int version, + const char *saslmech, + const char *msg +); + + +/* + * Function: is_root_dn_pw + * + * Returns: 1 if the password for the root dn is correct. + * 0 otherwise. + * dn must be normalized + * + */ +static int +is_root_dn_pw( const char *dn, const Slapi_Value *cred ) +{ + int rv= 0; + char *rootpw = config_get_rootpw(); + if ( rootpw == NULL || !slapi_dn_isroot( dn ) ) + { + rv = 0; + } + else + { + Slapi_Value rdnpwbv; + Slapi_Value *rdnpwvals[2]; + slapi_value_init_string(&rdnpwbv,rootpw); + rdnpwvals[ 0 ] = &rdnpwbv; + rdnpwvals[ 1 ] = NULL; + rv = slapi_pw_find_sv( rdnpwvals, cred ) == 0; + value_done(&rdnpwbv); + } + slapi_ch_free( (void **) &rootpw ); + return rv; +} + +void +do_bind( Slapi_PBlock *pb ) +{ + BerElement *ber = pb->pb_op->o_ber; + int err, version = -1, method = -1, isroot; + long long_method = -1; + long ber_version = -1; + int auth_response_requested = 0; + int pw_response_requested = 0; + char *dn, *saslmech = NULL; + struct berval cred = {0}; + Slapi_Backend *be = NULL; + unsigned long rc; + Slapi_DN sdn; + Slapi_Entry *referral; + char errorbuf[BUFSIZ]; + char **supported, **pmech; + char authtypebuf[256]; /* >26 (strlen(SLAPD_AUTH_SASL)+SASL_MECHNAMEMAX+1) */ + Slapi_Entry *bind_target_entry = NULL; + + LDAPDebug( LDAP_DEBUG_TRACE, "do_bind\n", 0, 0, 0 ); + + /* + * Parse the bind request. It looks like this: + * + * BindRequest ::= SEQUENCE { + * version INTEGER, -- version + * name DistinguishedName, -- dn + * authentication CHOICE { + * simple [0] OCTET STRING, -- passwd + * krbv42ldap [1] OCTET STRING, -- not used + * krbv42dsa [2] OCTET STRING, -- not used + * sasl [3] SaslCredentials -- v3 only + * } + * } + * + * Saslcredentials ::= SEQUENCE { + * mechanism LDAPString, + * credentials OCTET STRING + * } + */ + + rc = ber_scanf( ber, "{iat", &ber_version, &dn, &long_method ); + method = long_method; + version = ber_version; + if ( rc == LBER_ERROR ) { + LDAPDebug( LDAP_DEBUG_ANY, + "ber_scanf failed (op=Bind; params=Version,DN,Method)\n", + 0, 0, 0 ); + log_bind_access (pb, "???", method, version, saslmech, "decoding error"); + send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, + "decoding error", 0, NULL ); + return; + } + + slapi_sdn_init_dn_passin(&sdn,dn); + + LDAPDebug( LDAP_DEBUG_TRACE, "BIND dn=\"%s\" method=%d version=%d\n", + dn, method, version ); + + /* target spec is used to decide which plugins are applicable for the operation */ + operation_set_target_spec (pb->pb_op, &sdn); + + switch ( method ) { + case LDAP_AUTH_SASL: + if ( version < LDAP_VERSION3 ) { + LDAPDebug( LDAP_DEBUG_ANY, + "got SASL credentials from LDAPv2 client\n", + 0, 0, 0 ); + log_bind_access (pb, slapi_sdn_get_dn (&sdn), method, version, saslmech, "SASL credentials only in LDAPv3"); + send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, + "SASL credentials only in LDAPv3", 0, NULL ); + goto free_and_return; + } + /* Get the SASL mechanism */ + rc = ber_scanf( ber, "{a", &saslmech ); + /* Get the (optional) SASL credentials */ + if ( rc != LBER_ERROR ) { + /* Credentials are optional in SASL bind */ + unsigned long clen; + if (( ber_peek_tag( ber, &clen )) == LBER_OCTETSTRING ) { + rc = ber_scanf( ber, "o}}", &cred ); + } else { + rc = ber_scanf( ber, "}}" ); + } + } + break; + case LDAP_AUTH_KRBV41: + /* FALLTHROUGH */ + case LDAP_AUTH_KRBV42: + if ( version >= LDAP_VERSION3 ) { + static char *kmsg = + "LDAPv2-style kerberos authentication received " + "on LDAPv3 connection."; + LDAPDebug( LDAP_DEBUG_ANY, kmsg, 0, 0, 0 ); + log_bind_access (pb, slapi_sdn_get_dn (&sdn), method, version, saslmech, kmsg); + send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, + kmsg, 0, NULL ); + goto free_and_return; + } + /* FALLTHROUGH */ + case LDAP_AUTH_SIMPLE: + rc = ber_scanf( ber, "o}", &cred ); + break; + default: + log_bind_access (pb, slapi_sdn_get_dn (&sdn), method, version, saslmech, "Unknown bind method"); + send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, + "Unknown bind method", 0, NULL ); + goto free_and_return; + } + if ( rc == LBER_ERROR ) { + LDAPDebug( LDAP_DEBUG_ANY, + "ber_scanf failed (op=Bind; params=Credentials)\n", + 0, 0, 0 ); + log_bind_access (pb, slapi_sdn_get_dn (&sdn), method, version, saslmech, "decoding error"); + send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, + "decoding error", 0, NULL ); + goto free_and_return; + } + + /* + * in LDAPv3 there can be optional control extensions on + * the end of an LDAPMessage. we need to read them in and + * pass them to the backend. + * We also check for the presence of an "Authentication Request + * Control" and set a flag so we know later whether we need to send + * an "Authentication Response Control" with Success responses. + */ + { + LDAPControl **reqctrls; + + if (( err = get_ldapmessage_controls( pb, ber, &reqctrls )) + != 0 ) { + log_bind_access (pb, slapi_sdn_get_dn (&sdn), method, + version, saslmech, "failed to parse LDAP controls"); + send_ldap_result( pb, err, NULL, NULL, 0, NULL ); + goto free_and_return; + } + + auth_response_requested = slapi_control_present( reqctrls, + LDAP_CONTROL_AUTH_REQUEST, NULL, NULL ); + slapi_pblock_get (pb, SLAPI_PWPOLICY, &pw_response_requested); + } + + log_bind_access(pb, dn, method, version, saslmech, NULL); + + /* According to RFC2251, + * "if the bind fails, the connection will be treated as anonymous". + */ + PR_Lock( pb->pb_conn->c_mutex ); + bind_credentials_clear( pb->pb_conn, PR_FALSE, /* conn is already locked */ + PR_FALSE /* do not clear external creds. */ ); + /* Clear the password policy flag that forbid operation + * other than Bind, Modify, Unbind : + * With a new bind, the flag should be reset so that the new + * bound user can work properly + */ + pb->pb_conn->c_needpw = 0; + PR_Unlock( pb->pb_conn->c_mutex ); + + switch ( version ) { + case LDAP_VERSION2: + if (method == LDAP_AUTH_SIMPLE + && (dn == NULL || *dn == '\0') && cred.bv_len == 0 + && pb->pb_conn->c_external_dn != NULL) { + /* Treat this like a SASL EXTERNAL Bind: */ + method = LDAP_AUTH_SASL; + saslmech = slapi_ch_strdup (LDAP_SASL_EXTERNAL); + /* This enables a client to establish an identity by sending + * a certificate in the SSL handshake, and also use LDAPv2 + * (by sending this type of Bind request). + */ + } + break; + case LDAP_VERSION3: + break; + default: + LDAPDebug( LDAP_DEBUG_TRACE, "bind: unknown LDAP protocol version %d\n", + version, 0, 0 ); + send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, + "version not supported", 0, NULL ); + goto free_and_return; + } + + LDAPDebug( LDAP_DEBUG_TRACE, "do_bind: version %d method 0x%x dn %s\n", + version, method, dn ); + pb->pb_conn->c_ldapversion = version; + + isroot = slapi_dn_isroot( slapi_sdn_get_ndn(&sdn) ); + slapi_pblock_set( pb, SLAPI_REQUESTOR_ISROOT, &isroot ); + slapi_pblock_set( pb, SLAPI_BIND_TARGET, (void*)slapi_sdn_get_ndn(&sdn) ); + slapi_pblock_set( pb, SLAPI_BIND_METHOD, &method ); + slapi_pblock_set( pb, SLAPI_BIND_SASLMECHANISM, saslmech ); + slapi_pblock_set( pb, SLAPI_BIND_CREDENTIALS, &cred ); + + if (method != LDAP_AUTH_SASL) { + /* + * RFC2251: client may abort a sasl bind negotiation by sending + * an authentication choice other than sasl. + */ + pb->pb_conn->c_flags &= ~CONN_FLAG_SASL_CONTINUE; + } + + switch ( method ) { + case LDAP_AUTH_SASL: + /* + * All SASL auth methods are categorized as strong binds, + * although they are not necessarily stronger than simple. + */ + PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsStrongAuthBinds); + if ( saslmech == NULL || *saslmech == '\0' ) { + send_ldap_result( pb, LDAP_AUTH_METHOD_NOT_SUPPORTED, NULL, + "SASL mechanism absent", 0, NULL ); + goto free_and_return; + } + + if (strlen(saslmech) > SASL_MECHNAMEMAX) { + send_ldap_result( pb, LDAP_AUTH_METHOD_NOT_SUPPORTED, NULL, + "SASL mechanism name is too long", 0, NULL ); + goto free_and_return; + } + + supported = slapi_get_supported_saslmechanisms_copy(); + if ( (pmech = supported) != NULL ) while (1) { + if (*pmech == NULL) { + /* As we call the safe function, we receive a strdup'd saslmechanisms + charray. Therefore, we need to remove it instead of NULLing it */ + charray_free(supported); + pmech = supported = NULL; + break; + } + if (!strcasecmp (saslmech, *pmech)) break; + ++pmech; + } + if (!pmech) { + /* now check the sasl library */ + ids_sasl_check_bind(pb); + goto free_and_return; + } + else { + charray_free(supported); /* Avoid leaking */ + } + + if (!strcasecmp (saslmech, LDAP_SASL_EXTERNAL)) { + /* + * if this is not an SSL connection, fail and return an + * inappropriateAuth error. + */ + if ( 0 == ( pb->pb_conn->c_flags & CONN_FLAG_SSL )) { + send_ldap_result( pb, LDAP_INAPPROPRIATE_AUTH, NULL, + "SASL EXTERNAL bind requires an SSL connection", + 0, NULL ); + goto free_and_return; + } + + /* + * if the client sent us a certificate but we could not map it + * to an LDAP DN, fail and return an invalidCredentials error. + */ + if ( NULL != pb->pb_conn->c_client_cert && + NULL == pb->pb_conn->c_external_dn ) { + send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL, + "client certificate mapping failed", 0, NULL ); + goto free_and_return; + } + + /* + * copy external credentials into connection structure + */ + bind_credentials_set( pb->pb_conn, + pb->pb_conn->c_external_authtype, + pb->pb_conn->c_external_dn, + NULL, NULL, NULL , NULL); + if ( auth_response_requested ) { + add_auth_response_control( pb, pb->pb_conn->c_external_dn ); + } + send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL ); + goto free_and_return; + } + break; + case LDAP_AUTH_SIMPLE: + PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsSimpleAuthBinds); + /* accept null binds */ + if (dn == NULL || *dn == '\0') { + PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsAnonymousBinds); + /* by definition its anonymous is also UnAuthenticated so increment + that counter */ + PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsUnAuthBinds); + + /* call preop plugins */ + if (plugin_call_plugins( pb, SLAPI_PLUGIN_PRE_BIND_FN ) == 0){ + if ( auth_response_requested ) { + add_auth_response_control( pb, "" ); + } + send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL ); + + /* call postop plugins */ + plugin_call_plugins( pb, SLAPI_PLUGIN_POST_BIND_FN ); + } + goto free_and_return; + } + break; + default: + break; + } + + /* + * handle binds as the manager here, pass others to the backend + */ + + if ( isroot && method == LDAP_AUTH_SIMPLE ) { + if ( cred.bv_len == 0 ) { + /* unauthenticated bind */ + PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsUnAuthBinds); + + } else { + /* a passwd was supplied -- check it */ + Slapi_Value cv; + slapi_value_init_berval(&cv,&cred); + + if ( is_root_dn_pw( slapi_sdn_get_ndn(&sdn), &cv )) { + /* right dn and passwd - authorize */ + bind_credentials_set( pb->pb_conn, SLAPD_AUTH_SIMPLE, + slapi_ch_strdup( slapi_sdn_get_ndn(&sdn) ), + NULL, NULL, NULL , NULL); + + /* right dn, wrong passwd - reject with invalid creds */ + } else { + send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL, + NULL, 0, NULL ); + /* increment BindSecurityErrorcount */ + PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsBindSecurityErrors); + value_done(&cv); + goto free_and_return; + } + value_done(&cv); + } + + /* call preop plugin */ + if (plugin_call_plugins( pb, SLAPI_PLUGIN_PRE_BIND_FN ) == 0){ + if ( auth_response_requested ) { + add_auth_response_control( pb, + ( cred.bv_len == 0 ) ? "" : + slapi_sdn_get_ndn(&sdn)); + } + send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL ); + + /* call postop plugins */ + plugin_call_plugins( pb, SLAPI_PLUGIN_POST_BIND_FN ); + } + goto free_and_return; + } + + /* We could be serving multiple database backends. Select the appropriate one */ + if (slapi_mapping_tree_select(pb, &be, &referral, errorbuf) != LDAP_SUCCESS) { + send_nobackend_ldap_result( pb ); + be = NULL; + goto free_and_return; + } + + if (referral) + { + send_referrals_from_entry(pb,referral); + slapi_entry_free(referral); + goto free_and_return; + } + + slapi_pblock_set( pb, SLAPI_BACKEND, be ); + + /* not root dn - pass to the backend */ + if ( be->be_bind != NULL ) { + + /* + * call the pre-bind plugins. if they succeed, call + * the backend bind function. then call the post-bind + * plugins. + */ + if ( plugin_call_plugins( pb, SLAPI_PLUGIN_PRE_BIND_FN ) + == 0 ) { + int rc = 0; + + /* + * Is this account locked ? + * could be locked through the account inactivation + * or by the password policy + * + * rc=0: account not locked + * rc=1: account locked, can not bind, result has been sent + * rc!=0 and rc!=1: error. Result was not sent, lets be_bind + * deal with it. + * + */ + + /* get the entry now, so that we can give it to check_account_lock and reslimit_update_from_dn */ + if (! slapi_be_is_flag_set(be, SLAPI_BE_FLAG_REMOTE_DATA)) { + bind_target_entry = get_entry(pb, slapi_sdn_get_ndn(&sdn)); + rc = check_account_lock ( pb, bind_target_entry, pw_response_requested); + } + + slapi_pblock_set( pb, SLAPI_PLUGIN, be->be_database ); + set_db_default_result_handlers(pb); + if ( (rc != 1) && (((rc = (*be->be_bind)( pb )) + == SLAPI_BIND_SUCCESS ) || rc + == SLAPI_BIND_ANONYMOUS )) { + long t; + { + char* authtype = NULL; + switch ( method ) { + case LDAP_AUTH_SIMPLE: + if (cred.bv_len != 0) { + authtype = SLAPD_AUTH_SIMPLE; + } + break; + case LDAP_AUTH_SASL: + /* authtype = SLAPD_AUTH_SASL && saslmech: */ + sprintf(authtypebuf, "%s%s", SLAPD_AUTH_SASL, saslmech); + authtype = authtypebuf; + break; + default: /* ??? */ + break; + } + + if ( rc == SLAPI_BIND_SUCCESS ) { + bind_credentials_set( pb->pb_conn, + authtype, slapi_ch_strdup( + slapi_sdn_get_ndn(&sdn)), + NULL, NULL, NULL, bind_target_entry ); + if ( auth_response_requested ) { + add_auth_response_control( pb, + slapi_sdn_get_ndn(&sdn)); + } + } else { /* anonymous */ + if ( auth_response_requested ) { + add_auth_response_control( pb, + "" ); + } + } + } + + if ( rc != SLAPI_BIND_ANONYMOUS && + ! slapi_be_is_flag_set(be, + SLAPI_BE_FLAG_REMOTE_DATA)) { + /* check if need new password before sending + the bind success result */ + switch ( need_new_pw (pb, &t, bind_target_entry, pw_response_requested )) { + + case 1: + (void)add_pwd_control ( pb, + LDAP_CONTROL_PWEXPIRED, 0); + break; + + case 2: + (void)add_pwd_control ( pb, + LDAP_CONTROL_PWEXPIRING, t); + break; + case -1: + goto free_and_return; + default: + break; + } + } /* end if */ + }else{ + + if(cred.bv_len == 0) { + /* its an UnAuthenticated Bind, DN specified but no pw */ + PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsUnAuthBinds); + }else{ + /* password must have been invalid */ + /* increment BindSecurityError count */ + PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsBindSecurityErrors); + } + + } + + /* + * if rc != SLAPI_BIND_SUCCESS and != SLAPI_BIND_ANONYMOUS, + * the result has already been sent by the backend. otherwise, + * we assume it is success and send it here to avoid a race + * condition where the client could be told by the + * backend that the bind succeeded before we set the + * c_dn field in the connection structure here in + * the front end. + */ + if ( rc == SLAPI_BIND_SUCCESS || rc == SLAPI_BIND_ANONYMOUS) { + send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, + 0, NULL ); + } + + slapi_pblock_set( pb, SLAPI_PLUGIN_OPRETURN, &rc ); + plugin_call_plugins( pb, SLAPI_PLUGIN_POST_BIND_FN ); + } + } else { + send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL, + "Function not implemented", 0, NULL ); + } + + free_and_return:; + if (be) + slapi_be_Unlock(be); + slapi_sdn_done(&sdn); + if ( saslmech != NULL ) { + free( saslmech ); + } + if ( cred.bv_val != NULL ) { + free( cred.bv_val ); + } + if ( bind_target_entry != NULL ) + slapi_entry_free(bind_target_entry); +} + + +/* + * register all of the LDAPv3 SASL mechanisms we know about. + */ +void +init_saslmechanisms( void ) +{ + ids_sasl_init(); + slapi_register_supported_saslmechanism( LDAP_SASL_EXTERNAL ); +} + +static void +log_bind_access ( + Slapi_PBlock *pb, + const char* dn, + int method, + int version, + const char *saslmech, + const char *msg +) +{ + char ebuf[ BUFSIZ ]; + const char *edn; + + edn = escape_string( dn, ebuf ); + + if (method == LDAP_AUTH_SASL && saslmech && msg) { + slapi_log_access( LDAP_DEBUG_STATS, + "conn=%d op=%d BIND dn=\"%s\" " + "method=sasl version=%d mech=%s, %s\n", + pb->pb_conn->c_connid, pb->pb_op->o_opid, edn, + version, saslmech, msg ); + } else if (method == LDAP_AUTH_SASL && saslmech) { + slapi_log_access( LDAP_DEBUG_STATS, + "conn=%d op=%d BIND dn=\"%s\" " + "method=sasl version=%d mech=%s\n", + pb->pb_conn->c_connid, pb->pb_op->o_opid, edn, + version, saslmech ); + } else if (msg) { + slapi_log_access( LDAP_DEBUG_STATS, + "conn=%d op=%d BIND dn=\"%s\" " + "method=%d version=%d, %s\n", + pb->pb_conn->c_connid, pb->pb_op->o_opid, edn, + method, version, msg ); + } else { + slapi_log_access( LDAP_DEBUG_STATS, + "conn=%d op=%d BIND dn=\"%s\" " + "method=%d version=%d\n", + pb->pb_conn->c_connid, pb->pb_op->o_opid, edn, + method, version ); + } +} + + +void +add_auth_response_control( Slapi_PBlock *pb, const char *binddn ) +{ + LDAPControl arctrl; + char dnbuf_fixedsize[ 512 ], *dnbuf, *dnbuf_dynamic = NULL; + size_t dnlen; + + if ( NULL == binddn ) { + binddn = ""; + } + dnlen = strlen( binddn ); + + /* + * According to draft-weltman-ldapv3-auth-response-03.txt section + * 4 (Authentication Response Control): + * + * The controlType is "2.16.840.1.113730.3.4.15". If the bind request + * succeeded and resulted in an identity (not anonymous), the + * controlValue contains the authorization identity [AUTH] granted to + * the requestor. If the bind request resulted in anonymous + * authentication, the controlValue field is a string of zero length. + * + * [AUTH] is a reference to RFC 2829, which in section 9 defines + * authorization identity as: + * + * + * The authorization identity is a string in the UTF-8 character set, + * corresponding to the following ABNF [7]: + * + * ; Specific predefined authorization (authz) id schemes are + * ; defined below -- new schemes may be defined in the future. + * + * authzId = dnAuthzId / uAuthzId + * + * ; distinguished-name-based authz id. + * dnAuthzId = "dn:" dn + * dn = utf8string ; with syntax defined in RFC 2253 + * + * ; unspecified userid, UTF-8 encoded. + * uAuthzId = "u:" userid + * userid = utf8string ; syntax unspecified + * + * A utf8string is defined to be the UTF-8 encoding of one or more ISO + * 10646 characters. + * + * We always map identities to DNs, so we always use the dnAuthzId form. + */ + arctrl.ldctl_oid = LDAP_CONTROL_AUTH_RESPONSE; + arctrl.ldctl_iscritical = 0; + + if ( dnlen == 0 ) { /* anonymous -- return zero length value */ + arctrl.ldctl_value.bv_val = ""; + arctrl.ldctl_value.bv_len = 0; + } else { /* mapped to a DN -- return "dn:<DN>" */ + if ( 3 + dnlen < sizeof( dnbuf_fixedsize )) { + dnbuf = dnbuf_fixedsize; + } else { + dnbuf = dnbuf_dynamic = slapi_ch_malloc( 4 + dnlen ); + } + strcpy( dnbuf, "dn:" ); + strcpy( dnbuf + 3, binddn ); + arctrl.ldctl_value.bv_val = dnbuf; + arctrl.ldctl_value.bv_len = 3 + dnlen; + } + + if ( slapi_pblock_set( pb, SLAPI_ADD_RESCONTROL, &arctrl ) != 0 ) { + slapi_log_error( SLAPI_LOG_FATAL, "bind", + "unable to add authentication response control" ); + } + + if ( NULL != dnbuf_dynamic ) { + slapi_ch_free( (void **)&dnbuf_dynamic ); + } +} |