/*********************************************************************** * ldap_parse_page_controlW (WLDAP32.@) */ ULONG CDECL ldap_parse_page_controlW( WLDAP32_LDAP *ld, PLDAPControlW *ctrls, ULONG *count, struct WLDAP32_berval **cookie ) { ULONG ret = WLDAP32_LDAP_NOT_SUPPORTED; #ifdef HAVE_LDAP LDAPControlW *control = NULL; BerElement *ber; ber_tag_t tag; ULONG i; TRACE( "(%p, %p, %p, %p)\n", ld, ctrls, count, cookie ); if (!ld || !ctrls || !count || !cookie) return WLDAP32_LDAP_PARAM_ERROR; for (i = 0; ctrls[i]; i++) { if (!lstrcmpW( LDAP_PAGED_RESULT_OID_STRING_W, ctrls[i]->ldctl_oid )) control = ctrls[i]; } if (!control) return WLDAP32_LDAP_CONTROL_NOT_FOUND; ber = ber_init( &((LDAPControl *)control)->ldctl_value ); if (!ber) return WLDAP32_LDAP_NO_MEMORY; tag = ber_scanf( ber, "{iO}", count, cookie ); if ( tag == LBER_ERROR ) ret = WLDAP32_LDAP_DECODING_ERROR; else ret = WLDAP32_LDAP_SUCCESS; ber_free( ber, 1 ); #endif return ret; }
/* * load libldap's attributes data structure into ruby hash */ static VALUE rb_ldap_entry_load_attr(LDAP *ldap, LDAPMessage *msg) { VALUE hash = rb_hash_new(); BerElement *ber = NULL; char *c_attr; for (c_attr = ldap_first_attribute(ldap, msg, &ber); c_attr != NULL; c_attr = ldap_next_attribute(ldap, msg, ber)) { VALUE attr = rb_tainted_str_new2(c_attr); VALUE vals = rb_ldap_entry_load_val(ldap, msg, c_attr); rb_hash_aset(hash, attr, vals); ldap_memfree(c_attr); } #if !defined(USE_OPENLDAP1) ber_free(ber, 0); #endif return hash; }
/* Create an LDAP_SERVER_EXTENDED_DN control. */ int _ldap_create_extended_dn_control(LDAP *ld, int format, LDAPControl **edn_ctrl) { int rc = -1; BerElement *ber = NULL; struct berval *value = NULL; LDAPControl *ctrl = NULL; ber = ber_alloc_t(LBER_USE_DER); if (ber == NULL) return LDAP_NO_MEMORY; /* Transcode the data into a berval struct. */ ber_printf(ber, "{i}", format); rc = ber_flatten(ber, &value); ber_free(ber, 1); if (rc != 0) return rc; rc = ldap_control_create(LDAP_SERVER_EXTENDED_DN_OID, 0, value, 1, &ctrl); ber_bvfree(value); if (rc != LDAP_SUCCESS) return rc; *edn_ctrl = ctrl; return LDAP_SUCCESS; }
char * ldap_first_attribute( LDAP *ld, LDAPMessage *entry, BerElement **ber ) { int len; char *attrbuffer; if ((attrbuffer = (char *)malloc(LDAP_MAX_ATTR_LEN)) == NULL) { return (NULL); } Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 179, "ldap_first_attribute\n"), 0, 0, 0 ); if ( (*ber = alloc_ber_with_options( ld )) == NULLBER ) { free(attrbuffer); return( NULL ); } **ber = *entry->lm_ber; /* * Skip past the sequence, dn, sequence of sequence, snarf the * attribute type, and skip the set of values, leaving us * positioned right before the next attribute type/value sequence. */ len = LDAP_MAX_ATTR_LEN; if ( ber_scanf( *ber, "{x{{sx}", attrbuffer, &len ) == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; ber_free( *ber, 0 ); *ber = NULL; free(attrbuffer); return( NULL ); } return( attrbuffer ); }
/** Takes the object DN and BER encodes the data into the BER value which is used as part of the request * @verbatim RequestBer contents: clientVersion INTEGER targetObjectDN OCTET STRING @endverbatim * * @param[out] request_bv where to write the request BER value (must be freed with ber_bvfree). * @param[in] dn to query for. * @return 0 on success, and < 0 on error. */ static int ber_encode_request_data(char const *dn, struct berval **request_bv) { int err = 0; int rc = 0; BerElement *request_ber = NULL; if (!dn || !*dn) { err = NMAS_E_INVALID_PARAMETER; goto finish; } /* Allocate a BerElement for the request parameters.*/ if ((request_ber = ber_alloc()) == NULL) { err = NMAS_E_FRAG_FAILURE; goto finish; } rc = ber_printf(request_ber, "{io}", NMAS_LDAP_EXT_VERSION, dn, strlen(dn) + 1); if (rc < 0) { err = NMAS_E_FRAG_FAILURE; goto finish; } /* * Convert the BER we just built to a berval that we'll * send with the extended request. */ if (ber_flatten(request_ber, request_bv) < 0) { err = NMAS_E_FRAG_FAILURE; goto finish; } finish: if (request_ber) ber_free(request_ber, 1); return err; }
int checkBindRes(BerElement *ber) { ber_tag_t tag; ber_int_t resultCode; ber_len_t len; #ifdef DEBUG int ival = -1; ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &ival ); #endif if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) { /* log, close and send error */ printf(">>Error<< PeeK failed, tag;%d\n", tag); ber_free( ber, 1 ); return LBER_ERROR; } tag = ber_scanf( ber, "{i}" , &resultCode ); if ( tag == LBER_ERROR ) { return LBER_ERROR; //printf("BER decode Error! Ber_Scanf return tag:%d.\n", tag); } return resultCode; }
static int do_base( char *uri, char *dn, struct berval *pass, char *base, char *filter, char *pwattr, int maxloop, int force, int chaserefs, int noinit, int delay, int action_type, void *action ) { LDAP *ld = NULL; int i = 0; int rc = LDAP_SUCCESS; ber_int_t msgid; LDAPMessage *res, *msg; char **dns = NULL; struct berval *creds = NULL; char *attrs[] = { LDAP_NO_ATTRS, NULL }; int ndns = 0; #ifdef _WIN32 DWORD beg, end; #else struct timeval beg, end; #endif int version = LDAP_VERSION3; char *nullstr = ""; ldap_initialize( &ld, uri ); if ( ld == NULL ) { tester_perror( "ldap_initialize", NULL ); exit( EXIT_FAILURE ); } (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); (void) ldap_set_option( ld, LDAP_OPT_REFERRALS, chaserefs ? LDAP_OPT_ON: LDAP_OPT_OFF ); rc = ldap_sasl_bind_s( ld, dn, LDAP_SASL_SIMPLE, pass, NULL, NULL, NULL ); if ( rc != LDAP_SUCCESS ) { tester_ldap_error( ld, "ldap_sasl_bind_s", NULL ); exit( EXIT_FAILURE ); } fprintf( stderr, "PID=%ld - Bind(%d): base=\"%s\", filter=\"%s\" attr=\"%s\".\n", (long) pid, maxloop, base, filter, pwattr ); if ( pwattr != NULL ) { attrs[ 0 ] = pwattr; } rc = ldap_search_ext( ld, base, LDAP_SCOPE_SUBTREE, filter, attrs, 0, NULL, NULL, 0, 0, &msgid ); if ( rc != LDAP_SUCCESS ) { tester_ldap_error( ld, "ldap_search_ext", NULL ); exit( EXIT_FAILURE ); } while ( ( rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ONE, NULL, &res ) ) > 0 ) { BerElement *ber; struct berval bv; int done = 0; for ( msg = ldap_first_message( ld, res ); msg; msg = ldap_next_message( ld, msg ) ) { switch ( ldap_msgtype( msg ) ) { case LDAP_RES_SEARCH_ENTRY: rc = ldap_get_dn_ber( ld, msg, &ber, &bv ); dns = realloc( dns, (ndns + 1)*sizeof(char *) ); dns[ndns] = ber_strdup( bv.bv_val ); if ( pwattr != NULL ) { struct berval **values = ldap_get_values_len( ld, msg, pwattr ); creds = realloc( creds, (ndns + 1)*sizeof(struct berval) ); if ( values == NULL ) { novals:; creds[ndns].bv_len = 0; creds[ndns].bv_val = nullstr; } else { static struct berval cleartext = BER_BVC( "{CLEARTEXT} " ); struct berval value = *values[ 0 ]; if ( value.bv_val[ 0 ] == '{' ) { char *end = ber_bvchr( &value, '}' ); if ( end ) { if ( ber_bvcmp( &value, &cleartext ) == 0 ) { value.bv_val += cleartext.bv_len; value.bv_len -= cleartext.bv_len; } else { ldap_value_free_len( values ); goto novals; } } } ber_dupbv( &creds[ndns], &value ); ldap_value_free_len( values ); } } ndns++; ber_free( ber, 0 ); break; case LDAP_RES_SEARCH_RESULT: done = 1; break; } if ( done ) break; } ldap_msgfree( res ); if ( done ) break; } #ifdef _WIN32 beg = GetTickCount(); #else gettimeofday( &beg, NULL ); #endif if ( ndns == 0 ) { tester_error( "No DNs" ); return 1; } fprintf( stderr, " PID=%ld - Bind base=\"%s\" filter=\"%s\" got %d values.\n", (long) pid, base, filter, ndns ); /* Ok, got list of DNs, now start binding to each */ for ( i = 0; i < maxloop; i++ ) { int j; struct berval cred = { 0, NULL }; #if 0 /* use high-order bits for better randomness (Numerical Recipes in "C") */ j = rand() % ndns; #endif j = ((double)ndns)*rand()/(RAND_MAX + 1.0); if ( creds && !BER_BVISEMPTY( &creds[j] ) ) { cred = creds[j]; } if ( do_bind( uri, dns[j], &cred, 1, force, chaserefs, noinit, &ld, action_type, action ) && !force ) { break; } if ( delay ) { sleep( delay ); } } if ( ld != NULL ) { ldap_unbind_ext( ld, NULL, NULL ); ld = NULL; } #ifdef _WIN32 end = GetTickCount(); end -= beg; fprintf( stderr, " PID=%ld - Bind done %d in %d.%03d seconds.\n", (long) pid, i, end / 1000, end % 1000 ); #else gettimeofday( &end, NULL ); end.tv_usec -= beg.tv_usec; if (end.tv_usec < 0 ) { end.tv_usec += 1000000; end.tv_sec -= 1; } end.tv_sec -= beg.tv_sec; fprintf( stderr, " PID=%ld - Bind done %d in %ld.%06ld seconds.\n", (long) pid, i, (long) end.tv_sec, (long) end.tv_usec ); #endif if ( dns ) { for ( i = 0; i < ndns; i++ ) { ber_memfree( dns[i] ); } free( dns ); } if ( creds ) { for ( i = 0; i < ndns; i++ ) { if ( creds[i].bv_val != nullstr ) { ber_memfree( creds[i].bv_val ); } } free( creds ); } return 0; }
int ldap_send_server_request( LDAP *ld, BerElement *ber, ber_int_t msgid, LDAPRequest *parentreq, LDAPURLDesc **srvlist, LDAPConn *lc, LDAPreqinfo *bind, int m_noconn, int m_res ) { LDAPRequest *lr; int incparent, rc; LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex ); Debug( LDAP_DEBUG_TRACE, "ldap_send_server_request\n", 0, 0, 0 ); incparent = 0; ld->ld_errno = LDAP_SUCCESS; /* optimistic */ LDAP_CONN_LOCK_IF(m_noconn); if ( lc == NULL ) { if ( srvlist == NULL ) { lc = ld->ld_defconn; } else { lc = find_connection( ld, *srvlist, 1 ); if ( lc == NULL ) { if ( (bind != NULL) && (parentreq != NULL) ) { /* Remember the bind in the parent */ incparent = 1; ++parentreq->lr_outrefcnt; } lc = ldap_new_connection( ld, srvlist, 0, 1, bind, 1, m_res ); } } } /* async connect... */ if ( lc != NULL && lc->lconn_status == LDAP_CONNST_CONNECTING ) { ber_socket_t sd = AC_SOCKET_ERROR; struct timeval tv = { 0 }; ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_GET_FD, &sd ); /* poll ... */ switch ( ldap_int_poll( ld, sd, &tv, 1 ) ) { case 0: /* go on! */ lc->lconn_status = LDAP_CONNST_CONNECTED; break; case -2: /* async only occurs if a network timeout is set */ /* honor network timeout */ LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex ); if ( time( NULL ) - lc->lconn_created <= ld->ld_options.ldo_tm_net.tv_sec ) { /* caller will have to call again */ ld->ld_errno = LDAP_X_CONNECTING; } LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex ); /* fallthru */ default: /* error */ break; } } if ( lc == NULL || lc->lconn_status != LDAP_CONNST_CONNECTED ) { if ( ld->ld_errno == LDAP_SUCCESS ) { ld->ld_errno = LDAP_SERVER_DOWN; } ber_free( ber, 1 ); if ( incparent ) { /* Forget about the bind */ --parentreq->lr_outrefcnt; } LDAP_CONN_UNLOCK_IF(m_noconn); return( -1 ); } use_connection( ld, lc ); #ifdef LDAP_CONNECTIONLESS if ( LDAP_IS_UDP( ld )) { BerElement tmpber = *ber; ber_rewind( &tmpber ); LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex ); rc = ber_write( &tmpber, ld->ld_options.ldo_peer, sizeof( struct sockaddr_storage ), 0 ); LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex ); if ( rc == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; LDAP_CONN_UNLOCK_IF(m_noconn); return rc; } } #endif /* If we still have an incomplete write, try to finish it before * dealing with the new request. If we don't finish here, return * LDAP_BUSY and let the caller retry later. We only allow a single * request to be in WRITING state. */ rc = 0; if ( ld->ld_requests && ld->ld_requests->lr_status == LDAP_REQST_WRITING && ldap_int_flush_request( ld, ld->ld_requests ) < 0 ) { rc = -1; } if ( rc ) { LDAP_CONN_UNLOCK_IF(m_noconn); return rc; } lr = (LDAPRequest *)LDAP_CALLOC( 1, sizeof( LDAPRequest ) ); if ( lr == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; ldap_free_connection( ld, lc, 0, 0 ); ber_free( ber, 1 ); if ( incparent ) { /* Forget about the bind */ --parentreq->lr_outrefcnt; } LDAP_CONN_UNLOCK_IF(m_noconn); return( -1 ); } lr->lr_msgid = msgid; lr->lr_status = LDAP_REQST_INPROGRESS; lr->lr_res_errno = LDAP_SUCCESS; /* optimistic */ lr->lr_ber = ber; lr->lr_conn = lc; if ( parentreq != NULL ) { /* sub-request */ if ( !incparent ) { /* Increment if we didn't do it before the bind */ ++parentreq->lr_outrefcnt; } lr->lr_origid = parentreq->lr_origid; lr->lr_parentcnt = ++parentreq->lr_parentcnt; lr->lr_parent = parentreq; lr->lr_refnext = parentreq->lr_child; parentreq->lr_child = lr; } else { /* original request */ lr->lr_origid = lr->lr_msgid; } /* Extract requestDN for future reference */ #ifdef LDAP_CONNECTIONLESS if ( !LDAP_IS_UDP(ld) ) #endif { BerElement tmpber = *ber; ber_int_t bint; ber_tag_t tag, rtag; ber_reset( &tmpber, 1 ); rtag = ber_scanf( &tmpber, "{it", /*}*/ &bint, &tag ); switch ( tag ) { case LDAP_REQ_BIND: rtag = ber_scanf( &tmpber, "{i" /*}*/, &bint ); break; case LDAP_REQ_DELETE: break; default: rtag = ber_scanf( &tmpber, "{" /*}*/ ); case LDAP_REQ_ABANDON: break; } if ( tag != LDAP_REQ_ABANDON ) { ber_skip_tag( &tmpber, &lr->lr_dn.bv_len ); lr->lr_dn.bv_val = tmpber.ber_ptr; } } lr->lr_prev = NULL; lr->lr_next = ld->ld_requests; if ( lr->lr_next != NULL ) { lr->lr_next->lr_prev = lr; } ld->ld_requests = lr; ld->ld_errno = LDAP_SUCCESS; if ( ldap_int_flush_request( ld, lr ) == -1 ) { msgid = -1; } LDAP_CONN_UNLOCK_IF(m_noconn); return( msgid ); }
int LDAP_CALL ldap_parse_userstatus_control(LDAP *ld, LDAPControl **ctrlp, LDAPuserstatus *us) { BerElement *ber = NULL; int i, foundUSControl; LDAPControl *USCtrlp = NULL; ber_tag_t tag; if (!NSLDAPI_VALID_LDAP_POINTER(ld) || us == NULL) { return (LDAP_PARAM_ERROR); } /* find the control in the list of controls if it exists */ if (ctrlp == NULL) { LDAP_SET_LDERRNO(ld, LDAP_CONTROL_NOT_FOUND, NULL, NULL); return (LDAP_CONTROL_NOT_FOUND); } foundUSControl = 0; for (i = 0; ((ctrlp[i] != NULL) && (!foundUSControl)); i++) { foundUSControl = !strcmp(ctrlp[i]->ldctl_oid, LDAP_CONTROL_ACCOUNT_USABLE); } if (!foundUSControl) { LDAP_SET_LDERRNO(ld, LDAP_CONTROL_NOT_FOUND, NULL, NULL); return (LDAP_CONTROL_NOT_FOUND); } else { /* let local var point to the control */ USCtrlp = ctrlp[i - 1]; } /* allocate a Ber element with the contents of the control's struct berval */ if ((ber = ber_init(&USCtrlp->ldctl_value)) == NULL) { LDAP_SET_LDERRNO(ld, LDAP_NO_MEMORY, NULL, NULL); return (LDAP_NO_MEMORY); } memset(us, 0, sizeof(struct LDAPuserstatus)); /* * The control value should look like this: * * ACCOUNT_USABLE_RESPONSE::= CHOICE { * is_available [0] INTEGER, ** seconds before expiration ** * is_not_available [1] More_info * } * More_info::= SEQUENCE { * inactive [0] BOOLEAN DEFAULT FALSE, * reset [1] BOOLEAN DEFAULT FALSE, * expired [2] BOOLEAN DEFAULT FALSE, * remaining_grace [3] INTEGER OPTIONAL, * seconds_before_unlock [4] INTEGER OPTIONAL * } */ if ((ber_scanf(ber, "t", &tag)) == LBER_ERROR) { LDAP_SET_LDERRNO(ld, LDAP_DECODING_ERROR, NULL, NULL); ber_free(ber, 1); return (LDAP_DECODING_ERROR); } tag = ((tag & LBER_CONSTRUCTED) == LBER_CONSTRUCTED) ? 1 : 0; if (!tag) { us->us_available = 1; if (ber_scanf(ber, "i", &us->us_expire) == LBER_ERROR) { LDAP_SET_LDERRNO(ld, LDAP_DECODING_ERROR, NULL, NULL); ber_free(ber, 1); return (LDAP_DECODING_ERROR); } } else { us->us_available = 0; tag = 0; if ((ber_scanf(ber, "{t", &tag)) == LBER_ERROR) { LDAP_SET_LDERRNO(ld, LDAP_DECODING_ERROR, NULL, NULL); ber_free(ber, 1); return (LDAP_DECODING_ERROR); } while (tag != LBER_ERROR && tag != LBER_END_OF_SEQORSET) { tag = tag & (~LBER_CLASS_CONTEXT); switch (tag) { case 0: if (ber_scanf(ber, "b", &us->us_inactive) == LBER_ERROR) { LDAP_SET_LDERRNO(ld, LDAP_DECODING_ERROR, NULL, NULL); ber_free(ber, 1); return (LDAP_DECODING_ERROR); } us->us_inactive = (us->us_inactive != 0) ? 1 : 0; break; case 1: if (ber_scanf(ber, "b", &us->us_reset) == LBER_ERROR) { LDAP_SET_LDERRNO(ld, LDAP_DECODING_ERROR, NULL, NULL); ber_free(ber, 1); return (LDAP_DECODING_ERROR); } us->us_reset = (us->us_reset != 0) ? 1 : 0; break; case 2: if (ber_scanf(ber, "b", &us->us_expired) == LBER_ERROR) { LDAP_SET_LDERRNO(ld, LDAP_DECODING_ERROR, NULL, NULL); ber_free(ber, 1); return (LDAP_DECODING_ERROR); } us->us_expired = (us->us_expired != 0) ? 1 : 0; break; case 3: if (ber_scanf(ber, "i", &us->us_remaining) == LBER_ERROR) { LDAP_SET_LDERRNO(ld, LDAP_DECODING_ERROR, NULL, NULL); ber_free(ber, 1); return (LDAP_DECODING_ERROR); } break; case 4: if (ber_scanf(ber, "i", &us->us_seconds) == LBER_ERROR) { LDAP_SET_LDERRNO(ld, LDAP_DECODING_ERROR, NULL, NULL); ber_free(ber, 1); return (LDAP_DECODING_ERROR); } break; default: LDAP_SET_LDERRNO(ld, LDAP_DECODING_ERROR, NULL, NULL); ber_free(ber, 1); return (LDAP_DECODING_ERROR); } ber_scanf(ber, "t", &tag); } } /* the ber encoding is no longer needed */ ber_free(ber, 1); return (LDAP_SUCCESS); }
void AD::AddUsers(LDAPMessage *search) { DWORD i; DWORD j; LDAPMessage *entry = NULL; PWCHAR attribute; PWCHAR *values; BerElement *berElement; for(i = 0; i < ldap_count_entries(ldap, search); i++) { User *u = new User(); if(!i) { entry = ldap_first_entry(ldap, search); } else { entry = ldap_next_entry(ldap, entry); } attribute = ldap_first_attribute(ldap, entry, &berElement); while(attribute != NULL) { //wprintf(L"%s: ", attribute); values = ldap_get_values(ldap, entry, attribute); u->sidString = L"N/A"; u->lastLogin = 0; u->lastLogout = 0; if(lstrcmpi(attribute, L"samaccountname") == 0) { u->accountName.append(values[0]); } if(lstrcmpi(attribute, L"cn") == 0) { u->fullName.append(values[0]); } if(lstrcmpi(attribute, L"homedirectory") == 0) { u->homePath.append(values[0]); } if(lstrcmpi(attribute, L"memberof") == 0) { for(j = 0; j < ldap_count_values(values); j++) { std::wstring groupString = values[j]; // The 3 offset from left makes sense (to cull out the CN=) // but I'm not quite sure whey I need to find()-3. Here's // hoping that doesn't break when tested out in the world. std::wstring subString = groupString.substr(3, groupString.find(L",")-3); std::wstring *testString = new std::wstring(subString); if(subString.length() > 0) { u->groups.push_back(new std::wstring(subString)); } } } ldap_value_free(values); ldap_memfree(attribute); attribute = ldap_next_attribute(ldap, entry, berElement); } ber_free(berElement, 0); // Moment of truth; we only want accounts with account names. if(u->accountName.length() > 0) { GetUserManager()->users.push_back(u); u->PrettyPrint(); } else { delete(u); } } }
/* * returns an LDAP error code * * XXXmcs: this function used to have #ifdef LDAP_DNS code in it but I * removed it when I improved the parsing (we don't define LDAP_DNS * here at Netscape). */ static int chase_one_referral( LDAP *ld, LDAPRequest *lr, LDAPRequest *origreq, char *refurl, char *desc, int *unknownp ) { int rc, tmprc, secure, msgid; LDAPServer *srv; BerElement *ber; LDAPURLDesc *ludp; *unknownp = 0; ludp = NULLLDAPURLDESC; if ( nsldapi_url_parse( refurl, &ludp, 0 ) != 0 ) { LDAPDebug( LDAP_DEBUG_TRACE, "ignoring unknown %s <%s>\n", desc, refurl, 0 ); *unknownp = 1; rc = LDAP_SUCCESS; goto cleanup_and_return; } secure = (( ludp->lud_options & LDAP_URL_OPT_SECURE ) != 0 ); /* XXXmcs: can't tell if secure is supported by connect callback */ if ( secure && ld->ld_extconnect_fn == NULL ) { LDAPDebug( LDAP_DEBUG_TRACE, "ignoring LDAPS %s <%s>\n", desc, refurl, 0 ); *unknownp = 1; rc = LDAP_SUCCESS; goto cleanup_and_return; } LDAPDebug( LDAP_DEBUG_TRACE, "chasing LDAP%s %s: <%s>\n", secure ? "S" : "", desc, refurl ); LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK ); msgid = ++ld->ld_msgid; LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK ); if (( tmprc = re_encode_request( ld, origreq->lr_ber, msgid, ludp, &ber )) != LDAP_SUCCESS ) { rc = tmprc; goto cleanup_and_return; } if (( srv = (LDAPServer *)NSLDAPI_CALLOC( 1, sizeof( LDAPServer ))) == NULL ) { ber_free( ber, 1 ); rc = LDAP_NO_MEMORY; goto cleanup_and_return; } if (ludp->lud_host == NULL && ld->ld_defhost == NULL) { srv->lsrv_host = NULL; } else { if (ludp->lud_host == NULL) { srv->lsrv_host = nsldapi_strdup( origreq->lr_conn->lconn_server->lsrv_host ); LDAPDebug(LDAP_DEBUG_TRACE, "chase_one_referral: using hostname '%s' from original " "request on new request\n", srv->lsrv_host, 0, 0); } else { srv->lsrv_host = nsldapi_strdup(ludp->lud_host); LDAPDebug(LDAP_DEBUG_TRACE, "chase_one_referral: using hostname '%s' as specified " "on new request\n", srv->lsrv_host, 0, 0); } if (srv->lsrv_host == NULL) { NSLDAPI_FREE((char *)srv); ber_free(ber, 1); rc = LDAP_NO_MEMORY; goto cleanup_and_return; } } /* * According to our reading of RFCs 2255 and 1738, the * following algorithm applies: * - no hostport (no host, no port) provided in LDAP URL, use those * of previous request * - no port but a host, use default LDAP port * - else use given hostport */ if (ludp->lud_port == 0 && ludp->lud_host == NULL) { srv->lsrv_port = origreq->lr_conn->lconn_server->lsrv_port; LDAPDebug(LDAP_DEBUG_TRACE, "chase_one_referral: using port (%d) from original " "request on new request\n", srv->lsrv_port, 0, 0); } else if (ludp->lud_port == 0 && ludp->lud_host != NULL) { srv->lsrv_port = (secure) ? LDAPS_PORT : LDAP_PORT; LDAPDebug(LDAP_DEBUG_TRACE, "chase_one_referral: using default port (%d) \n", srv->lsrv_port, 0, 0); } else { srv->lsrv_port = ludp->lud_port; LDAPDebug(LDAP_DEBUG_TRACE, "chase_one_referral: using port (%d) as specified on " "new request\n", srv->lsrv_port, 0, 0); } if ( secure ) { srv->lsrv_options |= LDAP_SRV_OPT_SECURE; } if ( nsldapi_send_server_request( ld, ber, msgid, lr, srv, NULL, NULL, 1 ) < 0 ) { rc = LDAP_GET_LDERRNO( ld, NULL, NULL ); LDAPDebug( LDAP_DEBUG_ANY, "Unable to chase %s %s (%s)\n", desc, refurl, ldap_err2string( rc )); } else { rc = LDAP_SUCCESS; } cleanup_and_return: if ( ludp != NULLLDAPURLDESC ) { ldap_free_urldesc( ludp ); } return( rc ); }
/* returns an LDAP error code */ static int re_encode_request( LDAP *ld, BerElement *origber, int msgid, LDAPURLDesc *ludp, BerElement **berp ) { /* * XXX this routine knows way too much about how the lber library works! */ ber_uint_t along; ber_tag_t tag; ber_int_t ver; int rc; BerElement *ber; struct berelement tmpber; char *dn, *orig_dn; LDAPDebug( LDAP_DEBUG_TRACE, "re_encode_request: new msgid %d, new dn <%s>\n", msgid, ( ludp->lud_dn == NULL ) ? "NONE" : ludp->lud_dn, 0 ); tmpber = *origber; /* * All LDAP requests are sequences that start with a message id. For * everything except delete requests, this is followed by a sequence * that is tagged with the operation code. For deletes, there is just * a DN that is tagged with the operation code. */ /* skip past msgid and get operation tag */ if ( ber_scanf( &tmpber, "{it", &along, &tag ) == LBER_ERROR ) { return( LDAP_DECODING_ERROR ); } /* * XXXmcs: we don't support scope or filters in search referrals yet, * so if either were present we return an error which is probably * better than just ignoring the extra info. */ if ( tag == LDAP_REQ_SEARCH && ( ludp->lud_scope != -1 || ludp->lud_filter != NULL )) { return( LDAP_LOCAL_ERROR ); } if ( tag == LDAP_REQ_BIND ) { /* bind requests have a version number before the DN */ rc = ber_scanf( &tmpber, "{ia", &ver, &orig_dn ); } else if ( tag == LDAP_REQ_DELETE ) { /* delete requests DNs are not within a sequence */ rc = ber_scanf( &tmpber, "a", &orig_dn ); } else { rc = ber_scanf( &tmpber, "{a", &orig_dn ); } if ( rc == LBER_ERROR ) { return( LDAP_DECODING_ERROR ); } if ( ludp->lud_dn == NULL ) { dn = orig_dn; } else { dn = ludp->lud_dn; NSLDAPI_FREE( orig_dn ); orig_dn = NULL; } /* allocate and build the new request */ if (( rc = nsldapi_alloc_ber_with_options( ld, &ber )) != LDAP_SUCCESS ) { if ( orig_dn != NULL ) { NSLDAPI_FREE( orig_dn ); } return( rc ); } if ( tag == LDAP_REQ_BIND ) { rc = ber_printf( ber, "{it{is", msgid, tag, (int)ver /* XXX lossy cast */, dn ); } else if ( tag == LDAP_REQ_DELETE ) { rc = ber_printf( ber, "{its}", msgid, tag, dn ); } else { rc = ber_printf( ber, "{it{s", msgid, tag, dn ); } if ( orig_dn != NULL ) { NSLDAPI_FREE( orig_dn ); } /* * can't use "dn" or "orig_dn" from this point on (they've been freed) */ if ( rc == -1 ) { ber_free( ber, 1 ); return( LDAP_ENCODING_ERROR ); } if ( tag != LDAP_REQ_DELETE && ( ber_write( ber, tmpber.ber_ptr, ( tmpber.ber_end - tmpber.ber_ptr ), 0 ) != ( tmpber.ber_end - tmpber.ber_ptr ) || ber_printf( ber, "}}" ) == -1 )) { ber_free( ber, 1 ); return( LDAP_ENCODING_ERROR ); } #ifdef LDAP_DEBUG if ( ldap_debug & LDAP_DEBUG_PACKETS ) { LDAPDebug( LDAP_DEBUG_ANY, "re_encode_request new request is:\n", 0, 0, 0 ); ber_dump( ber, 0 ); } #endif /* LDAP_DEBUG */ *berp = ber; return( LDAP_SUCCESS ); }
char * ldap_first_attribute( LDAP *ld, LDAPMessage *entry, BerElement **berout ) { int rc; ber_tag_t tag; ber_len_t len = 0; char *attr; BerElement *ber; Debug( LDAP_DEBUG_TRACE, "ldap_first_attribute\n", 0, 0, 0 ); assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( entry != NULL ); assert( berout != NULL ); *berout = NULL; ber = ldap_alloc_ber_with_options( ld ); if( ber == NULL ) { return NULL; } *ber = *entry->lm_ber; /* * Skip past the sequence, dn, sequence of sequence leaving * us at the first attribute. */ tag = ber_scanf( ber, "{xl{" /*}}*/, &len ); if( tag == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; ber_free( ber, 0 ); return NULL; } /* set the length to avoid overrun */ rc = ber_set_option( ber, LBER_OPT_REMAINING_BYTES, &len ); if( rc != LBER_OPT_SUCCESS ) { ld->ld_errno = LDAP_LOCAL_ERROR; ber_free( ber, 0 ); return NULL; } if ( ber_pvt_ber_remaining( ber ) == 0 ) { assert( len == 0 ); ber_free( ber, 0 ); return NULL; } assert( len != 0 ); /* snatch the first attribute */ tag = ber_scanf( ber, "{ax}", &attr ); if( tag == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; ber_free( ber, 0 ); return NULL; } *berout = ber; return attr; }
/* * ldap_sasl_bind - authenticate to the ldap server. The dn, mechanism, * and credentials of the entry to which to bind are supplied. An LDAP * error code is returned and if LDAP_SUCCESS is returned *msgidp is set * to the id of the request initiated. * * Example: * struct berval creds; * LDAPControl **ctrls; * int err, msgid; * ... fill in creds with credentials ... * ... fill in ctrls with server controls ... * err = ldap_sasl_bind( ld, "cn=manager, o=university of michigan, c=us", * "mechanismname", &creds, ctrls, NULL, &msgid ); */ int LDAP_CALL ldap_sasl_bind( LDAP *ld, const char *dn, const char *mechanism, const struct berval *cred, LDAPControl **serverctrls, LDAPControl **clientctrls, int *msgidp ) { BerElement *ber; int rc, simple, msgid, ldapversion; /* * The ldapv3 bind request looks like this: * BindRequest ::= SEQUENCE { * version INTEGER, * name DistinguishedName, -- who * authentication CHOICE { * simple [0] OCTET STRING, -- passwd * sasl [3] SaslCredentials -- v3 only * } * } * SaslCredentials ::= SEQUENCE { * mechanism LDAPString, * credentials OCTET STRING * } * all wrapped up in an LDAPMessage sequence. */ LDAPDebug( LDAP_DEBUG_TRACE, "ldap_sasl_bind\n", 0, 0, 0 ); if ( msgidp == NULL ) { LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL ); return( LDAP_PARAM_ERROR ); } simple = ( mechanism == LDAP_SASL_SIMPLE ); ldapversion = NSLDAPI_LDAP_VERSION( ld ); /* only ldapv3 or higher can do sasl binds */ if ( !simple && ldapversion < LDAP_VERSION3 ) { LDAP_SET_LDERRNO( ld, LDAP_NOT_SUPPORTED, NULL, NULL ); return( LDAP_NOT_SUPPORTED ); } LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK ); msgid = ++ld->ld_msgid; LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK ); if ( dn == NULL ) dn = ""; if ( ld->ld_cache_on && ld->ld_cache_bind != NULL ) { LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK ); if ( (rc = (ld->ld_cache_bind)( ld, msgid, LDAP_REQ_BIND, dn, cred, LDAP_AUTH_SASL )) != 0 ) { *msgidp = rc; LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK ); return( LDAP_SUCCESS ); } LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK ); } /* create a message to send */ if (( rc = nsldapi_alloc_ber_with_options( ld, &ber )) != LDAP_SUCCESS ) { return( rc ); } /* fill it in */ if ( simple ) { /* simple bind; works in LDAPv2 or v3 */ struct berval tmpcred; if ( cred == NULL ) { tmpcred.bv_val = ""; tmpcred.bv_len = 0; cred = &tmpcred; } rc = ber_printf( ber, "{it{isto}", msgid, LDAP_REQ_BIND, ldapversion, dn, LDAP_AUTH_SIMPLE, cred->bv_val, (int)cred->bv_len /* XXX lossy cast */ ); } else { /* SASL bind; requires LDAPv3 or better */ if ( cred == NULL ) { rc = ber_printf( ber, "{it{ist{s}}", msgid, LDAP_REQ_BIND, ldapversion, dn, LDAP_AUTH_SASL, mechanism ); } else { rc = ber_printf( ber, "{it{ist{so}}", msgid, LDAP_REQ_BIND, ldapversion, dn, LDAP_AUTH_SASL, mechanism, cred->bv_val, (int)cred->bv_len /* XXX lossy cast */ ); } } if ( rc == -1 ) { LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL ); ber_free( ber, 1 ); return( LDAP_ENCODING_ERROR ); } if ( (rc = nsldapi_put_controls( ld, serverctrls, 1, ber )) != LDAP_SUCCESS ) { ber_free( ber, 1 ); return( rc ); } /* send the message */ rc = nsldapi_send_initial_request( ld, msgid, LDAP_REQ_BIND, (char *)dn, ber ); *msgidp = rc; return( rc < 0 ? LDAP_GET_LDERRNO( ld, NULL, NULL ) : LDAP_SUCCESS ); }
int main( int argc, char **argv ) { LDAP *ld; LDAPMessage *result, *e; BerElement *ber; char *host, *a, *dn; char **vals; int i; int rc; int finished; int msgid; int num_entries = 0; struct timeval zerotime; if ( argc > 1 ) { host = argv[1]; } else { host = MY_HOST; } zerotime.tv_sec = zerotime.tv_usec = 0L; if ( prldap_install_routines( NULL, 1 /* shared */ ) != LDAP_SUCCESS ) { ldap_perror( NULL, "prldap_install_routines" ); return( 1 ); } /* get a handle to an LDAP connection */ if ( (ld = ldap_init( host, MY_PORT )) == NULL ) { perror( host ); return( 1 ); } /* authenticate to the directory as nobody */ if ( ldap_simple_bind_s( ld, NULL, NULL ) != LDAP_SUCCESS ) { ldap_perror( ld, "ldap_simple_bind_s" ); return( 1 ); } /* search for all entries with surname of Jensen */ if (( msgid = ldap_search( ld, MY_SEARCHBASE, LDAP_SCOPE_SUBTREE, MY_FILTER, NULL, 0 )) < 0 ) { ldap_perror( ld, "ldap_search" ); return( 1 ); } /* Loop, polling for results until finished */ finished = 0; while ( !finished ) { /* * Poll for results. We call ldap_result with the "all" argument * set to LDAP_MSG_ONE. This causes ldap_result() to return exactly one * entry if at least one entry is available. This allows us to * display the entries as they are received. */ result = NULL; rc = ldap_result( ld, msgid, LDAP_MSG_ONE, &zerotime, &result ); switch ( rc ) { case -1: /* some error occurred */ ldap_perror( ld, "ldap_result" ); return( 1 ); case 0: /* Timeout was exceeded. No entries are ready for retrieval. */ if ( result != NULL ) { ldap_msgfree( result ); } break; default: /* * Either an entry is ready for retrieval, or all entries have * been retrieved. */ if (( e = ldap_first_entry( ld, result )) == NULL ) { /* All done */ finished = 1; if ( result != NULL ) { ldap_msgfree( result ); } continue; } /* for each entry print out name + all attrs and values */ num_entries++; if (( dn = ldap_get_dn( ld, e )) != NULL ) { printf( "dn: %s\n", dn ); ldap_memfree( dn ); } for ( a = ldap_first_attribute( ld, e, &ber ); a != NULL; a = ldap_next_attribute( ld, e, ber ) ) { if (( vals = ldap_get_values( ld, e, a )) != NULL ) { for ( i = 0; vals[ i ] != NULL; i++ ) { printf( "%s: %s\n", a, vals[ i ] ); } ldap_value_free( vals ); } ldap_memfree( a ); } if ( ber != NULL ) { ber_free( ber, 0 ); } printf( "\n" ); ldap_msgfree( result ); } /* Do other work here while you are waiting... */ do_other_work(); } /* All done. Print a summary. */ printf( "%d entries retrieved. I counted to %ld " "while I was waiting.\n", num_entries, global_counter ); ldap_unbind( ld ); return( 0 ); }
/* * handle the LDAP_RES_INTERMEDIATE response */ static int ldap_sync_search_intermediate( ldap_sync_t *ls, LDAPMessage *res, int *refreshDone ) { int rc; char *retoid = NULL; struct berval *retdata = NULL; BerElement *ber = NULL; ber_len_t len; ber_tag_t syncinfo_tag; struct berval cookie; int refreshDeletes = 0; BerVarray syncUUIDs = NULL; ldap_sync_refresh_t phase; #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\tgot LDAP_RES_INTERMEDIATE\n" ); #endif /* LDAP_SYNC_TRACE */ assert( ls != NULL ); assert( res != NULL ); assert( refreshDone != NULL ); *refreshDone = 0; rc = ldap_parse_intermediate( ls->ls_ld, res, &retoid, &retdata, NULL, 0 ); #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\t%sldap_parse_intermediate(%s) == %d\n", rc != LDAP_SUCCESS ? "!!! " : "", retoid == NULL ? "\"\"" : retoid, rc ); #endif /* LDAP_SYNC_TRACE */ /* parsing must be successful, and yield the OID * of the sync info intermediate response */ if ( rc != LDAP_SUCCESS ) { goto done; } rc = LDAP_OTHER; if ( retoid == NULL || strcmp( retoid, LDAP_SYNC_INFO ) != 0 ) { goto done; } /* init ber using the value in the response */ ber = ber_init( retdata ); if ( ber == NULL ) { goto done; } syncinfo_tag = ber_peek_tag( ber, &len ); switch ( syncinfo_tag ) { case LDAP_TAG_SYNC_NEW_COOKIE: if ( ber_scanf( ber, "m", &cookie ) == LBER_ERROR ) { goto done; } if ( cookie.bv_val != NULL ) { ber_bvreplace( &ls->ls_cookie, &cookie ); } #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\t\tgot cookie=%s\n", cookie.bv_val ? cookie.bv_val : "(null)" ); #endif /* LDAP_SYNC_TRACE */ break; case LDAP_TAG_SYNC_REFRESH_DELETE: case LDAP_TAG_SYNC_REFRESH_PRESENT: if ( syncinfo_tag == LDAP_TAG_SYNC_REFRESH_DELETE ) { #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\t\tgot refreshDelete\n" ); #endif /* LDAP_SYNC_TRACE */ switch ( ls->ls_refreshPhase ) { case LDAP_SYNC_CAPI_NONE: case LDAP_SYNC_CAPI_PRESENTS: ls->ls_refreshPhase = LDAP_SYNC_CAPI_DELETES; break; default: /* TODO: impossible; handle */ goto done; } } else { #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\t\tgot refreshPresent\n" ); #endif /* LDAP_SYNC_TRACE */ switch ( ls->ls_refreshPhase ) { case LDAP_SYNC_CAPI_NONE: ls->ls_refreshPhase = LDAP_SYNC_CAPI_PRESENTS; break; default: /* TODO: impossible; handle */ goto done; } } if ( ber_scanf( ber, "{" /*"}"*/ ) == LBER_ERROR ) { goto done; } if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) { if ( ber_scanf( ber, "m", &cookie ) == LBER_ERROR ) { goto done; } if ( cookie.bv_val != NULL ) { ber_bvreplace( &ls->ls_cookie, &cookie ); } #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\t\tgot cookie=%s\n", cookie.bv_val ? cookie.bv_val : "(null)" ); #endif /* LDAP_SYNC_TRACE */ } *refreshDone = 1; if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDONE ) { if ( ber_scanf( ber, "b", refreshDone ) == LBER_ERROR ) { goto done; } } #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\t\tgot refreshDone=%s\n", *refreshDone ? "TRUE" : "FALSE" ); #endif /* LDAP_SYNC_TRACE */ if ( ber_scanf( ber, /*"{"*/ "}" ) == LBER_ERROR ) { goto done; } if ( *refreshDone ) { ls->ls_refreshPhase = LDAP_SYNC_CAPI_DONE; } if ( ls->ls_intermediate ) { ls->ls_intermediate( ls, res, NULL, ls->ls_refreshPhase ); } break; case LDAP_TAG_SYNC_ID_SET: #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\t\tgot syncIdSet\n" ); #endif /* LDAP_SYNC_TRACE */ if ( ber_scanf( ber, "{" /*"}"*/ ) == LBER_ERROR ) { goto done; } if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) { if ( ber_scanf( ber, "m", &cookie ) == LBER_ERROR ) { goto done; } if ( cookie.bv_val != NULL ) { ber_bvreplace( &ls->ls_cookie, &cookie ); } #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\t\tgot cookie=%s\n", cookie.bv_val ? cookie.bv_val : "(null)" ); #endif /* LDAP_SYNC_TRACE */ } if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES ) { if ( ber_scanf( ber, "b", &refreshDeletes ) == LBER_ERROR ) { goto done; } } if ( ber_scanf( ber, /*"{"*/ "[W]}", &syncUUIDs ) == LBER_ERROR || syncUUIDs == NULL ) { goto done; } if ( refreshDeletes ) { phase = LDAP_SYNC_CAPI_DELETES_IDSET; } else { phase = LDAP_SYNC_CAPI_PRESENTS_IDSET; } /* FIXME: should touch ls->ls_refreshPhase? */ if ( ls->ls_intermediate ) { ls->ls_intermediate( ls, res, syncUUIDs, phase ); } ber_bvarray_free( syncUUIDs ); break; default: #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\t\tunknown tag!\n" ); #endif /* LDAP_SYNC_TRACE */ goto done; } rc = LDAP_SUCCESS; done:; if ( ber != NULL ) { ber_free( ber, 1 ); } if ( retoid != NULL ) { ldap_memfree( retoid ); } if ( retdata != NULL ) { ber_bvfree( retdata ); } return rc; }
/* * initialize the sync */ int ldap_sync_init( ldap_sync_t *ls, int mode ) { LDAPControl ctrl = { 0 }, *ctrls[ 2 ]; BerElement *ber = NULL; int rc; struct timeval tv = { 0 }, *tvp = NULL; LDAPMessage *res = NULL; #ifdef LDAP_SYNC_TRACE fprintf( stderr, "ldap_sync_init(%s)...\n", mode == LDAP_SYNC_REFRESH_AND_PERSIST ? "LDAP_SYNC_REFRESH_AND_PERSIST" : ( mode == LDAP_SYNC_REFRESH_ONLY ? "LDAP_SYNC_REFRESH_ONLY" : "unknown" ) ); #endif /* LDAP_SYNC_TRACE */ assert( ls != NULL ); assert( ls->ls_ld != NULL ); /* support both refreshOnly and refreshAndPersist */ switch ( mode ) { case LDAP_SYNC_REFRESH_AND_PERSIST: case LDAP_SYNC_REFRESH_ONLY: break; default: fprintf( stderr, "ldap_sync_init: unknown mode=%d\n", mode ); return LDAP_PARAM_ERROR; } /* check consistency of cookie and reloadHint at initial refresh */ if ( ls->ls_cookie.bv_val == NULL && ls->ls_reloadHint != 0 ) { fprintf( stderr, "ldap_sync_init: inconsistent cookie/rhint\n" ); return LDAP_PARAM_ERROR; } ctrls[ 0 ] = &ctrl; ctrls[ 1 ] = NULL; /* prepare the Sync Request control */ ber = ber_alloc_t( LBER_USE_DER ); #ifdef LDAP_SYNC_TRACE fprintf( stderr, "%sber_alloc_t() %s= NULL\n", ber == NULL ? "!!! " : "", ber == NULL ? "=" : "!" ); #endif /* LDAP_SYNC_TRACE */ if ( ber == NULL ) { rc = LDAP_NO_MEMORY; goto done; } ls->ls_refreshPhase = LDAP_SYNC_CAPI_NONE; if ( ls->ls_cookie.bv_val != NULL ) { ber_printf( ber, "{eOb}", mode, &ls->ls_cookie, ls->ls_reloadHint ); } else { ber_printf( ber, "{eb}", mode, ls->ls_reloadHint ); } rc = ber_flatten2( ber, &ctrl.ldctl_value, 0 ); #ifdef LDAP_SYNC_TRACE fprintf( stderr, "%sber_flatten2() == %d\n", rc ? "!!! " : "", rc ); #endif /* LDAP_SYNC_TRACE */ if ( rc < 0 ) { rc = LDAP_OTHER; goto done; } /* make the control critical, as we cannot proceed without */ ctrl.ldctl_oid = LDAP_CONTROL_SYNC; ctrl.ldctl_iscritical = 1; /* timelimit? */ if ( ls->ls_timelimit ) { tv.tv_sec = ls->ls_timelimit; tvp = &tv; } /* actually run the search */ rc = ldap_search_ext( ls->ls_ld, ls->ls_base, ls->ls_scope, ls->ls_filter, ls->ls_attrs, 0, ctrls, NULL, tvp, ls->ls_sizelimit, &ls->ls_msgid ); #ifdef LDAP_SYNC_TRACE fprintf( stderr, "%sldap_search_ext(\"%s\", %d, \"%s\") == %d\n", rc ? "!!! " : "", ls->ls_base, ls->ls_scope, ls->ls_filter, rc ); #endif /* LDAP_SYNC_TRACE */ if ( rc != LDAP_SUCCESS ) { goto done; } /* initial content/content update phase */ for ( ; ; ) { LDAPMessage *msg = NULL; /* NOTE: this very short timeout is just to let * ldap_result() yield long enough to get something */ tv.tv_sec = 0; tv.tv_usec = 100000; rc = ldap_result( ls->ls_ld, ls->ls_msgid, LDAP_MSG_RECEIVED, &tv, &res ); #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\t%sldap_result(%d) == %d\n", rc == -1 ? "!!! " : "", ls->ls_msgid, rc ); #endif /* LDAP_SYNC_TRACE */ switch ( rc ) { case 0: /* * timeout * * TODO: can do something else in the meanwhile) */ break; case -1: /* smtg bad! */ goto done; default: for ( msg = ldap_first_message( ls->ls_ld, res ); msg != NULL; msg = ldap_next_message( ls->ls_ld, msg ) ) { int refreshDone; switch ( ldap_msgtype( msg ) ) { case LDAP_RES_SEARCH_ENTRY: rc = ldap_sync_search_entry( ls, res ); break; case LDAP_RES_SEARCH_REFERENCE: rc = ldap_sync_search_reference( ls, res ); break; case LDAP_RES_SEARCH_RESULT: rc = ldap_sync_search_result( ls, res ); goto done_search; case LDAP_RES_INTERMEDIATE: rc = ldap_sync_search_intermediate( ls, res, &refreshDone ); if ( rc != LDAP_SUCCESS || refreshDone ) { goto done_search; } break; default: #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\tgot something unexpected...\n" ); #endif /* LDAP_SYNC_TRACE */ ldap_msgfree( res ); rc = LDAP_OTHER; goto done; } } ldap_msgfree( res ); res = NULL; break; } } done_search:; ldap_msgfree( res ); done:; if ( ber != NULL ) { ber_free( ber, 1 ); } return rc; }
static switch_status_t xml_ldap_directory_result(void *ldap_connection, xml_binding_t *binding, switch_xml_t *xml, int *off) { struct ldap_c *ldap = ldap_connection; switch_xml_t asdf = *xml; switch_xml_t param, variable, params = NULL, variables = NULL; int i = 0; int loff = *off; for (ldap->entry = ldap_first_entry(ldap->ld, ldap->msg); ldap->entry != NULL; ldap->entry = ldap_next_entry(ldap->ld, ldap->entry)) { ldap->key = ldap_first_attribute(ldap->ld, ldap->entry, &ldap->berkey); do { ldap->val = ldap_first_attribute(ldap->ld, ldap->entry, &ldap->berval); do { if (strstr(ldap->val, "value")) { if (strstr(ldap->val, ldap->key) && strcmp(ldap->val, ldap->key)) { if (!strcmp(ldap->key, "param")) { params = switch_xml_add_child_d(asdf, "params", loff++); } else if (!strcmp(ldap->key, "variable")) { variables = switch_xml_add_child_d(asdf, "variables", loff++); } ldap->keyvals = ldap_get_values(ldap->ld, ldap->entry, ldap->key); ldap->valvals = ldap_get_values(ldap->ld, ldap->entry, ldap->val); if (ldap->keyvals && ldap->valvals) { if (ldap_count_values(ldap->valvals) == ldap_count_values(ldap->keyvals)) { for (i = 0; ldap->keyvals[i] != NULL && ldap->valvals[i] != NULL; i++) { if (!strcmp(ldap->key, "param")) { param = switch_xml_add_child_d(params, "param", loff++); switch_xml_set_attr_d(param, "name", ldap->keyvals[i]); switch_xml_set_attr_d(param, "value", ldap->valvals[i]); } else if (!strcmp(ldap->key, "variable")) { variable = switch_xml_add_child_d(variables, "variable", loff++); switch_xml_set_attr_d(variable, "name", ldap->keyvals[i]); switch_xml_set_attr_d(variable, "value", ldap->valvals[i]); } } if (ldap->keyvals) { ldap_value_free(ldap->keyvals); } if (ldap->valvals) { ldap_value_free(ldap->valvals); } } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Seems the values %d and %d are not the same??\n", ldap_count_values(ldap->valvals), ldap_count_values(ldap->keyvals)); } } } } if (ldap->val) { ldap_memfree(ldap->val); } ldap->val = ldap_next_attribute(ldap->ld, ldap->entry, ldap->berval); } while (ldap->val != NULL); if (ldap->key) { ldap_memfree(ldap->key); } if (ldap->berval) { ber_free(ldap->berval, 0); } ldap->key = ldap_next_attribute(ldap->ld, ldap->entry, ldap->berkey); } while (ldap->key != NULL); if (ldap->berkey) { ber_free(ldap->berkey, 0); } } return SWITCH_STATUS_SUCCESS; }
/* returns the message id of the request or -1 if an error occurs */ int nsldapi_send_server_request( LDAP *ld, /* session handle */ BerElement *ber, /* message to send */ int msgid, /* ID of message to send */ LDAPRequest *parentreq, /* non-NULL for referred requests */ LDAPServer *srvlist, /* servers to connect to (NULL for default) */ LDAPConn *lc, /* connection to use (NULL for default) */ char *bindreqdn, /* non-NULL for bind requests */ int bind /* perform a bind after opening new conn.? */ ) { LDAPRequest *lr; int err; int incparent; /* did we bump parent's ref count? */ LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_send_server_request\n", 0, 0, 0 ); incparent = 0; LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK ); if ( lc == NULL ) { if ( srvlist == NULL ) { if ( ld->ld_defconn == NULL ) { LDAP_MUTEX_LOCK( ld, LDAP_OPTION_LOCK ); if ( bindreqdn == NULL && ( ld->ld_options & LDAP_BITOPT_RECONNECT ) != 0 ) { LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL ); ber_free( ber, 1 ); LDAP_MUTEX_UNLOCK( ld, LDAP_OPTION_LOCK ); LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK ); return( -1 ); } LDAP_MUTEX_UNLOCK( ld, LDAP_OPTION_LOCK ); if ( nsldapi_open_ldap_defconn( ld ) < 0 ) { ber_free( ber, 1 ); LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK ); return( -1 ); } } lc = ld->ld_defconn; } else { if (( lc = find_connection( ld, srvlist, 1 )) == NULL ) { if ( bind && (parentreq != NULL) ) { /* Remember the bind in the parent */ incparent = 1; ++parentreq->lr_outrefcnt; } lc = nsldapi_new_connection( ld, &srvlist, 0, 1, bind ); } free_servers( srvlist ); } } /* * the logic here is: * if * 1. no connections exists, * or * 2. if the connection is either not in the connected * or connecting state in an async io model * or * 3. the connection is notin a connected state with normal (non async io) */ if ( lc == NULL || ( (ld->ld_options & LDAP_BITOPT_ASYNC && lc->lconn_status != LDAP_CONNST_CONNECTING && lc->lconn_status != LDAP_CONNST_CONNECTED) || (!(ld->ld_options & LDAP_BITOPT_ASYNC ) && lc->lconn_status != LDAP_CONNST_CONNECTED) ) ) { ber_free( ber, 1 ); if ( lc != NULL ) { LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL ); } if ( incparent ) { /* Forget about the bind */ --parentreq->lr_outrefcnt; } LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK ); return( -1 ); } use_connection( ld, lc ); if (( lr = (LDAPRequest *)NSLDAPI_CALLOC( 1, sizeof( LDAPRequest ))) == NULL || ( bindreqdn != NULL && ( bindreqdn = nsldapi_strdup( bindreqdn )) == NULL )) { if ( lr != NULL ) { NSLDAPI_FREE( lr ); } LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL ); nsldapi_free_connection( ld, lc, NULL, NULL, 0, 0 ); ber_free( ber, 1 ); if ( incparent ) { /* Forget about the bind */ --parentreq->lr_outrefcnt; } LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK ); return( -1 ); } lr->lr_binddn = bindreqdn; lr->lr_msgid = msgid; lr->lr_status = LDAP_REQST_INPROGRESS; lr->lr_res_errno = LDAP_SUCCESS; /* optimistic */ lr->lr_ber = ber; lr->lr_conn = lc; if ( parentreq != NULL ) { /* sub-request */ if ( !incparent ) { /* Increment if we didn't do it before the bind */ ++parentreq->lr_outrefcnt; } lr->lr_origid = parentreq->lr_origid; lr->lr_parentcnt = parentreq->lr_parentcnt + 1; lr->lr_parent = parentreq; if ( parentreq->lr_child != NULL ) { lr->lr_sibling = parentreq->lr_child; } parentreq->lr_child = lr; } else { /* original request */ lr->lr_origid = lr->lr_msgid; } LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK ); if (( lr->lr_next = ld->ld_requests ) != NULL ) { lr->lr_next->lr_prev = lr; } ld->ld_requests = lr; lr->lr_prev = NULL; if (( err = nsldapi_ber_flush( ld, lc->lconn_sb, ber, 0, 1 )) != 0 ) { /* need to continue write later */ if (ld->ld_options & LDAP_BITOPT_ASYNC && err == -2 ) { lr->lr_status = LDAP_REQST_WRITING; nsldapi_iostatus_interest_write( ld, lc->lconn_sb ); } else { LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL ); nsldapi_free_request( ld, lr, 0 ); nsldapi_free_connection( ld, lc, NULL, NULL, 0, 0 ); LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK ); LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK ); return( -1 ); } } else { if ( parentreq == NULL ) { ber->ber_end = ber->ber_ptr; ber->ber_ptr = ber->ber_buf; } /* sent -- waiting for a response */ if (ld->ld_options & LDAP_BITOPT_ASYNC) { lc->lconn_status = LDAP_CONNST_CONNECTED; } nsldapi_iostatus_interest_read( ld, lc->lconn_sb ); } LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK ); LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK ); LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL ); return( msgid ); }
sInt32 CLDAPNode::GetSchemaMessage ( LDAP *inHost, int inSearchTO, LDAPMessage **outResultMsg ) { sInt32 siResult = eDSNoErr; bool bResultFound = false; int ldapMsgId = 0; LDAPMessage *result = nil; int ldapReturnCode = 0; char *sattrs[2] = {"subschemasubentry",NULL}; char *attrs[2] = {"objectclasses",NULL}; char *subschemaDN = nil; BerElement *ber; struct berval **bValues; char *pAttr = nil; try { //search for the specific LDAP record subschemasubentry at the rootDSE which contains //the "dn" of the subschema record // here is the call to the LDAP server asynchronously which requires // host handle, search base, search scope(LDAP_SCOPE_SUBTREE for all), search filter, // attribute list (NULL for all), return attrs values flag // Note: asynchronous call is made so that a MsgId can be used for future calls // This returns us the message ID which is used to query the server for the results if ( (ldapMsgId = ldap_search( inHost, "", LDAP_SCOPE_BASE, "(objectclass=*)", sattrs, 0) ) == -1 ) { bResultFound = false; } else { bResultFound = true; //retrieve the actual LDAP record data for use internally //useful only from the read-only perspective if (inSearchTO == 0) { ldapReturnCode = ldap_result(inHost, ldapMsgId, 0, NULL, &result); } else { struct timeval tv; tv.tv_sec = inSearchTO; tv.tv_usec = 0; ldapReturnCode = ldap_result(inHost, ldapMsgId, 0, &tv, &result); } } if ( (bResultFound) && ( ldapReturnCode == LDAP_RES_SEARCH_ENTRY ) ) { siResult = eDSNoErr; //get the subschemaDN here //parse the attributes in the result - should only be one ie. subschemasubentry for ( pAttr = ldap_first_attribute (inHost, result, &ber ); pAttr != NULL; pAttr = ldap_next_attribute(inHost, result, ber ) ) { if (( bValues = ldap_get_values_len (inHost, result, pAttr )) != NULL) { // should be only one value of the attribute if ( bValues[0] != NULL ) { subschemaDN = (char *) calloc(1, bValues[0]->bv_len + 1); strcpy(subschemaDN,bValues[0]->bv_val); } ldap_value_free_len(bValues); } // if bValues = ldap_get_values_len ... if (pAttr != nil) { ldap_memfree( pAttr ); } } // for ( loop over ldap_next_attribute ) if (ber != nil) { ber_free( ber, 0 ); } ldap_msgfree( result ); result = nil; } // if bResultFound and ldapReturnCode okay else if (ldapReturnCode == LDAP_TIMEOUT) { siResult = eDSServerTimeout; if ( result != nil ) { ldap_msgfree( result ); result = nil; } } else { siResult = eDSRecordNotFound; if ( result != nil ) { ldap_msgfree( result ); result = nil; } } if (subschemaDN != nil) { //here we call to get the actual subschema record //here is the call to the LDAP server asynchronously which requires // host handle, search base, search scope(LDAP_SCOPE_SUBTREE for all), search filter, // attribute list (NULL for all), return attrs values flag // Note: asynchronous call is made so that a MsgId can be used for future calls // This returns us the message ID which is used to query the server for the results if ( (ldapMsgId = ldap_search( inHost, subschemaDN, LDAP_SCOPE_BASE, "(objectclass=subSchema)", attrs, 0) ) == -1 ) { bResultFound = false; } else { bResultFound = true; //retrieve the actual LDAP record data for use internally //useful only from the read-only perspective //KW when write capability is added, we will need to re-read the result after a write if (inSearchTO == 0) { ldapReturnCode = ldap_result(inHost, ldapMsgId, 0, NULL, &result); } else { struct timeval tv; tv.tv_sec = inSearchTO; tv.tv_usec = 0; ldapReturnCode = ldap_result(inHost, ldapMsgId, 0, &tv, &result); } } free(subschemaDN); subschemaDN = nil; if ( (bResultFound) && ( ldapReturnCode == LDAP_RES_SEARCH_ENTRY ) ) { siResult = eDSNoErr; } // if bResultFound and ldapReturnCode okay else if (ldapReturnCode == LDAP_TIMEOUT) { siResult = eDSServerTimeout; if ( result != nil ) { ldap_msgfree( result ); result = nil; } } else { siResult = eDSRecordNotFound; if ( result != nil ) { ldap_msgfree( result ); result = nil; } } } } catch ( sInt32 err ) { siResult = err; } if (result != nil) { *outResultMsg = result; } return( siResult ); } // GetSchemaMessage
void AD::Enumerate(ADSearchFilter searchFilter) { LDAPMessage *search = NULL; LDAPMessage *entry = NULL; PWCHAR *value; PWCHAR attribute; berval *ber = NULL; DWORD i; DWORD j; // 20 strings should be enough? LPWSTR filters[20]; BerElement *berElement = NULL; // Fill our filters array (NULL-terminated) with search-specific filters. switch(searchFilter) { case AD_SEARCH_USER: SetFilter(L"(&(objectClass=user)(objectCategory=person))"); filters[0] = L"samAccountName"; filters[1] = L"cn"; filters[2] = L"homeDirectory"; filters[3] = L"memberOf"; filters[4] = NULL; break; case AD_SEARCH_GROUP: SetFilter(L"(&(objectCategory=group))"); filters[0] = L"samAccountName"; filters[1] = L"cn"; filters[2] = L"member"; filters[3] = NULL; break; case AD_SEARCH_MACHINE: SetFilter(L"(&(objectCategory=computer))"); filters[0] = L"samAccountName"; filters[1] = L"cn"; filters[2] = NULL; break; default: break; } if(ldap_search_s(ldap, (const PWCHAR)dn.c_str(), LDAP_SCOPE_SUBTREE, (PWCHAR)filter.c_str(), NULL, 0, &search) != LDAP_SUCCESS) { Util::Error(LdapGetLastError(), L"ldap_search"); Util::Notice(L"ret = %x\n", LdapGetLastError()); } switch(searchFilter) { case AD_SEARCH_USER: AddUsers(search); break; case AD_SEARCH_GROUP: AddGroups(search); break; case AD_SEARCH_MACHINE: AddServers(search); break; default: break; } ldap_msgfree(search); ber_free(berElement, 0); }
void CLDAPNode::GetSchema ( sLDAPContextData *inContext ) { sInt32 siResult = eDSNoErr; sLDAPConfigData *pConfig = nil; LDAPMessage *LDAPResult = nil; BerElement *ber; struct berval **bValues; char *pAttr = nil; sObjectClassSchema *aOCSchema = nil; bool bSkipToTag = true; char *lineEntry = nil; char *strtokContext = nil; LDAP *aHost = nil; if ( inContext != nil ) { pConfig = (sLDAPConfigData *)gConfigTable->GetItemData( inContext->fConfigTableIndex ); if (pConfig != nil) { aHost = LockSession(inContext); if ( (aHost != nil) && !(pConfig->bOCBuilt) ) //valid LDAP handle and schema not already built { //at this point we can make the call to the LDAP server to determine the object class schema //then after building the ObjectClassMap we can assign it to the pConfig->fObjectClassSchema //in either case we set the pConfig->bOCBuilt since we made the attempt siResult = GetSchemaMessage( aHost, pConfig->fSearchTimeout, &LDAPResult); if (siResult == eDSNoErr) { //parse the attributes in the LDAPResult - should only be one ie. objectclass for ( pAttr = ldap_first_attribute (aHost, LDAPResult, &ber ); pAttr != NULL; pAttr = ldap_next_attribute(aHost, LDAPResult, ber ) ) { if (( bValues = ldap_get_values_len (aHost, LDAPResult, pAttr )) != NULL) { ObjectClassMap *aOCClassMap = new(ObjectClassMap); // for each value of the attribute we need to parse and add as an entry to the objectclass schema map for (int i = 0; bValues[i] != NULL; i++ ) { aOCSchema = nil; if (lineEntry != nil) //delimiter chars will be overwritten by NULLs { free(lineEntry); lineEntry = nil; } //here we actually parse the values lineEntry = (char *)calloc(1,bValues[i]->bv_len+1); strcpy(lineEntry, bValues[i]->bv_val); char *aToken = nil; //find the objectclass name aToken = strtok_r(lineEntry,OCSEPCHARS, &strtokContext); while ( (aToken != nil) && (strcmp(aToken,"NAME") != 0) ) { aToken = strtok_r(NULL,OCSEPCHARS, &strtokContext); } if (aToken != nil) { aToken = strtok_r(NULL,OCSEPCHARS, &strtokContext); if (aToken != nil) { //now use the NAME to create an entry //first check if that NAME is already present - unlikely if (aOCClassMap->find(aToken) == aOCClassMap->end()) { aOCSchema = new(sObjectClassSchema); (*aOCClassMap)[aToken] = aOCSchema; } } } if (aOCSchema == nil) { continue; } if (aToken == nil) { continue; } //here we have the NAME - at least one of them //now check if there are any more NAME values bSkipToTag = true; while (bSkipToTag) { aToken = strtok_r(NULL,OCSEPCHARS, &strtokContext); if (aToken == nil) { break; } bSkipToTag = IsTokenNotATag(aToken); if (bSkipToTag) { aOCSchema->fOtherNames.insert(aOCSchema->fOtherNames.begin(),aToken); } } if (aToken == nil) { continue; } if (strcmp(aToken,"DESC") == 0) { bSkipToTag = true; while (bSkipToTag) { aToken = strtok_r(NULL,OCSEPCHARS, &strtokContext); if (aToken == nil) { break; } bSkipToTag = IsTokenNotATag(aToken); } if (aToken == nil) { continue; } } if (strcmp(aToken,"OBSOLETE") == 0) { bSkipToTag = true; while (bSkipToTag) { aToken = strtok_r(NULL,OCSEPCHARS, &strtokContext); if (aToken == nil) { break; } bSkipToTag = IsTokenNotATag(aToken); } if (aToken == nil) { continue; } } if (strcmp(aToken,"SUP") == 0) { aToken = strtok_r(NULL,OCSEPCHARS, &strtokContext); if (aToken == nil) { continue; } aOCSchema->fParentOCs.insert(aOCSchema->fParentOCs.begin(),aToken); //get the other SUP entries bSkipToTag = true; while (bSkipToTag) { aToken = strtok_r(NULL,OCSEPCHARS, &strtokContext); if (aToken == nil) { break; } bSkipToTag = IsTokenNotATag(aToken); if (bSkipToTag) { aOCSchema->fParentOCs.insert(aOCSchema->fParentOCs.begin(),aToken); } } if (aToken == nil) { continue; } } if (strcmp(aToken,"ABSTRACT") == 0) { aOCSchema->fType = 0; aToken = strtok_r(NULL,OCSEPCHARS, &strtokContext); if (aToken == nil) { continue; } } if (strcmp(aToken,"STRUCTURAL") == 0) { aOCSchema->fType = 1; aToken = strtok_r(NULL,OCSEPCHARS, &strtokContext); if (aToken == nil) { continue; } } if (strcmp(aToken,"AUXILIARY") == 0) { aOCSchema->fType = 2; aToken = strtok_r(NULL,OCSEPCHARS, &strtokContext); if (aToken == nil) { continue; } } if (strcmp(aToken,"MUST") == 0) { aToken = strtok_r(NULL,OCSEPCHARS, &strtokContext); if (aToken == nil) { continue; } aOCSchema->fRequiredAttrs.insert(aOCSchema->fRequiredAttrs.begin(),aToken); //get the other MUST entries bSkipToTag = true; while (bSkipToTag) { aToken = strtok_r(NULL,OCSEPCHARS, &strtokContext); if (aToken == nil) { break; } bSkipToTag = IsTokenNotATag(aToken); if (bSkipToTag) { aOCSchema->fRequiredAttrs.insert(aOCSchema->fRequiredAttrs.begin(),aToken); } } if (aToken == nil) { continue; } } if (strcmp(aToken,"MAY") == 0) { aToken = strtok_r(NULL,OCSEPCHARS, &strtokContext); if (aToken == nil) { continue; } aOCSchema->fAllowedAttrs.insert(aOCSchema->fAllowedAttrs.begin(),aToken); //get the other MAY entries bSkipToTag = true; while (bSkipToTag) { aToken = strtok_r(NULL,OCSEPCHARS, &strtokContext); if (aToken == nil) { break; } bSkipToTag = IsTokenNotATag(aToken); if (bSkipToTag) { aOCSchema->fAllowedAttrs.insert(aOCSchema->fAllowedAttrs.begin(),aToken); } } if (aToken == nil) { continue; } } } // for each bValues[i] if (lineEntry != nil) //delimiter chars will be overwritten by NULLs { free(lineEntry); lineEntry = nil; } ldap_value_free_len(bValues); pConfig->fObjectClassSchema = aOCClassMap; } // if bValues = ldap_get_values_len ... if (pAttr != nil) { ldap_memfree( pAttr ); } } // for ( loop over ldap_next_attribute ) if (ber != nil) { ber_free( ber, 0 ); } ldap_msgfree( LDAPResult ); } } pConfig->bOCBuilt = true; UnLockSession(inContext); } } } // GetSchema
static int ldap_set_keytab(krb5_context krbctx, const char *ldap_uri, const char *principal_name, krb5_principal princ, const char *binddn, const char *bindpw, const char *mech, const char *ca_cert_file, struct keys_container *keys) { LDAP *ld = NULL; BerElement *sctrl = NULL; struct berval *control = NULL; LDAPControl **srvctrl = NULL; int ret; int kvno, i; ber_tag_t rtag; ber_int_t *encs = NULL; int successful_keys = 0; /* cant' return more than nkeys, sometimes less */ encs = calloc(keys->nkeys + 1, sizeof(ber_int_t)); if (!encs) { fprintf(stderr, _("Out of Memory!\n")); return 0; } /* build password change control */ control = create_key_control(keys, principal_name); if (!control) { fprintf(stderr, _("Failed to create control!\n")); goto error_out; } ret = ipa_ldap_bind(ldap_uri, princ, binddn, bindpw, mech, ca_cert_file, &ld); if (ret != LDAP_SUCCESS) { fprintf(stderr, _("Failed to bind to server!\n")); goto error_out; } /* perform password change */ ret = ipa_ldap_extended_op(ld, KEYTAB_SET_OID, control, &srvctrl); if (ret != LDAP_SUCCESS) { fprintf(stderr, _("Failed to get keytab!\n")); goto error_out; } ber_bvfree(control); control = NULL; sctrl = get_control_data(srvctrl, KEYTAB_RET_OID); if (!sctrl) { fprintf(stderr, _("ber_init() failed, Invalid control ?!\n")); goto error_out; } /* Format of response * * KeytabGetRequest ::= SEQUENCE { * new_kvno Int32 * SEQUENCE OF KeyTypes * } * * * List of accepted enctypes * * KeyTypes ::= SEQUENCE { * enctype Int32 * } */ rtag = ber_scanf(sctrl, "{i{", &kvno); if (rtag == LBER_ERROR) { fprintf(stderr, _("ber_scanf() failed, unable to find kvno ?!\n")); goto error_out; } for (i = 0; i < keys->nkeys; i++) { ret = ber_scanf(sctrl, "{i}", &encs[i]); if (ret == LBER_ERROR) { char enc[79]; /* fit std terminal or truncate */ krb5_error_code krberr; krberr = krb5_enctype_to_string( keys->ksdata[i].enctype, enc, 79); if (krberr) { fprintf(stderr, _("Failed to retrieve " "encryption type type #%d\n"), keys->ksdata[i].enctype); } else { fprintf(stderr, _("Failed to retrieve " "encryption type %1$s (#%2$d)\n"), enc, keys->ksdata[i].enctype); } } else { successful_keys++; } } if (successful_keys == 0) { fprintf(stderr, _("Failed to retrieve any keys")); goto error_out; } ret = filter_keys(krbctx, keys, encs); if (ret == 0) goto error_out; ber_free(sctrl, 1); ldap_controls_free(srvctrl); ldap_unbind_ext(ld, NULL, NULL); free(encs); return kvno; error_out: if (sctrl) ber_free(sctrl, 1); if (srvctrl) ldap_controls_free(srvctrl); if (ld) ldap_unbind_ext(ld, NULL, NULL); if (control) ber_bvfree(control); free(encs); return -1; }
int ldap_create_sort_control_value( LDAP *ld, LDAPSortKey **keyList, struct berval *value ) { int i; BerElement *ber = NULL; ber_tag_t tag; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); if ( ld == NULL ) return LDAP_PARAM_ERROR; if ( keyList == NULL || value == NULL ) { ld->ld_errno = LDAP_PARAM_ERROR; return LDAP_PARAM_ERROR; } value->bv_val = NULL; value->bv_len = 0; ld->ld_errno = LDAP_SUCCESS; ber = ldap_alloc_ber_with_options( ld ); if ( ber == NULL) { ld->ld_errno = LDAP_NO_MEMORY; return ld->ld_errno; } tag = ber_printf( ber, "{" /*}*/ ); if ( tag == LBER_ERROR ) { goto error_return; } for ( i = 0; keyList[i] != NULL; i++ ) { tag = ber_printf( ber, "{s" /*}*/, keyList[i]->attributeType ); if ( tag == LBER_ERROR ) { goto error_return; } if ( keyList[i]->orderingRule != NULL ) { tag = ber_printf( ber, "ts", LDAP_MATCHRULE_IDENTIFIER, keyList[i]->orderingRule ); if ( tag == LBER_ERROR ) { goto error_return; } } if ( keyList[i]->reverseOrder ) { tag = ber_printf( ber, "tb", LDAP_REVERSEORDER_IDENTIFIER, keyList[i]->reverseOrder ); if ( tag == LBER_ERROR ) { goto error_return; } } tag = ber_printf( ber, /*{*/ "N}" ); if ( tag == LBER_ERROR ) { goto error_return; } } tag = ber_printf( ber, /*{*/ "N}" ); if ( tag == LBER_ERROR ) { goto error_return; } if ( ber_flatten2( ber, value, 1 ) == -1 ) { ld->ld_errno = LDAP_NO_MEMORY; } if ( 0 ) { error_return:; ld->ld_errno = LDAP_ENCODING_ERROR; } if ( ber != NULL ) { ber_free( ber, 1 ); } return ld->ld_errno; }
static BerElement * re_encode_request( LDAP *ld, BerElement *origber, ber_int_t msgid, int sref, LDAPURLDesc *srv, int *type ) { /* * XXX this routine knows way too much about how the lber library works! */ ber_int_t along; ber_tag_t tag; ber_tag_t rtag; ber_int_t ver; ber_int_t scope; int rc; BerElement tmpber, *ber; struct berval dn; Debug( LDAP_DEBUG_TRACE, "re_encode_request: new msgid %ld, new dn <%s>\n", (long) msgid, ( srv == NULL || srv->lud_dn == NULL) ? "NONE" : srv->lud_dn, 0 ); tmpber = *origber; /* * all LDAP requests are sequences that start with a message id. * For all except delete, this is followed by a sequence that is * tagged with the operation code. For delete, the provided DN * is not wrapped by a sequence. */ rtag = ber_scanf( &tmpber, "{it", /*}*/ &along, &tag ); if ( rtag == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; return( NULL ); } assert( tag != 0); if ( tag == LDAP_REQ_BIND ) { /* bind requests have a version number before the DN & other stuff */ rtag = ber_scanf( &tmpber, "{im" /*}*/, &ver, &dn ); } else if ( tag == LDAP_REQ_DELETE ) { /* delete requests don't have a DN wrapping sequence */ rtag = ber_scanf( &tmpber, "m", &dn ); } else if ( tag == LDAP_REQ_SEARCH ) { /* search requests need to be re-scope-ed */ rtag = ber_scanf( &tmpber, "{me" /*"}"*/, &dn, &scope ); if( srv->lud_scope != LDAP_SCOPE_DEFAULT ) { /* use the scope provided in reference */ scope = srv->lud_scope; } else if ( sref ) { /* use scope implied by previous operation * base -> base * one -> base * subtree -> subtree * subordinate -> subtree */ switch( scope ) { default: case LDAP_SCOPE_BASE: case LDAP_SCOPE_ONELEVEL: scope = LDAP_SCOPE_BASE; break; case LDAP_SCOPE_SUBTREE: case LDAP_SCOPE_SUBORDINATE: scope = LDAP_SCOPE_SUBTREE; break; } } } else { rtag = ber_scanf( &tmpber, "{m" /*}*/, &dn ); } if( rtag == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; return NULL; } /* restore character zero'd out by ber_scanf*/ dn.bv_val[dn.bv_len] = tmpber.ber_tag; if (( ber = ldap_alloc_ber_with_options( ld )) == NULL ) { return NULL; } if ( srv->lud_dn ) { ber_str2bv( srv->lud_dn, 0, 0, &dn ); } if ( tag == LDAP_REQ_BIND ) { rc = ber_printf( ber, "{it{iO" /*}}*/, msgid, tag, ver, &dn ); } else if ( tag == LDAP_REQ_DELETE ) { rc = ber_printf( ber, "{itON}", msgid, tag, &dn ); } else if ( tag == LDAP_REQ_SEARCH ) { rc = ber_printf( ber, "{it{Oe" /*}}*/, msgid, tag, &dn, scope ); } else { rc = ber_printf( ber, "{it{O" /*}}*/, msgid, tag, &dn ); } if ( rc == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return NULL; } if ( tag != LDAP_REQ_DELETE && ( ber_write(ber, tmpber.ber_ptr, ( tmpber.ber_end - tmpber.ber_ptr ), 0) != ( tmpber.ber_end - tmpber.ber_ptr ) || ber_printf( ber, /*{{*/ "N}N}" ) == -1 ) ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return NULL; } #ifdef LDAP_DEBUG if ( ldap_debug & LDAP_DEBUG_PACKETS ) { Debug( LDAP_DEBUG_ANY, "re_encode_request new request is:\n", 0, 0, 0 ); ber_log_dump( LDAP_DEBUG_BER, ldap_debug, ber, 0 ); } #endif /* LDAP_DEBUG */ *type = tag; /* return request type */ return ber; }
int ldap_parse_sortresponse_control( LDAP *ld, LDAPControl *ctrl, ber_int_t *returnCode, char **attribute ) { BerElement *ber; ber_tag_t tag, berTag; ber_len_t berLen; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); if (ld == NULL) { return LDAP_PARAM_ERROR; } if (ctrl == NULL) { ld->ld_errno = LDAP_PARAM_ERROR; return(ld->ld_errno); } if (attribute) { *attribute = NULL; } if ( strcmp(LDAP_CONTROL_SORTRESPONSE, ctrl->ldctl_oid) != 0 ) { /* Not sort result control */ ld->ld_errno = LDAP_CONTROL_NOT_FOUND; return(ld->ld_errno); } /* Create a BerElement from the berval returned in the control. */ ber = ber_init(&ctrl->ldctl_value); if (ber == NULL) { ld->ld_errno = LDAP_NO_MEMORY; return(ld->ld_errno); } /* Extract the result code from the control. */ tag = ber_scanf(ber, "{e" /*}*/, returnCode); if( tag == LBER_ERROR ) { ber_free(ber, 1); ld->ld_errno = LDAP_DECODING_ERROR; return(ld->ld_errno); } /* If caller wants the attribute name, and if it's present in the control, extract the attribute name which caused the error. */ if (attribute && (LDAP_ATTRTYPES_IDENTIFIER == ber_peek_tag(ber, &berLen))) { tag = ber_scanf(ber, "ta", &berTag, attribute); if (tag == LBER_ERROR ) { ber_free(ber, 1); ld->ld_errno = LDAP_DECODING_ERROR; return(ld->ld_errno); } } ber_free(ber,1); ld->ld_errno = LDAP_SUCCESS; return(ld->ld_errno); }
/* 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 ); } }
/* * handle the LDAP_RES_SEARCH_ENTRY response */ static int ldap_sync_search_entry( ldap_sync_t *ls, LDAPMessage *res ) { LDAPControl **ctrls = NULL; int rc = LDAP_OTHER, i; BerElement *ber = NULL; struct berval entryUUID = { 0 }, cookie = { 0 }; int state = -1; ber_len_t len; ldap_sync_refresh_t phase; #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\tgot LDAP_RES_SEARCH_ENTRY\n" ); #endif /* LDAP_SYNC_TRACE */ assert( ls != NULL ); assert( res != NULL ); phase = ls->ls_refreshPhase; /* OK */ /* extract: * - data * - entryUUID * * check that: * - Sync State Control is "add" */ /* the control MUST be present */ /* extract controls */ ldap_get_entry_controls( ls->ls_ld, res, &ctrls ); if ( ctrls == NULL ) { goto done; } /* lookup the sync state control */ for ( i = 0; ctrls[ i ] != NULL; i++ ) { if ( strcmp( ctrls[ i ]->ldctl_oid, LDAP_CONTROL_SYNC_STATE ) == 0 ) { break; } } /* control must be present; there might be other... */ if ( ctrls[ i ] == NULL ) { goto done; } /* extract data */ ber = ber_init( &ctrls[ i ]->ldctl_value ); if ( ber == NULL ) { goto done; } /* scan entryUUID in-place ("m") */ if ( ber_scanf( ber, "{em" /*"}"*/, &state, &entryUUID ) == LBER_ERROR || entryUUID.bv_len == 0 ) { goto done; } if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) { /* scan cookie in-place ("m") */ if ( ber_scanf( ber, /*"{"*/ "m}", &cookie ) == LBER_ERROR ) { goto done; } if ( cookie.bv_val != NULL ) { ber_bvreplace( &ls->ls_cookie, &cookie ); } #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\t\tgot cookie=%s\n", cookie.bv_val ? cookie.bv_val : "(null)" ); #endif /* LDAP_SYNC_TRACE */ } switch ( state ) { case LDAP_SYNC_PRESENT: case LDAP_SYNC_DELETE: case LDAP_SYNC_ADD: case LDAP_SYNC_MODIFY: /* NOTE: ldap_sync_refresh_t is defined * as the corresponding LDAP_SYNC_* * for the 4 above cases */ phase = state; #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\t\tgot syncState=%s\n", ldap_sync_state2str( state ) ); #endif /* LDAP_SYNC_TRACE */ break; default: #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\t\tgot unknown syncState=%d\n", state ); #endif /* LDAP_SYNC_TRACE */ goto done; } rc = ls->ls_search_entry ? ls->ls_search_entry( ls, res, &entryUUID, phase ) : LDAP_SUCCESS; done:; if ( ber != NULL ) { ber_free( ber, 1 ); } if ( ctrls != NULL ) { ldap_controls_free( ctrls ); } return rc; }
/* * Creates an LDAP search URL given a comma-separated list of attributes. * Returns a list of key=values separated by '\n' */ char * pref_get_ldap_attributes(char* host, char* base, char* filter, char* attrs, char** return_error) { char *value = NULL; LDAP* ld; int err, i; char *url; LDAPMessage *result; LDAPMessage *e; char *a; BerElement *ber; char **vals; ld = ldap_init(host, LDAP_PORT); if (!ld) return value; url = (char*) malloc(sizeof(char) * (strlen(host) + strlen(base) + strlen(filter) + strlen(attrs) + 20)); if (!url) return value; XP_SPRINTF(url, "ldap://%s/%s?%s?sub?%s", host, base, attrs, filter); err = ldap_url_search_s( ld, url, 0, &result ); XP_FREE(url); if (err != LDAP_SUCCESS) { *return_error = ldap_err2string(err); return value; } e = ldap_first_entry( ld, result ); if (e) { a = ldap_first_attribute( ld, e, &ber ); if (a) { int total_buf_size = 200; int remaining_buf_size = total_buf_size; value = (char*) malloc(sizeof(char*) * total_buf_size); if (!value) return NULL; value[0] = '\0'; for ( ; a != NULL; a = ldap_next_attribute( ld, e, ber )) { vals = ldap_get_values( ld, e, a ); if (vals && vals[0]) { remaining_buf_size -= (strlen(a) + strlen(vals[0]) + 2); if (remaining_buf_size < 1) { remaining_buf_size += 2 * total_buf_size; total_buf_size += 2 * total_buf_size; value = (char*) realloc(value, sizeof(char*) * total_buf_size); if (!value) return NULL; } strcat(value, "\n"); strcat(value, a); strcat(value, "="); strcat(value, vals[0]); ldap_value_free( vals ); } } ldap_memfree(a); } if (ber) ber_free(ber, 0); } ldap_msgfree(result); ldap_unbind(ld); return value; }
/* * handle the LDAP_RES_SEARCH_RESULT response */ static int ldap_sync_search_result( ldap_sync_t *ls, LDAPMessage *res ) { int err; char *matched = NULL, *msg = NULL; LDAPControl **ctrls = NULL; int rc; int refreshDeletes = -1; #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\tgot LDAP_RES_SEARCH_RESULT\n" ); #endif /* LDAP_SYNC_TRACE */ assert( ls != NULL ); assert( res != NULL ); /* should not happen in refreshAndPersist... */ rc = ldap_parse_result( ls->ls_ld, res, &err, &matched, &msg, NULL, &ctrls, 0 ); #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\tldap_parse_result(%d, \"%s\", \"%s\") == %d\n", err, matched ? matched : "", msg ? msg : "", rc ); #endif /* LDAP_SYNC_TRACE */ if ( rc == LDAP_SUCCESS ) { rc = err; } ls->ls_refreshPhase = LDAP_SYNC_CAPI_DONE; switch ( rc ) { case LDAP_SUCCESS: { int i; BerElement *ber = NULL; ber_len_t len; struct berval cookie = { 0 }; rc = LDAP_OTHER; /* deal with control; then fallthru to handler */ if ( ctrls == NULL ) { goto done; } /* lookup the sync state control */ for ( i = 0; ctrls[ i ] != NULL; i++ ) { if ( strcmp( ctrls[ i ]->ldctl_oid, LDAP_CONTROL_SYNC_DONE ) == 0 ) { break; } } /* control must be present; there might be other... */ if ( ctrls[ i ] == NULL ) { goto done; } /* extract data */ ber = ber_init( &ctrls[ i ]->ldctl_value ); if ( ber == NULL ) { goto done; } if ( ber_scanf( ber, "{" /*"}"*/) == LBER_ERROR ) { goto ber_done; } if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) { if ( ber_scanf( ber, "m", &cookie ) == LBER_ERROR ) { goto ber_done; } if ( cookie.bv_val != NULL ) { ber_bvreplace( &ls->ls_cookie, &cookie ); } #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\t\tgot cookie=%s\n", cookie.bv_val ? cookie.bv_val : "(null)" ); #endif /* LDAP_SYNC_TRACE */ } refreshDeletes = 0; if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES ) { if ( ber_scanf( ber, "b", &refreshDeletes ) == LBER_ERROR ) { goto ber_done; } if ( refreshDeletes ) { refreshDeletes = 1; } } if ( ber_scanf( ber, /*"{"*/ "}" ) != LBER_ERROR ) { rc = LDAP_SUCCESS; } ber_done:; ber_free( ber, 1 ); if ( rc != LDAP_SUCCESS ) { break; } #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\t\tgot refreshDeletes=%s\n", refreshDeletes ? "TRUE" : "FALSE" ); #endif /* LDAP_SYNC_TRACE */ /* FIXME: what should we do with the refreshDelete? */ switch ( refreshDeletes ) { case 0: ls->ls_refreshPhase = LDAP_SYNC_CAPI_PRESENTS; break; default: ls->ls_refreshPhase = LDAP_SYNC_CAPI_DELETES; break; } } /* fallthru */ case LDAP_SYNC_REFRESH_REQUIRED: /* TODO: check for Sync Done Control */ /* FIXME: perhaps the handler should be called * also in case of failure; we'll deal with this * later when implementing refreshOnly */ if ( ls->ls_search_result ) { err = ls->ls_search_result( ls, res, refreshDeletes ); } break; } done:; if ( matched != NULL ) { ldap_memfree( matched ); } if ( msg != NULL ) { ldap_memfree( msg ); } if ( ctrls != NULL ) { ldap_controls_free( ctrls ); } ls->ls_refreshPhase = LDAP_SYNC_CAPI_DONE; return rc; }