int ldap_pvt_sasl_getmechs ( LDAP *ld, char **pmechlist ) { /* we need to query the server for supported mechs anyway */ LDAPMessage *res, *e; char *attrs[] = { "supportedSASLMechanisms", NULL }; char **values, *mechlist; int rc; Debug( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_getmech\n", 0, 0, 0 ); rc = ldap_search_s( ld, "", LDAP_SCOPE_BASE, NULL, attrs, 0, &res ); if ( rc != LDAP_SUCCESS ) { return ld->ld_errno; } e = ldap_first_entry( ld, res ); if ( e == NULL ) { ldap_msgfree( res ); if ( ld->ld_errno == LDAP_SUCCESS ) { ld->ld_errno = LDAP_NO_SUCH_OBJECT; } return ld->ld_errno; } values = ldap_get_values( ld, e, "supportedSASLMechanisms" ); if ( values == NULL ) { ldap_msgfree( res ); ld->ld_errno = LDAP_NO_SUCH_ATTRIBUTE; return ld->ld_errno; } mechlist = ldap_charray2str( values, " " ); if ( mechlist == NULL ) { LDAP_VFREE( values ); ldap_msgfree( res ); ld->ld_errno = LDAP_NO_MEMORY; return ld->ld_errno; } LDAP_VFREE( values ); ldap_msgfree( res ); *pmechlist = mechlist; return LDAP_SUCCESS; }
void ldap_mods_free( LDAPMod **mods, int freemods ) { int i; if ( mods == NULL ) return; for ( i = 0; mods[i] != NULL; i++ ) { if ( mods[i]->mod_op & LDAP_MOD_BVALUES ) { if( mods[i]->mod_bvalues != NULL ) ber_bvecfree( mods[i]->mod_bvalues ); } else if( mods[i]->mod_values != NULL ) { LDAP_VFREE( mods[i]->mod_values ); } if ( mods[i]->mod_type != NULL ) { LDAP_FREE( mods[i]->mod_type ); } LDAP_FREE( (char *) mods[i] ); } if ( freemods ) { LDAP_FREE( (char *) mods ); } }
int ldap_ld_free( LDAP *ld, int close, LDAPControl **sctrls, LDAPControl **cctrls ) { LDAPMessage *lm, *next; int err = LDAP_SUCCESS; LDAP_MUTEX_LOCK( &ld->ld_ldcmutex ); /* Someone else is still using this ld. */ if (ld->ld_ldcrefcnt > 1) { /* but not last thread */ /* clean up self only */ ld->ld_ldcrefcnt--; if ( ld->ld_error != NULL ) { LDAP_FREE( ld->ld_error ); ld->ld_error = NULL; } if ( ld->ld_matched != NULL ) { LDAP_FREE( ld->ld_matched ); ld->ld_matched = NULL; } if ( ld->ld_referrals != NULL) { LDAP_VFREE(ld->ld_referrals); ld->ld_referrals = NULL; } LDAP_MUTEX_UNLOCK( &ld->ld_ldcmutex ); LDAP_FREE( (char *) ld ); return( err ); } /* This ld is the last thread. */ /* free LDAP structure and outstanding requests/responses */ LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); while ( ld->ld_requests != NULL ) { ldap_free_request( ld, ld->ld_requests ); } LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); /* free and unbind from all open connections */ while ( ld->ld_conns != NULL ) { ldap_free_connection( ld, ld->ld_conns, 1, close ); } LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); LDAP_MUTEX_LOCK( &ld->ld_res_mutex ); for ( lm = ld->ld_responses; lm != NULL; lm = next ) { next = lm->lm_next; ldap_msgfree( lm ); } if ( ld->ld_abandoned != NULL ) { LDAP_FREE( ld->ld_abandoned ); ld->ld_abandoned = NULL; } LDAP_MUTEX_UNLOCK( &ld->ld_res_mutex ); LDAP_MUTEX_LOCK( &ld->ld_ldopts_mutex ); /* final close callbacks */ { ldaplist *ll, *next; for ( ll = ld->ld_options.ldo_conn_cbs; ll; ll = next ) { ldap_conncb *cb = ll->ll_data; next = ll->ll_next; cb->lc_del( ld, NULL, cb ); LDAP_FREE( ll ); } } if ( ld->ld_error != NULL ) { LDAP_FREE( ld->ld_error ); ld->ld_error = NULL; } if ( ld->ld_matched != NULL ) { LDAP_FREE( ld->ld_matched ); ld->ld_matched = NULL; } if ( ld->ld_referrals != NULL) { LDAP_VFREE(ld->ld_referrals); ld->ld_referrals = NULL; } if ( ld->ld_selectinfo != NULL ) { ldap_free_select_info( ld->ld_selectinfo ); ld->ld_selectinfo = NULL; } if ( ld->ld_options.ldo_defludp != NULL ) { ldap_free_urllist( ld->ld_options.ldo_defludp ); ld->ld_options.ldo_defludp = NULL; } #ifdef LDAP_CONNECTIONLESS if ( ld->ld_options.ldo_peer != NULL ) { LDAP_FREE( ld->ld_options.ldo_peer ); ld->ld_options.ldo_peer = NULL; } if ( ld->ld_options.ldo_cldapdn != NULL ) { LDAP_FREE( ld->ld_options.ldo_cldapdn ); ld->ld_options.ldo_cldapdn = NULL; } #endif #ifdef HAVE_CYRUS_SASL if ( ld->ld_options.ldo_def_sasl_mech != NULL ) { LDAP_FREE( ld->ld_options.ldo_def_sasl_mech ); ld->ld_options.ldo_def_sasl_mech = NULL; } if ( ld->ld_options.ldo_def_sasl_realm != NULL ) { LDAP_FREE( ld->ld_options.ldo_def_sasl_realm ); ld->ld_options.ldo_def_sasl_realm = NULL; } if ( ld->ld_options.ldo_def_sasl_authcid != NULL ) { LDAP_FREE( ld->ld_options.ldo_def_sasl_authcid ); ld->ld_options.ldo_def_sasl_authcid = NULL; } if ( ld->ld_options.ldo_def_sasl_authzid != NULL ) { LDAP_FREE( ld->ld_options.ldo_def_sasl_authzid ); ld->ld_options.ldo_def_sasl_authzid = NULL; } #endif #ifdef HAVE_TLS ldap_int_tls_destroy( &ld->ld_options ); #endif if ( ld->ld_options.ldo_sctrls != NULL ) { ldap_controls_free( ld->ld_options.ldo_sctrls ); ld->ld_options.ldo_sctrls = NULL; } if ( ld->ld_options.ldo_cctrls != NULL ) { ldap_controls_free( ld->ld_options.ldo_cctrls ); ld->ld_options.ldo_cctrls = NULL; } LDAP_MUTEX_UNLOCK( &ld->ld_ldopts_mutex ); ber_sockbuf_free( ld->ld_sb ); #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_destroy( &ld->ld_msgid_mutex ); ldap_pvt_thread_mutex_destroy( &ld->ld_conn_mutex ); ldap_pvt_thread_mutex_destroy( &ld->ld_req_mutex ); ldap_pvt_thread_mutex_destroy( &ld->ld_res_mutex ); ldap_pvt_thread_mutex_destroy( &ld->ld_abandon_mutex ); ldap_pvt_thread_mutex_destroy( &ld->ld_ldopts_mutex ); ldap_pvt_thread_mutex_unlock( &ld->ld_ldcmutex ); ldap_pvt_thread_mutex_destroy( &ld->ld_ldcmutex ); #endif #ifndef NDEBUG LDAP_TRASH(ld); #endif LDAP_FREE( (char *) ld->ldc ); LDAP_FREE( (char *) ld ); return( err ); }
/* protected by ld_conn_mutex */ void ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind ) { LDAPConn *tmplc, *prevlc; LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex ); Debug( LDAP_DEBUG_TRACE, "ldap_free_connection %d %d\n", force, unbind, 0 ); if ( force || --lc->lconn_refcnt <= 0 ) { /* remove from connections list first */ for ( prevlc = NULL, tmplc = ld->ld_conns; tmplc != NULL; tmplc = tmplc->lconn_next ) { if ( tmplc == lc ) { if ( prevlc == NULL ) { ld->ld_conns = tmplc->lconn_next; } else { prevlc->lconn_next = tmplc->lconn_next; } if ( ld->ld_defconn == lc ) { ld->ld_defconn = NULL; } break; } prevlc = tmplc; } /* process connection callbacks */ { struct ldapoptions *lo; ldaplist *ll; ldap_conncb *cb; lo = &ld->ld_options; LDAP_MUTEX_LOCK( &lo->ldo_mutex ); if ( lo->ldo_conn_cbs ) { for ( ll=lo->ldo_conn_cbs; ll; ll=ll->ll_next ) { cb = ll->ll_data; cb->lc_del( ld, lc->lconn_sb, cb ); } } LDAP_MUTEX_UNLOCK( &lo->ldo_mutex ); lo = LDAP_INT_GLOBAL_OPT(); LDAP_MUTEX_LOCK( &lo->ldo_mutex ); if ( lo->ldo_conn_cbs ) { for ( ll=lo->ldo_conn_cbs; ll; ll=ll->ll_next ) { cb = ll->ll_data; cb->lc_del( ld, lc->lconn_sb, cb ); } } LDAP_MUTEX_UNLOCK( &lo->ldo_mutex ); } if ( lc->lconn_status == LDAP_CONNST_CONNECTED ) { ldap_mark_select_clear( ld, lc->lconn_sb ); if ( unbind ) { ldap_send_unbind( ld, lc->lconn_sb, NULL, NULL ); } } if ( lc->lconn_ber != NULL ) { ber_free( lc->lconn_ber, 1 ); } ldap_int_sasl_close( ld, lc ); #ifdef HAVE_GSSAPI ldap_int_gssapi_close( ld, lc ); #endif ldap_free_urllist( lc->lconn_server ); /* FIXME: is this at all possible? * ldap_ld_free() in unbind.c calls ldap_free_connection() * with force == 1 __after__ explicitly calling * ldap_free_request() on all requests */ if ( force ) { LDAPRequest *lr; for ( lr = ld->ld_requests; lr; ) { LDAPRequest *lr_next = lr->lr_next; if ( lr->lr_conn == lc ) { ldap_free_request_int( ld, lr ); } lr = lr_next; } } if ( lc->lconn_sb != ld->ld_sb ) { ber_sockbuf_free( lc->lconn_sb ); } else { ber_int_sb_close( lc->lconn_sb ); } if ( lc->lconn_rebind_queue != NULL) { int i; for( i = 0; lc->lconn_rebind_queue[i] != NULL; i++ ) { LDAP_VFREE( lc->lconn_rebind_queue[i] ); } LDAP_FREE( lc->lconn_rebind_queue ); } LDAP_FREE( lc ); Debug( LDAP_DEBUG_TRACE, "ldap_free_connection: actually freed\n", 0, 0, 0 ); } else { lc->lconn_lastused = time( NULL ); Debug( LDAP_DEBUG_TRACE, "ldap_free_connection: refcnt %d\n", lc->lconn_refcnt, 0, 0 ); } }
/* * Chase v3 referrals * * Parameters: * (IN) ld = LDAP connection handle * (IN) lr = LDAP Request structure * (IN) refs = array of pointers to referral strings that we will chase * The array will be free'd by this function when no longer needed * (IN) sref != 0 if following search reference * (OUT) errstrp = Place to return a string of referrals which could not be followed * (OUT) hadrefp = 1 if sucessfully followed referral * * Return value - number of referrals followed * * Protected by res_mutex, conn_mutex and req_mutex (try_read1msg) */ int ldap_chase_v3referrals( LDAP *ld, LDAPRequest *lr, char **refs, int sref, char **errstrp, int *hadrefp ) { char *unfollowed; int unfollowedcnt = 0; LDAPRequest *origreq; LDAPURLDesc *srv = NULL; BerElement *ber; char **refarray = NULL; LDAPConn *lc; int rc, count, i, j, id; LDAPreqinfo rinfo; LDAP_NEXTREF_PROC *nextref_proc = ld->ld_nextref_proc ? ld->ld_nextref_proc : ldap_int_nextref; LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex ); LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex ); Debug( LDAP_DEBUG_TRACE, "ldap_chase_v3referrals\n", 0, 0, 0 ); ld->ld_errno = LDAP_SUCCESS; /* optimistic */ *hadrefp = 0; unfollowed = NULL; rc = count = 0; /* If no referrals in array, return */ if ( (refs == NULL) || ( (refs)[0] == NULL) ) { rc = 0; goto done; } /* Check for hop limit exceeded */ if ( lr->lr_parentcnt >= ld->ld_refhoplimit ) { Debug( LDAP_DEBUG_ANY, "more than %d referral hops (dropping)\n", ld->ld_refhoplimit, 0, 0 ); ld->ld_errno = LDAP_REFERRAL_LIMIT_EXCEEDED; rc = -1; goto done; } /* find original request */ for ( origreq = lr; origreq->lr_parent != NULL; origreq = origreq->lr_parent ) { /* empty */ ; } refarray = refs; refs = NULL; /* parse out & follow referrals */ /* NOTE: if nextref_proc == ldap_int_nextref, params is ignored */ i = -1; for ( nextref_proc( ld, &refarray, &i, ld->ld_nextref_params ); i != -1; nextref_proc( ld, &refarray, &i, ld->ld_nextref_params ) ) { /* Parse the referral URL */ rc = ldap_url_parse_ext( refarray[i], &srv, LDAP_PVT_URL_PARSE_NOEMPTY_DN ); if ( rc != LDAP_URL_SUCCESS ) { /* ldap_url_parse_ext() returns LDAP_URL_* errors * which do not map on API errors */ ld->ld_errno = LDAP_PARAM_ERROR; rc = -1; goto done; } if( srv->lud_crit_exts ) { int ok = 0; #ifdef HAVE_TLS /* If StartTLS is the only critical ext, OK. */ if ( find_tls_ext( srv ) == 2 && srv->lud_crit_exts == 1 ) ok = 1; #endif if ( !ok ) { /* we do not support any other extensions */ ld->ld_errno = LDAP_NOT_SUPPORTED; rc = -1; goto done; } } /* check connection for re-bind in progress */ if (( lc = find_connection( ld, srv, 1 )) != NULL ) { /* See if we've already requested this DN with this conn */ LDAPRequest *lp; int looped = 0; ber_len_t len = srv->lud_dn ? strlen( srv->lud_dn ) : 0; for ( lp = origreq; lp; ) { if ( lp->lr_conn == lc && len == lp->lr_dn.bv_len && len && strncmp( srv->lud_dn, lp->lr_dn.bv_val, len ) == 0 ) { looped = 1; break; } if ( lp == origreq ) { lp = lp->lr_child; } else { lp = lp->lr_refnext; } } if ( looped ) { ldap_free_urllist( srv ); srv = NULL; ld->ld_errno = LDAP_CLIENT_LOOP; rc = -1; continue; } if ( lc->lconn_rebind_inprogress ) { /* We are already chasing a referral or search reference and a * bind on that connection is in progress. We must queue * referrals on that connection, so we don't get a request * going out before the bind operation completes. This happens * if two search references come in one behind the other * for the same server with different contexts. */ Debug( LDAP_DEBUG_TRACE, "ldap_chase_v3referrals: queue referral \"%s\"\n", refarray[i], 0, 0); if( lc->lconn_rebind_queue == NULL ) { /* Create a referral list */ lc->lconn_rebind_queue = (char ***) LDAP_MALLOC( sizeof(void *) * 2); if( lc->lconn_rebind_queue == NULL) { ld->ld_errno = LDAP_NO_MEMORY; rc = -1; goto done; } lc->lconn_rebind_queue[0] = refarray; lc->lconn_rebind_queue[1] = NULL; refarray = NULL; } else { /* Count how many referral arrays we already have */ for( j = 0; lc->lconn_rebind_queue[j] != NULL; j++) { /* empty */; } /* Add the new referral to the list */ lc->lconn_rebind_queue = (char ***) LDAP_REALLOC( lc->lconn_rebind_queue, sizeof(void *) * (j + 2)); if( lc->lconn_rebind_queue == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; rc = -1; goto done; } lc->lconn_rebind_queue[j] = refarray; lc->lconn_rebind_queue[j+1] = NULL; refarray = NULL; } /* We have queued the referral/reference, now just return */ rc = 0; *hadrefp = 1; count = 1; /* Pretend we already followed referral */ goto done; } } /* Re-encode the request with the new starting point of the search. * Note: In the future we also need to replace the filter if one * was provided with the search reference */ /* For references we don't want old dn if new dn empty */ if ( sref && srv->lud_dn == NULL ) { srv->lud_dn = LDAP_STRDUP( "" ); } LDAP_NEXT_MSGID( ld, id ); ber = re_encode_request( ld, origreq->lr_ber, id, sref, srv, &rinfo.ri_request ); if( ber == NULL ) { ld->ld_errno = LDAP_ENCODING_ERROR; rc = -1; goto done; } Debug( LDAP_DEBUG_TRACE, "ldap_chase_v3referral: msgid %d, url \"%s\"\n", lr->lr_msgid, refarray[i], 0); /* Send the new request to the server - may require a bind */ rinfo.ri_msgid = origreq->lr_origid; rinfo.ri_url = refarray[i]; rc = ldap_send_server_request( ld, ber, id, origreq, &srv, NULL, &rinfo, 0, 1 ); if ( rc < 0 ) { /* Failure, try next referral in the list */ Debug( LDAP_DEBUG_ANY, "Unable to chase referral \"%s\" (%d: %s)\n", refarray[i], ld->ld_errno, ldap_err2string( ld->ld_errno ) ); unfollowedcnt += ldap_append_referral( ld, &unfollowed, refarray[i] ); ldap_free_urllist( srv ); srv = NULL; ld->ld_errno = LDAP_REFERRAL; } else { /* Success, no need to try this referral list further */ rc = 0; ++count; *hadrefp = 1; /* check if there is a queue of referrals that came in during bind */ if ( lc == NULL) { lc = find_connection( ld, srv, 1 ); if ( lc == NULL ) { ld->ld_errno = LDAP_OPERATIONS_ERROR; rc = -1; LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); goto done; } } if ( lc->lconn_rebind_queue != NULL ) { /* Release resources of previous list */ LDAP_VFREE( refarray ); refarray = NULL; ldap_free_urllist( srv ); srv = NULL; /* Pull entries off end of queue so list always null terminated */ for( j = 0; lc->lconn_rebind_queue[j] != NULL; j++ ) ; refarray = lc->lconn_rebind_queue[j - 1]; lc->lconn_rebind_queue[j-1] = NULL; /* we pulled off last entry from queue, free queue */ if ( j == 1 ) { LDAP_FREE( lc->lconn_rebind_queue ); lc->lconn_rebind_queue = NULL; } /* restart the loop the with new referral list */ i = -1; continue; } break; /* referral followed, break out of for loop */ } } /* end for loop */ done: LDAP_VFREE( refarray ); ldap_free_urllist( srv ); LDAP_FREE( *errstrp ); if( rc == 0 ) { *errstrp = NULL; LDAP_FREE( unfollowed ); return count; } else { *errstrp = unfollowed; return rc; } }
int ldap_sort_entries( LDAP *ld, LDAPMessage **chain, LDAP_CONST char *attr, /* NULL => sort by DN */ int (*cmp) (LDAP_CONST char *, LDAP_CONST char *) ) { int i, count = 0; struct entrything *et; LDAPMessage *e, *ehead = NULL, *etail = NULL; LDAPMessage *ohead = NULL, *otail = NULL; LDAPMessage **ep; assert( ld != NULL ); /* Separate entries from non-entries */ for ( e = *chain; e; e=e->lm_chain ) { if ( e->lm_msgtype == LDAP_RES_SEARCH_ENTRY ) { count++; if ( !ehead ) ehead = e; if ( etail ) etail->lm_chain = e; etail = e; } else { if ( !ohead ) ohead = e; if ( otail ) otail->lm_chain = e; otail = e; } } if ( count < 2 ) { /* zero or one entries -- already sorted! */ if ( ehead ) { etail->lm_chain = ohead; *chain = ehead; } else { *chain = ohead; } return 0; } if ( (et = (struct entrything *) LDAP_MALLOC( count * sizeof(struct entrything) )) == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return( -1 ); } e = ehead; for ( i = 0; i < count; i++ ) { et[i].et_cmp_fn = cmp; et[i].et_msg = e; if ( attr == NULL ) { char *dn; dn = ldap_get_dn( ld, e ); et[i].et_vals = ldap_explode_dn( dn, 1 ); LDAP_FREE( dn ); } else { et[i].et_vals = ldap_get_values( ld, e, attr ); } e = e->lm_chain; } qsort( et, count, sizeof(struct entrything), et_cmp ); ep = chain; for ( i = 0; i < count; i++ ) { *ep = et[i].et_msg; ep = &(*ep)->lm_chain; LDAP_VFREE( et[i].et_vals ); } *ep = ohead; (*chain)->lm_chain_tail = otail ? otail : etail; LDAP_FREE( (char *) et ); return( 0 ); }
int ldap_set_option( LDAP *ld, int option, LDAP_CONST void *invalue) { struct ldapoptions *lo; int *dbglvl = NULL; int rc = LDAP_OPT_ERROR; /* Get pointer to global option structure */ lo = LDAP_INT_GLOBAL_OPT(); if (lo == NULL) { return LDAP_NO_MEMORY; } /* * The architecture to turn on debugging has a chicken and egg * problem. Thus, we introduce a fix here. */ if (option == LDAP_OPT_DEBUG_LEVEL) { dbglvl = (int *) invalue; } if( lo->ldo_valid != LDAP_INITIALIZED ) { ldap_int_initialize(lo, dbglvl); if ( lo->ldo_valid != LDAP_INITIALIZED ) return LDAP_LOCAL_ERROR; } if(ld != NULL) { assert( LDAP_VALID( ld ) ); if( !LDAP_VALID( ld ) ) { return LDAP_OPT_ERROR; } lo = &ld->ld_options; } LDAP_MUTEX_LOCK( &lo->ldo_mutex ); switch ( option ) { /* options with boolean values */ case LDAP_OPT_REFERRALS: if(invalue == LDAP_OPT_OFF) { LDAP_BOOL_CLR(lo, LDAP_BOOL_REFERRALS); } else { LDAP_BOOL_SET(lo, LDAP_BOOL_REFERRALS); } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_RESTART: if(invalue == LDAP_OPT_OFF) { LDAP_BOOL_CLR(lo, LDAP_BOOL_RESTART); } else { LDAP_BOOL_SET(lo, LDAP_BOOL_RESTART); } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_CONNECT_ASYNC: if(invalue == LDAP_OPT_OFF) { LDAP_BOOL_CLR(lo, LDAP_BOOL_CONNECT_ASYNC); } else { LDAP_BOOL_SET(lo, LDAP_BOOL_CONNECT_ASYNC); } rc = LDAP_OPT_SUCCESS; break; /* options which can withstand invalue == NULL */ case LDAP_OPT_SERVER_CONTROLS: { LDAPControl *const *controls = (LDAPControl *const *) invalue; if( lo->ldo_sctrls ) ldap_controls_free( lo->ldo_sctrls ); if( controls == NULL || *controls == NULL ) { lo->ldo_sctrls = NULL; rc = LDAP_OPT_SUCCESS; break; } lo->ldo_sctrls = ldap_controls_dup( controls ); if(lo->ldo_sctrls == NULL) { /* memory allocation error ? */ break; /* LDAP_OPT_ERROR */ } } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_CLIENT_CONTROLS: { LDAPControl *const *controls = (LDAPControl *const *) invalue; if( lo->ldo_cctrls ) ldap_controls_free( lo->ldo_cctrls ); if( controls == NULL || *controls == NULL ) { lo->ldo_cctrls = NULL; rc = LDAP_OPT_SUCCESS; break; } lo->ldo_cctrls = ldap_controls_dup( controls ); if(lo->ldo_cctrls == NULL) { /* memory allocation error ? */ break; /* LDAP_OPT_ERROR */ } } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_HOST_NAME: { const char *host = (const char *) invalue; LDAPURLDesc *ludlist = NULL; rc = LDAP_OPT_SUCCESS; if(host != NULL) { rc = ldap_url_parsehosts( &ludlist, host, lo->ldo_defport ? lo->ldo_defport : LDAP_PORT ); } else if(ld == NULL) { /* * must want global default returned * to initial condition. */ rc = ldap_url_parselist_ext(&ludlist, "ldap://localhost/", NULL, LDAP_PVT_URL_PARSE_NOEMPTY_HOST | LDAP_PVT_URL_PARSE_DEF_PORT ); } else { /* * must want the session default * updated to the current global default */ ludlist = ldap_url_duplist( ldap_int_global_options.ldo_defludp); if (ludlist == NULL) rc = LDAP_NO_MEMORY; } if (rc == LDAP_OPT_SUCCESS) { if (lo->ldo_defludp != NULL) ldap_free_urllist(lo->ldo_defludp); lo->ldo_defludp = ludlist; } break; } case LDAP_OPT_URI: { const char *urls = (const char *) invalue; LDAPURLDesc *ludlist = NULL; rc = LDAP_OPT_SUCCESS; if(urls != NULL) { rc = ldap_url_parselist_ext(&ludlist, urls, NULL, LDAP_PVT_URL_PARSE_NOEMPTY_HOST | LDAP_PVT_URL_PARSE_DEF_PORT ); } else if(ld == NULL) { /* * must want global default returned * to initial condition. */ rc = ldap_url_parselist_ext(&ludlist, "ldap://localhost/", NULL, LDAP_PVT_URL_PARSE_NOEMPTY_HOST | LDAP_PVT_URL_PARSE_DEF_PORT ); } else { /* * must want the session default * updated to the current global default */ ludlist = ldap_url_duplist( ldap_int_global_options.ldo_defludp); if (ludlist == NULL) rc = LDAP_URL_ERR_MEM; } switch (rc) { case LDAP_URL_SUCCESS: /* Success */ rc = LDAP_SUCCESS; break; case LDAP_URL_ERR_MEM: /* can't allocate memory space */ rc = LDAP_NO_MEMORY; break; case LDAP_URL_ERR_PARAM: /* parameter is bad */ case LDAP_URL_ERR_BADSCHEME: /* URL doesn't begin with "ldap[si]://" */ case LDAP_URL_ERR_BADENCLOSURE: /* URL is missing trailing ">" */ case LDAP_URL_ERR_BADURL: /* URL is bad */ case LDAP_URL_ERR_BADHOST: /* host port is bad */ case LDAP_URL_ERR_BADATTRS: /* bad (or missing) attributes */ case LDAP_URL_ERR_BADSCOPE: /* scope string is invalid (or missing) */ case LDAP_URL_ERR_BADFILTER: /* bad or missing filter */ case LDAP_URL_ERR_BADEXTS: /* bad or missing extensions */ rc = LDAP_PARAM_ERROR; break; } if (rc == LDAP_SUCCESS) { if (lo->ldo_defludp != NULL) ldap_free_urllist(lo->ldo_defludp); lo->ldo_defludp = ludlist; } break; } case LDAP_OPT_DEFBASE: { const char *newbase = (const char *) invalue; char *defbase = NULL; if ( newbase != NULL ) { defbase = LDAP_STRDUP( newbase ); if ( defbase == NULL ) { rc = LDAP_NO_MEMORY; break; } } else if ( ld != NULL ) { defbase = LDAP_STRDUP( ldap_int_global_options.ldo_defbase ); if ( defbase == NULL ) { rc = LDAP_NO_MEMORY; break; } } if ( lo->ldo_defbase != NULL ) LDAP_FREE( lo->ldo_defbase ); lo->ldo_defbase = defbase; } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_DIAGNOSTIC_MESSAGE: { const char *err = (const char *) invalue; if(ld == NULL) { /* need a struct ldap */ break; /* LDAP_OPT_ERROR */ } if( ld->ld_error ) { LDAP_FREE(ld->ld_error); ld->ld_error = NULL; } if ( err ) { ld->ld_error = LDAP_STRDUP(err); } } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_MATCHED_DN: { const char *matched = (const char *) invalue; if (ld == NULL) { /* need a struct ldap */ break; /* LDAP_OPT_ERROR */ } if( ld->ld_matched ) { LDAP_FREE(ld->ld_matched); ld->ld_matched = NULL; } if ( matched ) { ld->ld_matched = LDAP_STRDUP( matched ); } } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_REFERRAL_URLS: { char *const *referrals = (char *const *) invalue; if(ld == NULL) { /* need a struct ldap */ break; /* LDAP_OPT_ERROR */ } if( ld->ld_referrals ) { LDAP_VFREE(ld->ld_referrals); } if ( referrals ) { ld->ld_referrals = ldap_value_dup(referrals); } } rc = LDAP_OPT_SUCCESS; break; /* Only accessed from inside this function by ldap_set_rebind_proc() */ case LDAP_OPT_REBIND_PROC: { lo->ldo_rebind_proc = (LDAP_REBIND_PROC *)invalue; } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_REBIND_PARAMS: { lo->ldo_rebind_params = (void *)invalue; } rc = LDAP_OPT_SUCCESS; break; /* Only accessed from inside this function by ldap_set_nextref_proc() */ case LDAP_OPT_NEXTREF_PROC: { lo->ldo_nextref_proc = (LDAP_NEXTREF_PROC *)invalue; } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_NEXTREF_PARAMS: { lo->ldo_nextref_params = (void *)invalue; } rc = LDAP_OPT_SUCCESS; break; /* Only accessed from inside this function by ldap_set_urllist_proc() */ case LDAP_OPT_URLLIST_PROC: { lo->ldo_urllist_proc = (LDAP_URLLIST_PROC *)invalue; } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_URLLIST_PARAMS: { lo->ldo_urllist_params = (void *)invalue; } rc = LDAP_OPT_SUCCESS; break; /* read-only options */ case LDAP_OPT_API_INFO: case LDAP_OPT_DESC: case LDAP_OPT_SOCKBUF: case LDAP_OPT_API_FEATURE_INFO: break; /* LDAP_OPT_ERROR */ /* options which cannot withstand invalue == NULL */ case LDAP_OPT_DEREF: case LDAP_OPT_SIZELIMIT: case LDAP_OPT_TIMELIMIT: case LDAP_OPT_PROTOCOL_VERSION: case LDAP_OPT_RESULT_CODE: case LDAP_OPT_DEBUG_LEVEL: case LDAP_OPT_TIMEOUT: case LDAP_OPT_NETWORK_TIMEOUT: case LDAP_OPT_CONNECT_CB: case LDAP_OPT_X_KEEPALIVE_IDLE: case LDAP_OPT_X_KEEPALIVE_PROBES : case LDAP_OPT_X_KEEPALIVE_INTERVAL : if(invalue == NULL) { /* no place to set from */ LDAP_MUTEX_UNLOCK( &lo->ldo_mutex ); return ( LDAP_OPT_ERROR ); } break; default: #ifdef HAVE_TLS if ( ldap_pvt_tls_set_option( ld, option, (void *)invalue ) == 0 ) { LDAP_MUTEX_UNLOCK( &lo->ldo_mutex ); return ( LDAP_OPT_SUCCESS ); } #endif #ifdef HAVE_CYRUS_SASL if ( ldap_int_sasl_set_option( ld, option, (void *)invalue ) == 0 ) { LDAP_MUTEX_UNLOCK( &lo->ldo_mutex ); return ( LDAP_OPT_SUCCESS ); } #endif #ifdef HAVE_GSSAPI if ( ldap_int_gssapi_set_option( ld, option, (void *)invalue ) == 0 ) { LDAP_MUTEX_UNLOCK( &lo->ldo_mutex ); return ( LDAP_OPT_SUCCESS ); } #endif /* bad param */ break; /* LDAP_OPT_ERROR */ } /* options which cannot withstand invalue == NULL */ switch(option) { case LDAP_OPT_DEREF: /* FIXME: check value for protocol compliance? */ lo->ldo_deref = * (const int *) invalue; rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_SIZELIMIT: /* FIXME: check value for protocol compliance? */ lo->ldo_sizelimit = * (const int *) invalue; rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_TIMELIMIT: /* FIXME: check value for protocol compliance? */ lo->ldo_timelimit = * (const int *) invalue; rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_TIMEOUT: { const struct timeval *tv = (const struct timeval *) invalue; lo->ldo_tm_api = *tv; } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_NETWORK_TIMEOUT: { const struct timeval *tv = (const struct timeval *) invalue; lo->ldo_tm_net = *tv; } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_PROTOCOL_VERSION: { int vers = * (const int *) invalue; if (vers < LDAP_VERSION_MIN || vers > LDAP_VERSION_MAX) { /* not supported */ break; } lo->ldo_version = vers; } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_RESULT_CODE: { int err = * (const int *) invalue; if(ld == NULL) { /* need a struct ldap */ break; } ld->ld_errno = err; } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_DEBUG_LEVEL: lo->ldo_debug = * (const int *) invalue; rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_CONNECT_CB: { /* setting pushes the callback */ ldaplist *ll; ll = LDAP_MALLOC( sizeof( *ll )); ll->ll_data = (void *)invalue; ll->ll_next = lo->ldo_conn_cbs; lo->ldo_conn_cbs = ll; } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_X_KEEPALIVE_IDLE: lo->ldo_keepalive_idle = * (const int *) invalue; rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_X_KEEPALIVE_PROBES : lo->ldo_keepalive_probes = * (const int *) invalue; rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_X_KEEPALIVE_INTERVAL : lo->ldo_keepalive_interval = * (const int *) invalue; rc = LDAP_OPT_SUCCESS; break; } LDAP_MUTEX_UNLOCK( &lo->ldo_mutex ); return ( rc ); }
void ldap_value_free( char **vals ) { LDAP_VFREE( vals ); }
void ldap_memvfree( void **v ) { LDAP_VFREE( v ); }
int main( int argc, char *argv[] ) { int rc, i, debug = 0, f2 = 0; unsigned flags[ 2 ] = { 0U, 0 }; char *strin, *str = NULL, buf[ 1024 ]; LDAPDN dn, dn2 = NULL; while ( 1 ) { int opt = getopt( argc, argv, "d:" ); if ( opt == EOF ) { break; } switch ( opt ) { case 'd': debug = atoi( optarg ); break; } } optind--; argc -= optind; argv += optind; if ( argc < 2 ) { fprintf( stderr, "usage: dntest <dn> [flags-in[,...]] [flags-out[,...]]\n\n" ); fprintf( stderr, "\tflags-in: V3,V2,DCE,<flags>\n" ); fprintf( stderr, "\tflags-out: V3,V2,UFN,DCE,AD,<flags>\n\n" ); fprintf( stderr, "\t<flags>: PRETTY,PEDANTIC,NOSPACES,NOONESPACE\n\n" ); return( 0 ); } if ( ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &debug ) != LBER_OPT_SUCCESS ) { fprintf( stderr, "Could not set LBER_OPT_DEBUG_LEVEL %d\n", debug ); } if ( ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &debug ) != LDAP_OPT_SUCCESS ) { fprintf( stderr, "Could not set LDAP_OPT_DEBUG_LEVEL %d\n", debug ); } if ( strcmp( argv[ 1 ], "-" ) == 0 ) { size_t len = fgets( buf, sizeof( buf ), stdin ) ? strlen( buf ) : 0; if ( len == 0 || buf[ --len ] == '\n' ) { buf[ len ] = '\0'; } strin = buf; } else { strin = argv[ 1 ]; } if ( argc >= 3 ) { for ( i = 0; i < argc - 2; i++ ) { char *s, *e; for ( s = argv[ 2 + i ]; s; s = e ) { e = strchr( s, ',' ); if ( e != NULL ) { e[ 0 ] = '\0'; e++; } if ( !strcasecmp( s, "V3" ) ) { flags[ i ] |= LDAP_DN_FORMAT_LDAPV3; } else if ( !strcasecmp( s, "V2" ) ) { flags[ i ] |= LDAP_DN_FORMAT_LDAPV2; } else if ( !strcasecmp( s, "DCE" ) ) { flags[ i ] |= LDAP_DN_FORMAT_DCE; } else if ( !strcasecmp( s, "UFN" ) ) { flags[ i ] |= LDAP_DN_FORMAT_UFN; } else if ( !strcasecmp( s, "AD" ) ) { flags[ i ] |= LDAP_DN_FORMAT_AD_CANONICAL; } else if ( !strcasecmp( s, "PRETTY" ) ) { flags[ i ] |= LDAP_DN_PRETTY; } else if ( !strcasecmp( s, "PEDANTIC" ) ) { flags[ i ] |= LDAP_DN_PEDANTIC; } else if ( !strcasecmp( s, "NOSPACES" ) ) { flags[ i ] |= LDAP_DN_P_NOLEADTRAILSPACES; } else if ( !strcasecmp( s, "NOONESPACE" ) ) { flags[ i ] |= LDAP_DN_P_NOSPACEAFTERRDN; } } } } if ( flags[ 1 ] == 0 ) flags[ 1 ] = LDAP_DN_FORMAT_LDAPV3; f2 = 1; rc = ldap_str2dn( strin, &dn, flags[ 0 ] ); if ( rc == LDAP_SUCCESS ) { int i; if ( dn ) { for ( i = 0; dn[ i ]; i++ ) { LDAPRDN rdn = dn[ i ]; char *rstr = NULL; if ( ldap_rdn2str( rdn, &rstr, flags[ f2 ] ) ) { fprintf( stdout, "\tldap_rdn2str() failed\n" ); continue; } fprintf( stdout, "\tldap_rdn2str() = \"%s\"\n", rstr ); ldap_memfree( rstr ); } } else { fprintf( stdout, "\tempty DN\n" ); } } str = NULL; if ( rc == LDAP_SUCCESS && ldap_dn2str( dn, &str, flags[ f2 ] ) == LDAP_SUCCESS ) { char **values, *tmp, *tmp2, *str2 = NULL; int n; fprintf( stdout, "\nldap_dn2str(ldap_str2dn(\"%s\"))\n" "\t= \"%s\"\n", strin, str ); switch ( flags[ f2 ] & LDAP_DN_FORMAT_MASK ) { case LDAP_DN_FORMAT_UFN: case LDAP_DN_FORMAT_AD_CANONICAL: return( 0 ); case LDAP_DN_FORMAT_LDAPV3: case LDAP_DN_FORMAT_LDAPV2: n = ldap_dn2domain( strin, &tmp ); if ( n ) { fprintf( stdout, "\nldap_dn2domain(\"%s\") FAILED\n", strin ); } else { fprintf( stdout, "\nldap_dn2domain(\"%s\")\n" "\t= \"%s\"\n", strin, tmp ? tmp : "" ); } ldap_memfree( tmp ); tmp = ldap_dn2ufn( strin ); fprintf( stdout, "\nldap_dn2ufn(\"%s\")\n" "\t= \"%s\"\n", strin, tmp ? tmp : "" ); ldap_memfree( tmp ); tmp = ldap_dn2dcedn( strin ); fprintf( stdout, "\nldap_dn2dcedn(\"%s\")\n" "\t= \"%s\"\n", strin, tmp ? tmp : "" ); tmp2 = ldap_dcedn2dn( tmp ); fprintf( stdout, "\nldap_dcedn2dn(\"%s\")\n" "\t= \"%s\"\n", tmp ? tmp : "", tmp2 ? tmp2 : "" ); ldap_memfree( tmp ); ldap_memfree( tmp2 ); tmp = ldap_dn2ad_canonical( strin ); fprintf( stdout, "\nldap_dn2ad_canonical(\"%s\")\n" "\t= \"%s\"\n", strin, tmp ? tmp : "" ); ldap_memfree( tmp ); fprintf( stdout, "\nldap_explode_dn(\"%s\"):\n", str ); values = ldap_explode_dn( str, 0 ); for ( n = 0; values && values[ n ]; n++ ) { char **vv; int nn; fprintf( stdout, "\t\"%s\"\n", values[ n ] ); fprintf( stdout, "\tldap_explode_rdn(\"%s\")\n", values[ n ] ); vv = ldap_explode_rdn( values[ n ], 0 ); for ( nn = 0; vv && vv[ nn ]; nn++ ) { fprintf( stdout, "\t\t'%s'\n", vv[ nn ] ); } LDAP_VFREE( vv ); fprintf( stdout, "\tldap_explode_rdn(\"%s\")" " (no types)\n", values[ n ] ); vv = ldap_explode_rdn( values[ n ], 1 ); for ( nn = 0; vv && vv[ nn ]; nn++ ) { fprintf( stdout, "\t\t\t\"%s\"\n", vv[ nn ] ); } LDAP_VFREE( vv ); } LDAP_VFREE( values ); fprintf( stdout, "\nldap_explode_dn(\"%s\")" " (no types):\n", str ); values = ldap_explode_dn( str, 1 ); for ( n = 0; values && values[ n ]; n++ ) { fprintf( stdout, "\t\"%s\"\n", values[ n ] ); } LDAP_VFREE( values ); break; } dn2 = NULL; rc = ldap_str2dn( str, &dn2, flags[ f2 ] ); str2 = NULL; if ( rc == LDAP_SUCCESS && ldap_dn2str( dn2, &str2, flags[ f2 ] ) == LDAP_SUCCESS ) { int iRDN; fprintf( stdout, "\n\"%s\"\n\t == \"%s\" ? %s\n", str, str2, strcmp( str, str2 ) == 0 ? "yes" : "no" ); if( dn != NULL && dn2 == NULL ) { fprintf( stdout, "dn mismatch\n" ); } else if (( dn != NULL ) && (dn2 != NULL)) for ( iRDN = 0; dn[ iRDN ] && dn2[ iRDN ]; iRDN++ ) { LDAPRDN r = dn[ iRDN ]; LDAPRDN r2 = dn2[ iRDN ]; int iAVA; for ( iAVA = 0; r[ iAVA ] && r2[ iAVA ]; iAVA++ ) { LDAPAVA *a = r[ iAVA ]; LDAPAVA *a2 = r2[ iAVA ]; if ( a->la_attr.bv_len != a2->la_attr.bv_len ) { fprintf( stdout, "ava(%d), rdn(%d) attr len mismatch (%ld->%ld)\n", iAVA + 1, iRDN + 1, a->la_attr.bv_len, a2->la_attr.bv_len ); } else if ( memcmp( a->la_attr.bv_val, a2->la_attr.bv_val, a->la_attr.bv_len ) ) { fprintf( stdout, "ava(%d), rdn(%d) attr mismatch\n", iAVA + 1, iRDN + 1 ); } else if ( a->la_flags != a2->la_flags ) { fprintf( stdout, "ava(%d), rdn(%d) flag mismatch (%x->%x)\n", iAVA + 1, iRDN + 1, a->la_flags, a2->la_flags ); } else if ( a->la_value.bv_len != a2->la_value.bv_len ) { fprintf( stdout, "ava(%d), rdn(%d) value len mismatch (%ld->%ld)\n", iAVA + 1, iRDN + 1, a->la_value.bv_len, a2->la_value.bv_len ); } else if ( memcmp( a->la_value.bv_val, a2->la_value.bv_val, a->la_value.bv_len ) ) { fprintf( stdout, "ava(%d), rdn(%d) value mismatch\n", iAVA + 1, iRDN + 1 ); } } } ldap_dnfree( dn2 ); ldap_memfree( str2 ); } ldap_memfree( str ); } ldap_dnfree( dn ); /* note: dn is not freed */ return( 0 ); }
/* * Parse LDAPResult Messages: * * LDAPResult ::= SEQUENCE { * resultCode ENUMERATED, * matchedDN LDAPDN, * errorMessage LDAPString, * referral [3] Referral OPTIONAL } * * including Bind results: * * BindResponse ::= [APPLICATION 1] SEQUENCE { * COMPONENTS OF LDAPResult, * serverSaslCreds [7] OCTET STRING OPTIONAL } * * and ExtendedOp results: * * ExtendedResponse ::= [APPLICATION 24] SEQUENCE { * COMPONENTS OF LDAPResult, * responseName [10] LDAPOID OPTIONAL, * response [11] OCTET STRING OPTIONAL } * */ int ldap_parse_result( LDAP *ld, LDAPMessage *r, int *errcodep, char **matcheddnp, char **errmsgp, char ***referralsp, LDAPControl ***serverctrls, int freeit ) { LDAPMessage *lm; ber_int_t errcode = LDAP_SUCCESS; ber_tag_t tag; BerElement *ber; Debug( LDAP_DEBUG_TRACE, "ldap_parse_result\n", 0, 0, 0 ); assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( r != NULL ); if(errcodep != NULL) *errcodep = LDAP_SUCCESS; if(matcheddnp != NULL) *matcheddnp = NULL; if(errmsgp != NULL) *errmsgp = NULL; if(referralsp != NULL) *referralsp = NULL; if(serverctrls != NULL) *serverctrls = NULL; #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_lock( &ld->ld_res_mutex ); #endif /* Find the result, last msg in chain... */ lm = r->lm_chain_tail; /* FIXME: either this is not possible (assert?) * or it should be handled */ if ( lm != NULL ) { switch ( lm->lm_msgtype ) { case LDAP_RES_SEARCH_ENTRY: case LDAP_RES_SEARCH_REFERENCE: case LDAP_RES_INTERMEDIATE: lm = NULL; break; default: break; } } if( lm == NULL ) { errcode = ld->ld_errno = LDAP_NO_RESULTS_RETURNED; #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_unlock( &ld->ld_res_mutex ); #endif goto done; } if ( ld->ld_error ) { LDAP_FREE( ld->ld_error ); ld->ld_error = NULL; } if ( ld->ld_matched ) { LDAP_FREE( ld->ld_matched ); ld->ld_matched = NULL; } if ( ld->ld_referrals ) { LDAP_VFREE( ld->ld_referrals ); ld->ld_referrals = NULL; } /* parse results */ ber = ber_dup( lm->lm_ber ); if ( ld->ld_version < LDAP_VERSION2 ) { tag = ber_scanf( ber, "{iA}", &ld->ld_errno, &ld->ld_error ); } else { ber_len_t len; tag = ber_scanf( ber, "{iAA" /*}*/, &ld->ld_errno, &ld->ld_matched, &ld->ld_error ); if( tag != LBER_ERROR ) { /* peek for referrals */ if( ber_peek_tag(ber, &len) == LDAP_TAG_REFERRAL ) { tag = ber_scanf( ber, "v", &ld->ld_referrals ); } } /* need to clean out misc items */ if( tag != LBER_ERROR ) { if( lm->lm_msgtype == LDAP_RES_BIND ) { /* look for sasl result creditials */ if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SASL_RES_CREDS ) { /* skip 'em */ tag = ber_scanf( ber, "x" ); } } else if( lm->lm_msgtype == LDAP_RES_EXTENDED ) { /* look for exop result oid or value */ if ( ber_peek_tag( ber, &len ) == LDAP_TAG_EXOP_RES_OID ) { /* skip 'em */ tag = ber_scanf( ber, "x" ); } if ( tag != LBER_ERROR && ber_peek_tag( ber, &len ) == LDAP_TAG_EXOP_RES_VALUE ) { /* skip 'em */ tag = ber_scanf( ber, "x" ); } } } if( tag != LBER_ERROR ) { int rc = ldap_pvt_get_controls( ber, serverctrls ); if( rc != LDAP_SUCCESS ) { tag = LBER_ERROR; } } if( tag != LBER_ERROR ) { tag = ber_scanf( ber, /*{*/"}" ); } } if ( tag == LBER_ERROR ) { ld->ld_errno = errcode = LDAP_DECODING_ERROR; } if( ber != NULL ) { ber_free( ber, 0 ); } /* return */ if( errcodep != NULL ) { *errcodep = ld->ld_errno; } if ( errcode == LDAP_SUCCESS ) { if( matcheddnp != NULL ) { if ( ld->ld_matched ) { *matcheddnp = LDAP_STRDUP( ld->ld_matched ); } } if( errmsgp != NULL ) { if ( ld->ld_error ) { *errmsgp = LDAP_STRDUP( ld->ld_error ); } } if( referralsp != NULL) { *referralsp = ldap_value_dup( ld->ld_referrals ); } } #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_unlock( &ld->ld_res_mutex ); #endif done: if ( freeit ) { ldap_msgfree( r ); } return errcode; }
int ldap_ld_free( LDAP *ld, int close, LDAPControl **sctrls, LDAPControl **cctrls ) { LDAPMessage *lm, *next; int err = LDAP_SUCCESS; LDAP_MUTEX_LOCK( &ld->ld_ldcmutex ); /* Someone else is still using this ld. */ if (ld->ld_ldcrefcnt > 1) { /* but not last thread */ /* clean up self only */ ld->ld_ldcrefcnt--; if ( ld->ld_error != NULL ) { LDAP_FREE( ld->ld_error ); ld->ld_error = NULL; } if ( ld->ld_matched != NULL ) { LDAP_FREE( ld->ld_matched ); ld->ld_matched = NULL; } if ( ld->ld_referrals != NULL) { LDAP_VFREE(ld->ld_referrals); ld->ld_referrals = NULL; } LDAP_MUTEX_UNLOCK( &ld->ld_ldcmutex ); LDAP_FREE( (char *) ld ); return( err ); } /* This ld is the last thread. */ /* free LDAP structure and outstanding requests/responses */ #ifdef LDAP_R_COMPILE #ifdef __APPLE__ /* If the ld is in async mode, this will stop the thread that's handling * the results messages. This *must* be done before anything is torn * down to prevent the thread from using deallocated structs. This is a * blocking call; it won't exit until the thread exits. If not in * async mode, this call does nothing. */ ldap_pvt_clear_search_results_callback( ld ); #endif #endif LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); while ( ld->ld_requests != NULL ) { ldap_free_request( ld, ld->ld_requests ); } LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); /* free and unbind from all open connections */ while ( ld->ld_conns != NULL ) { ldap_free_connection( ld, ld->ld_conns, 1, close ); } LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); LDAP_MUTEX_LOCK( &ld->ld_res_mutex ); #ifdef LDAP_RESPONSE_RB_TREE ldap_resp_rbt_free( ld ); #else for ( lm = ld->ld_responses; lm != NULL; lm = next ) { next = lm->lm_next; ldap_msgfree( lm ); } #endif if ( ld->ld_abandoned != NULL ) { LDAP_FREE( ld->ld_abandoned ); ld->ld_abandoned = NULL; } LDAP_MUTEX_UNLOCK( &ld->ld_res_mutex ); LDAP_MUTEX_LOCK( &ld->ld_ldopts_mutex ); /* final close callbacks */ { ldaplist *ll, *next; for ( ll = ld->ld_options.ldo_conn_cbs; ll; ll = next ) { ldap_conncb *cb = ll->ll_data; next = ll->ll_next; cb->lc_del( ld, NULL, cb ); LDAP_FREE( ll ); } } if ( ld->ld_error != NULL ) { LDAP_FREE( ld->ld_error ); ld->ld_error = NULL; } if ( ld->ld_matched != NULL ) { LDAP_FREE( ld->ld_matched ); ld->ld_matched = NULL; } if ( ld->ld_referrals != NULL) { LDAP_VFREE(ld->ld_referrals); ld->ld_referrals = NULL; } if ( ld->ld_selectinfo != NULL ) { ldap_free_select_info( ld->ld_selectinfo ); ld->ld_selectinfo = NULL; } if ( ld->ld_options.ldo_defludp != NULL ) { ldap_free_urllist( ld->ld_options.ldo_defludp ); ld->ld_options.ldo_defludp = NULL; } #ifdef LDAP_CONNECTIONLESS if ( ld->ld_options.ldo_peer != NULL ) { LDAP_FREE( ld->ld_options.ldo_peer ); ld->ld_options.ldo_peer = NULL; } if ( ld->ld_options.ldo_cldapdn != NULL ) { LDAP_FREE( ld->ld_options.ldo_cldapdn ); ld->ld_options.ldo_cldapdn = NULL; } #endif #ifdef HAVE_CYRUS_SASL if ( ld->ld_options.ldo_def_sasl_mech != NULL ) { LDAP_FREE( ld->ld_options.ldo_def_sasl_mech ); ld->ld_options.ldo_def_sasl_mech = NULL; } if ( ld->ld_options.ldo_def_sasl_realm != NULL ) { LDAP_FREE( ld->ld_options.ldo_def_sasl_realm ); ld->ld_options.ldo_def_sasl_realm = NULL; } if ( ld->ld_options.ldo_def_sasl_authcid != NULL ) { LDAP_FREE( ld->ld_options.ldo_def_sasl_authcid ); ld->ld_options.ldo_def_sasl_authcid = NULL; } if ( ld->ld_options.ldo_def_sasl_authzid != NULL ) { LDAP_FREE( ld->ld_options.ldo_def_sasl_authzid ); ld->ld_options.ldo_def_sasl_authzid = NULL; } #endif #ifdef HAVE_TLS ldap_int_tls_destroy( &ld->ld_options ); #endif if ( ld->ld_options.ldo_sctrls != NULL ) { ldap_controls_free( ld->ld_options.ldo_sctrls ); ld->ld_options.ldo_sctrls = NULL; } if ( ld->ld_options.ldo_cctrls != NULL ) { ldap_controls_free( ld->ld_options.ldo_cctrls ); ld->ld_options.ldo_cctrls = NULL; } if ( ld->ld_options.ldo_sasl_secprops.property_names != NULL ) { LDAP_FREE( ld->ld_options.ldo_sasl_secprops.property_names ); ld->ld_options.ldo_sasl_secprops.property_names = NULL; } if ( ld->ld_options.ldo_sasl_secprops.property_values != NULL ) { LDAP_FREE( ld->ld_options.ldo_sasl_secprops.property_values ); ld->ld_options.ldo_sasl_secprops.property_values = NULL; } if ( ld->ld_options.ldo_sasl_fqdn != NULL ) { LDAP_FREE( ld->ld_options.ldo_sasl_fqdn ); ld->ld_options.ldo_sasl_fqdn = NULL; } LDAP_MUTEX_UNLOCK( &ld->ld_ldopts_mutex ); ber_sockbuf_free( ld->ld_sb ); #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_destroy( &ld->ld_msgid_mutex ); ldap_pvt_thread_mutex_destroy( &ld->ld_conn_mutex ); ldap_pvt_thread_mutex_destroy( &ld->ld_req_mutex ); ldap_pvt_thread_mutex_destroy( &ld->ld_res_mutex ); ldap_pvt_thread_mutex_destroy( &ld->ld_abandon_mutex ); ldap_pvt_thread_mutex_destroy( &ld->ld_ldopts_mutex ); ldap_pvt_thread_mutex_unlock( &ld->ld_ldcmutex ); ldap_pvt_thread_mutex_destroy( &ld->ld_ldcmutex ); #endif #ifndef NDEBUG LDAP_TRASH(ld); #endif LDAP_FREE( (char *) ld->ldc ); LDAP_FREE( (char *) ld ); return( err ); }
/* * Parse LDAPResult Messages: * * LDAPResult ::= SEQUENCE { * resultCode ENUMERATED, * matchedDN LDAPDN, * errorMessage LDAPString, * referral [3] Referral OPTIONAL } * * including Bind results: * * BindResponse ::= [APPLICATION 1] SEQUENCE { * COMPONENTS OF LDAPResult, * serverSaslCreds [7] OCTET STRING OPTIONAL } * * and ExtendedOp results: * * ExtendedResponse ::= [APPLICATION 24] SEQUENCE { * COMPONENTS OF LDAPResult, * responseName [10] LDAPOID OPTIONAL, * response [11] OCTET STRING OPTIONAL } * */ int ldap_parse_result( LDAP *ld, LDAPMessage *r, int *errcodep, char **matcheddnp, char **errmsgp, char ***referralsp, LDAPControl ***serverctrls, int freeit ) { LDAPMessage *lm; ber_int_t errcode = LDAP_SUCCESS; ber_tag_t tag; BerElement *ber; #ifdef NEW_LOGGING LDAP_LOG ( OPERATION, ENTRY, "ldap_parse_result\n", 0,0,0 ); #else Debug( LDAP_DEBUG_TRACE, "ldap_parse_result\n", 0, 0, 0 ); #endif assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( r != NULL ); if(errcodep != NULL) *errcodep = LDAP_SUCCESS; if(matcheddnp != NULL) *matcheddnp = NULL; if(errmsgp != NULL) *errmsgp = NULL; if(referralsp != NULL) *referralsp = NULL; if(serverctrls != NULL) *serverctrls = NULL; /* Find the next result... */ for ( lm = r; lm != NULL; lm = lm->lm_chain ) { /* skip over entries and references */ if( lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY && lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE && lm->lm_msgtype != LDAP_RES_EXTENDED_PARTIAL ) { break; } } if( lm == NULL ) { ld->ld_errno = LDAP_NO_RESULTS_RETURNED; return ld->ld_errno; } if ( ld->ld_error ) { LDAP_FREE( ld->ld_error ); ld->ld_error = NULL; } if ( ld->ld_matched ) { LDAP_FREE( ld->ld_matched ); ld->ld_matched = NULL; } if ( ld->ld_referrals ) { LDAP_VFREE( ld->ld_referrals ); ld->ld_referrals = NULL; } /* parse results */ ber = ber_dup( lm->lm_ber ); if ( ld->ld_version < LDAP_VERSION2 ) { tag = ber_scanf( ber, "{ia}", &ld->ld_errno, &ld->ld_error ); } else { ber_len_t len; tag = ber_scanf( ber, "{iaa" /*}*/, &ld->ld_errno, &ld->ld_matched, &ld->ld_error ); if( tag != LBER_ERROR ) { /* peek for referrals */ if( ber_peek_tag(ber, &len) == LDAP_TAG_REFERRAL ) { tag = ber_scanf( ber, "v", &ld->ld_referrals ); } } /* need to clean out misc items */ if( tag != LBER_ERROR ) { if( lm->lm_msgtype == LDAP_RES_BIND ) { /* look for sasl result creditials */ if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SASL_RES_CREDS ) { /* skip 'em */ tag = ber_scanf( ber, "x" ); } } else if( lm->lm_msgtype == LDAP_RES_EXTENDED ) { /* look for exop result oid or value */ if ( ber_peek_tag( ber, &len ) == LDAP_TAG_EXOP_RES_OID ) { /* skip 'em */ tag = ber_scanf( ber, "x" ); } if ( tag != LBER_ERROR && ber_peek_tag( ber, &len ) == LDAP_TAG_EXOP_RES_VALUE ) { /* skip 'em */ tag = ber_scanf( ber, "x" ); } } } if( tag != LBER_ERROR ) { int rc = ldap_int_get_controls( ber, serverctrls ); if( rc != LDAP_SUCCESS ) { tag = LBER_ERROR; } } if( tag != LBER_ERROR ) { tag = ber_scanf( ber, /*{*/"}" ); } } if ( tag == LBER_ERROR ) { ld->ld_errno = errcode = LDAP_DECODING_ERROR; } if( ber != NULL ) { ber_free( ber, 0 ); } /* return */ if( errcodep != NULL ) { *errcodep = ld->ld_errno; } if ( errcode == LDAP_SUCCESS ) { if( matcheddnp != NULL ) { *matcheddnp = LDAP_STRDUP( ld->ld_matched ); } if( errmsgp != NULL ) { *errmsgp = LDAP_STRDUP( ld->ld_error ); } if( referralsp != NULL) { *referralsp = ldap_value_dup( ld->ld_referrals ); } /* Find the next result... */ for ( lm = lm->lm_chain; lm != NULL; lm = lm->lm_chain ) { /* skip over entries and references */ if( lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY && lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE && lm->lm_msgtype != LDAP_RES_EXTENDED_PARTIAL ) { /* more results to return */ errcode = LDAP_MORE_RESULTS_TO_RETURN; break; } } } if ( freeit ) { ldap_msgfree( r ); } return( errcode ); }
int ldap_parse_reference( LDAP *ld, LDAPMessage *ref, char ***referralsp, LDAPControl ***serverctrls, int freeit) { BerElement be; char **refs = NULL; int rc; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( ref != NULL ); if( ref->lm_msgtype != LDAP_RES_SEARCH_REFERENCE ) { return LDAP_PARAM_ERROR; } /* make a private copy of BerElement */ AC_MEMCPY(&be, ref->lm_ber, sizeof(be)); if ( ber_scanf( &be, "{v" /*}*/, &refs ) == LBER_ERROR ) { rc = LDAP_DECODING_ERROR; goto free_and_return; } if ( serverctrls == NULL ) { rc = LDAP_SUCCESS; goto free_and_return; } if ( ber_scanf( &be, /*{*/ "}" ) == LBER_ERROR ) { rc = LDAP_DECODING_ERROR; goto free_and_return; } rc = ldap_pvt_get_controls( &be, serverctrls ); free_and_return: if( referralsp != NULL ) { /* provide references regradless of return code */ *referralsp = refs; } else { LDAP_VFREE( refs ); } if( freeit ) { ldap_msgfree( ref ); } if( rc != LDAP_SUCCESS ) { ld->ld_errno = rc; if( ld->ld_matched != NULL ) { LDAP_FREE( ld->ld_matched ); ld->ld_matched = NULL; } if( ld->ld_error != NULL ) { LDAP_FREE( ld->ld_error ); ld->ld_error = NULL; } } return rc; }