int ldap_append_referral( LDAP *ld, char **referralsp, char *s ) { int first; if ( *referralsp == NULL ) { first = 1; *referralsp = (char *)LDAP_MALLOC( strlen( s ) + LDAP_REF_STR_LEN + 1 ); } else { first = 0; *referralsp = (char *)LDAP_REALLOC( *referralsp, strlen( *referralsp ) + strlen( s ) + 2 ); } if ( *referralsp == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return( -1 ); } if ( first ) { strcpy( *referralsp, LDAP_REF_STR ); } else { strcat( *referralsp, "\n" ); } strcat( *referralsp, s ); return( 0 ); }
static char *safe_realloc( char **buf, int len ) { char *tmpbuf; tmpbuf = LDAP_REALLOC( *buf, len ); if (tmpbuf) { *buf=tmpbuf; } return tmpbuf; }
int ldap_domain2dn( LDAP_CONST char *domain_in, char **dnp) { char *domain, *s, *tok_r, *dn, *dntmp; size_t loc; assert( domain_in != NULL ); assert( dnp != NULL ); domain = LDAP_STRDUP(domain_in); if (domain == NULL) { return LDAP_NO_MEMORY; } dn = NULL; loc = 0; for (s = ldap_pvt_strtok(domain, ".", &tok_r); s != NULL; s = ldap_pvt_strtok(NULL, ".", &tok_r)) { size_t len = strlen(s); dntmp = (char *) LDAP_REALLOC(dn, loc + sizeof(",dc=") + len ); if (dntmp == NULL) { if (dn != NULL) LDAP_FREE(dn); LDAP_FREE(domain); return LDAP_NO_MEMORY; } dn = dntmp; if (loc > 0) { /* not first time. */ strcpy(dn + loc, ","); loc++; } strcpy(dn + loc, "dc="); loc += sizeof("dc=")-1; strcpy(dn + loc, s); loc += len; } LDAP_FREE(domain); *dnp = dn; return LDAP_SUCCESS; }
/* * 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_dn2domain( LDAP_CONST char *dn_in, char **domainp) { int i, j; char *ndomain; LDAPDN dn = NULL; LDAPRDN rdn = NULL; LDAPAVA *ava = NULL; struct berval domain = BER_BVNULL; static const struct berval DC = BER_BVC("DC"); static const struct berval DCOID = BER_BVC("0.9.2342.19200300.100.1.25"); assert( dn_in != NULL ); assert( domainp != NULL ); *domainp = NULL; if ( ldap_str2dn( dn_in, &dn, LDAP_DN_FORMAT_LDAP ) != LDAP_SUCCESS ) { return -2; } if( dn ) for( i=0; dn[i] != NULL; i++ ) { rdn = dn[i]; for( j=0; rdn[j] != NULL; j++ ) { ava = rdn[j]; if( rdn[j+1] == NULL && (ava->la_flags & LDAP_AVA_STRING) && ava->la_value.bv_len && ( ber_bvstrcasecmp( &ava->la_attr, &DC ) == 0 || ber_bvcmp( &ava->la_attr, &DCOID ) == 0 ) ) { if( domain.bv_len == 0 ) { ndomain = LDAP_REALLOC( domain.bv_val, ava->la_value.bv_len + 1); if( ndomain == NULL ) { goto return_error; } domain.bv_val = ndomain; AC_MEMCPY( domain.bv_val, ava->la_value.bv_val, ava->la_value.bv_len ); domain.bv_len = ava->la_value.bv_len; domain.bv_val[domain.bv_len] = '\0'; } else { ndomain = LDAP_REALLOC( domain.bv_val, ava->la_value.bv_len + sizeof(".") + domain.bv_len ); if( ndomain == NULL ) { goto return_error; } domain.bv_val = ndomain; domain.bv_val[domain.bv_len++] = '.'; AC_MEMCPY( &domain.bv_val[domain.bv_len], ava->la_value.bv_val, ava->la_value.bv_len ); domain.bv_len += ava->la_value.bv_len; domain.bv_val[domain.bv_len] = '\0'; } } else { domain.bv_len = 0; } } } if( domain.bv_len == 0 && domain.bv_val != NULL ) { LDAP_FREE( domain.bv_val ); domain.bv_val = NULL; } ldap_dnfree( dn ); *domainp = domain.bv_val; return 0; return_error: ldap_dnfree( dn ); LDAP_FREE( domain.bv_val ); return -1; }
/* * Lookup and return LDAP servers for domain (using the DNS * SRV record _ldap._tcp.domain). */ int ldap_domain2hostlist( LDAP_CONST char *domain, char **list ) { #ifdef HAVE_RES_QUERY #define DNSBUFSIZ (64*1024) char *request; char *hostlist = NULL; int rc, len, cur = 0; unsigned char reply[DNSBUFSIZ]; assert( domain != NULL ); assert( list != NULL ); if( *domain == '\0' ) { return LDAP_PARAM_ERROR; } request = LDAP_MALLOC(strlen(domain) + sizeof("_ldap._tcp.")); if (request == NULL) { return LDAP_NO_MEMORY; } sprintf(request, "_ldap._tcp.%s", domain); #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_lock(&ldap_int_resolv_mutex); #endif rc = LDAP_UNAVAILABLE; #ifdef NS_HFIXEDSZ /* Bind 8/9 interface */ len = res_query(request, ns_c_in, ns_t_srv, reply, sizeof(reply)); # ifndef T_SRV # define T_SRV ns_t_srv # endif #else /* Bind 4 interface */ # ifndef T_SRV # define T_SRV 33 # endif len = res_query(request, C_IN, T_SRV, reply, sizeof(reply)); #endif if (len >= 0) { unsigned char *p; char host[DNSBUFSIZ]; int status; u_short port; /* int priority, weight; */ /* Parse out query */ p = reply; #ifdef NS_HFIXEDSZ /* Bind 8/9 interface */ p += NS_HFIXEDSZ; #elif defined(HFIXEDSZ) /* Bind 4 interface w/ HFIXEDSZ */ p += HFIXEDSZ; #else /* Bind 4 interface w/o HFIXEDSZ */ p += sizeof(HEADER); #endif status = dn_expand(reply, reply + len, p, host, sizeof(host)); if (status < 0) { goto out; } p += status; p += 4; while (p < reply + len) { int type, class, ttl, size; status = dn_expand(reply, reply + len, p, host, sizeof(host)); if (status < 0) { goto out; } p += status; type = (p[0] << 8) | p[1]; p += 2; class = (p[0] << 8) | p[1]; p += 2; ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; p += 4; size = (p[0] << 8) | p[1]; p += 2; if (type == T_SRV) { int buflen; status = dn_expand(reply, reply + len, p + 6, host, sizeof(host)); if (status < 0) { goto out; } /* ignore priority and weight for now */ /* priority = (p[0] << 8) | p[1]; */ /* weight = (p[2] << 8) | p[3]; */ port = (p[4] << 8) | p[5]; if ( port == 0 || host[ 0 ] == '\0' ) { goto add_size; } buflen = strlen(host) + STRLENOF(":65355 "); hostlist = (char *) LDAP_REALLOC(hostlist, cur + buflen + 1); if (hostlist == NULL) { rc = LDAP_NO_MEMORY; goto out; } if (cur > 0) { /* not first time around */ hostlist[cur++] = ' '; } cur += sprintf(&hostlist[cur], "%s:%hd", host, port); } add_size:; p += size; } }
void * ldap_memrealloc( void* p, ber_len_t s ) { return LDAP_REALLOC( p, s ); }
int ldap_pvt_get_controls( BerElement *ber, LDAPControl ***ctrls ) { int nctrls; ber_tag_t tag; ber_len_t len; char *opaque; assert( ber != NULL ); if( ctrls == NULL ) { return LDAP_SUCCESS; } *ctrls = NULL; len = ber_pvt_ber_remaining( ber ); if( len == 0) { /* no controls */ return LDAP_SUCCESS; } if(( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) { if( tag == LBER_ERROR ) { /* decoding error */ return LDAP_DECODING_ERROR; } /* ignore unexpected input */ return LDAP_SUCCESS; } /* set through each element */ nctrls = 0; *ctrls = LDAP_MALLOC( 1 * sizeof(LDAPControl *) ); if( *ctrls == NULL ) { return LDAP_NO_MEMORY; } *ctrls[nctrls] = NULL; for( tag = ber_first_element( ber, &len, &opaque ); tag != LBER_ERROR; tag = ber_next_element( ber, &len, opaque ) ) { LDAPControl *tctrl; LDAPControl **tctrls; tctrl = LDAP_CALLOC( 1, sizeof(LDAPControl) ); /* allocate pointer space for current controls (nctrls) * + this control + extra NULL */ tctrls = (tctrl == NULL) ? NULL : LDAP_REALLOC(*ctrls, (nctrls+2) * sizeof(LDAPControl *)); if( tctrls == NULL ) { /* one of the above allocation failed */ if( tctrl != NULL ) { LDAP_FREE( tctrl ); } ldap_controls_free(*ctrls); *ctrls = NULL; return LDAP_NO_MEMORY; } tctrls[nctrls++] = tctrl; tctrls[nctrls] = NULL; tag = ber_scanf( ber, "{a" /*}*/, &tctrl->ldctl_oid ); if( tag == LBER_ERROR ) { *ctrls = NULL; ldap_controls_free( tctrls ); return LDAP_DECODING_ERROR; } tag = ber_peek_tag( ber, &len ); if( tag == LBER_BOOLEAN ) { ber_int_t crit; tag = ber_scanf( ber, "b", &crit ); tctrl->ldctl_iscritical = crit ? (char) 0 : (char) ~0; tag = ber_peek_tag( ber, &len ); } if( tag == LBER_OCTETSTRING ) { tag = ber_scanf( ber, "o", &tctrl->ldctl_value ); } else { BER_BVZERO( &tctrl->ldctl_value ); } *ctrls = tctrls; } return LDAP_SUCCESS; }
int ldap_parse_verify_credentials( LDAP *ld, LDAPMessage *res, int * code, char ** diagmsg, struct berval **cookie, struct berval **screds, LDAPControl ***ctrls) { int rc; char *retoid = NULL; struct berval *retdata = NULL; assert(ld != NULL); assert(LDAP_VALID(ld)); assert(res != NULL); assert(code != NULL); assert(diagmsg != NULL); rc = ldap_parse_extended_result(ld, res, &retoid, &retdata, 0); if( rc != LDAP_SUCCESS ) { ldap_perror(ld, "ldap_parse_verify_credentials"); return rc; } if (retdata) { ber_tag_t tag; ber_len_t len; ber_int_t i; BerElement * ber = ber_init(retdata); struct berval diagmsg_bv = BER_BVNULL; if (!ber) { rc = ld->ld_errno = LDAP_NO_MEMORY; goto done; } ber_scanf(ber, "{im" /*"}"*/, &i, &diagmsg_bv); if ( diagmsg != NULL ) { *diagmsg = LDAP_MALLOC( diagmsg_bv.bv_len + 1 ); AC_MEMCPY( *diagmsg, diagmsg_bv.bv_val, diagmsg_bv.bv_len ); (*diagmsg)[diagmsg_bv.bv_len] = '\0'; } *code = i; tag = ber_peek_tag(ber, &len); if (tag == LDAP_TAG_EXOP_VERIFY_CREDENTIALS_COOKIE) { ber_scanf(ber, "O", cookie); tag = ber_peek_tag(ber, &len); } if (tag == LDAP_TAG_EXOP_VERIFY_CREDENTIALS_SCREDS) { ber_scanf(ber, "O", screds); tag = ber_peek_tag(ber, &len); } if (tag == LDAP_TAG_EXOP_VERIFY_CREDENTIALS_CONTROLS) { int nctrls = 0; char * opaque; *ctrls = LDAP_MALLOC(1 * sizeof(LDAPControl *)); if (!*ctrls) { rc = LDAP_NO_MEMORY; goto done; } *ctrls[nctrls] = NULL; for(tag = ber_first_element(ber, &len, &opaque); tag != LBER_ERROR; tag = ber_next_element(ber, &len, opaque)) { LDAPControl *tctrl; LDAPControl **tctrls; tctrl = LDAP_CALLOC(1, sizeof(LDAPControl)); /* allocate pointer space for current controls (nctrls) * + this control + extra NULL */ tctrls = !tctrl ? NULL : LDAP_REALLOC(*ctrls, (nctrls+2) * sizeof(LDAPControl *)); if (!tctrls) { /* allocation failure */ if (tctrl) LDAP_FREE(tctrl); ldap_controls_free(*ctrls); *ctrls = NULL; rc = LDAP_NO_MEMORY; goto done; } tctrls[nctrls++] = tctrl; tctrls[nctrls] = NULL; tag = ber_scanf(ber, "{a" /*"}"*/, &tctrl->ldctl_oid); if (tag == LBER_ERROR) { *ctrls = NULL; ldap_controls_free(tctrls); rc = LDAP_DECODING_ERROR; goto done; } tag = ber_peek_tag(ber, &len); if (tag == LBER_BOOLEAN) { ber_int_t crit; tag = ber_scanf(ber, "b", &crit); tctrl->ldctl_iscritical = crit ? (char) 0 : (char) ~0; tag = ber_peek_tag(ber, &len); } if (tag == LBER_OCTETSTRING) { tag = ber_scanf( ber, "o", &tctrl->ldctl_value ); } else { BER_BVZERO( &tctrl->ldctl_value ); } *ctrls = tctrls; } } ber_free(ber, 1); } done: ber_bvfree(retdata); ber_memfree(retoid); return rc; }
/* Convert a structured DN from an X.509 certificate into an LDAPV3 DN. * x509_name must be raw DER. If func is non-NULL, the * constructed DN will use numeric OIDs to identify attributeTypes, * and the func() will be invoked to rewrite the DN with the given * flags. * * Otherwise the DN will use shortNames from a hardcoded table. */ int ldap_X509dn2bv( void *x509_name, struct berval *bv, LDAPDN_rewrite_func *func, unsigned flags ) { LDAPDN newDN; LDAPRDN newRDN; LDAPAVA *newAVA, *baseAVA; BerElementBuffer berbuf; BerElement *ber = (BerElement *)&berbuf; char oids[8192], *oidptr = oids, *oidbuf = NULL; void *ptrs[2048]; char *dn_end, *rdn_end; int i, navas, nrdns, rc = LDAP_SUCCESS; size_t dnsize, oidrem = sizeof(oids), oidsize = 0; int csize; ber_tag_t tag; ber_len_t len; oid_name *oidname; struct berval Oid, Val, oid2, *in = x509_name; assert( bv != NULL ); bv->bv_len = 0; bv->bv_val = NULL; navas = 0; nrdns = 0; /* A DN is a SEQUENCE of RDNs. An RDN is a SET of AVAs. * An AVA is a SEQUENCE of attr and value. * Count the number of AVAs and RDNs */ ber_init2( ber, in, LBER_USE_DER ); tag = ber_peek_tag( ber, &len ); if ( tag != LBER_SEQUENCE ) return LDAP_DECODING_ERROR; for ( tag = ber_first_element( ber, &len, &dn_end ); tag == LBER_SET; tag = ber_next_element( ber, &len, dn_end )) { nrdns++; for ( tag = ber_first_element( ber, &len, &rdn_end ); tag == LBER_SEQUENCE; tag = ber_next_element( ber, &len, rdn_end )) { tag = ber_skip_tag( ber, &len ); ber_skip_data( ber, len ); navas++; } } /* Allocate the DN/RDN/AVA stuff as a single block */ dnsize = sizeof(LDAPRDN) * (nrdns+1); dnsize += sizeof(LDAPAVA *) * (navas+nrdns); dnsize += sizeof(LDAPAVA) * navas; if (dnsize > sizeof(ptrs)) { newDN = (LDAPDN)LDAP_MALLOC( dnsize ); if ( newDN == NULL ) return LDAP_NO_MEMORY; } else { newDN = (LDAPDN)(char *)ptrs; } newDN[nrdns] = NULL; newRDN = (LDAPRDN)(newDN + nrdns+1); newAVA = (LDAPAVA *)(newRDN + navas + nrdns); baseAVA = newAVA; /* Rewind and start extracting */ ber_rewind( ber ); tag = ber_first_element( ber, &len, &dn_end ); for ( i = nrdns - 1; i >= 0; i-- ) { newDN[i] = newRDN; for ( tag = ber_first_element( ber, &len, &rdn_end ); tag == LBER_SEQUENCE; tag = ber_next_element( ber, &len, rdn_end )) { *newRDN++ = newAVA; tag = ber_skip_tag( ber, &len ); tag = ber_get_stringbv( ber, &Oid, LBER_BV_NOTERM ); if ( tag != LBER_TAG_OID ) { rc = LDAP_DECODING_ERROR; goto nomem; } oid2.bv_val = oidptr; oid2.bv_len = oidrem; if ( ber_decode_oid( &Oid, &oid2 ) < 0 ) { rc = LDAP_DECODING_ERROR; goto nomem; } oidname = find_oid( &oid2 ); if ( !oidname ) { newAVA->la_attr = oid2; oidptr += oid2.bv_len + 1; oidrem -= oid2.bv_len + 1; /* Running out of OID buffer space? */ if (oidrem < 128) { if ( oidsize == 0 ) { oidsize = sizeof(oids) * 2; oidrem = oidsize; oidbuf = LDAP_MALLOC( oidsize ); if ( oidbuf == NULL ) goto nomem; oidptr = oidbuf; } else { char *old = oidbuf; oidbuf = LDAP_REALLOC( oidbuf, oidsize*2 ); if ( oidbuf == NULL ) goto nomem; /* Buffer moved! Fix AVA pointers */ if ( old != oidbuf ) { LDAPAVA *a; long dif = oidbuf - old; for (a=baseAVA; a<=newAVA; a++){ if (a->la_attr.bv_val >= old && a->la_attr.bv_val <= (old + oidsize)) a->la_attr.bv_val += dif; } } oidptr = oidbuf + oidsize - oidrem; oidrem += oidsize; oidsize *= 2; } } } else { if ( func ) { newAVA->la_attr = oidname->oid; } else { newAVA->la_attr = oidname->name; } } newAVA->la_private = NULL; newAVA->la_flags = LDAP_AVA_STRING; tag = ber_get_stringbv( ber, &Val, LBER_BV_NOTERM ); switch(tag) { case LBER_TAG_UNIVERSAL: /* This uses 32-bit ISO 10646-1 */ csize = 4; goto to_utf8; case LBER_TAG_BMP: /* This uses 16-bit ISO 10646-1 */ csize = 2; goto to_utf8; case LBER_TAG_TELETEX: /* This uses 8-bit, assume ISO 8859-1 */ csize = 1; to_utf8: rc = ldap_ucs_to_utf8s( &Val, csize, &newAVA->la_value ); newAVA->la_flags |= LDAP_AVA_NONPRINTABLE; allocd: newAVA->la_flags |= LDAP_AVA_FREE_VALUE; if (rc != LDAP_SUCCESS) goto nomem; break; case LBER_TAG_UTF8: newAVA->la_flags |= LDAP_AVA_NONPRINTABLE; /* This is already in UTF-8 encoding */ case LBER_TAG_IA5: case LBER_TAG_PRINTABLE: /* These are always 7-bit strings */ newAVA->la_value = Val; break; case LBER_BITSTRING: /* X.690 bitString value converted to RFC4517 Bit String */ rc = der_to_ldap_BitString( &Val, &newAVA->la_value ); goto allocd; default: /* Not a string type at all */ newAVA->la_flags = 0; newAVA->la_value = Val; break; } newAVA++; } *newRDN++ = NULL; tag = ber_next_element( ber, &len, dn_end ); } if ( func ) { rc = func( newDN, flags, NULL ); if ( rc != LDAP_SUCCESS ) goto nomem; } rc = ldap_dn2bv_x( newDN, bv, LDAP_DN_FORMAT_LDAPV3, NULL ); nomem: for (;baseAVA < newAVA; baseAVA++) { if (baseAVA->la_flags & LDAP_AVA_FREE_ATTR) LDAP_FREE( baseAVA->la_attr.bv_val ); if (baseAVA->la_flags & LDAP_AVA_FREE_VALUE) LDAP_FREE( baseAVA->la_value.bv_val ); } if ( oidsize != 0 ) LDAP_FREE( oidbuf ); if ( newDN != (LDAPDN)(char *) ptrs ) LDAP_FREE( newDN ); return rc; }
/* * Lookup and return LDAP servers for domain (using the DNS * SRV record _ldap._tcp.domain). */ int ldap_domain2hostlist( LDAP_CONST char *domain, char **list ) { #ifdef HAVE_RES_QUERY char *request; char *hostlist = NULL; srv_record *hostent_head=NULL; int i, j; int rc, len, cur = 0; unsigned char reply[DNSBUFSIZ]; int hostent_count=0; assert( domain != NULL ); assert( list != NULL ); if( *domain == '\0' ) { return LDAP_PARAM_ERROR; } request = LDAP_MALLOC(strlen(domain) + sizeof("_ldap._tcp.")); if (request == NULL) { return LDAP_NO_MEMORY; } sprintf(request, "_ldap._tcp.%s", domain); LDAP_MUTEX_LOCK(&ldap_int_resolv_mutex); rc = LDAP_UNAVAILABLE; #ifdef NS_HFIXEDSZ /* Bind 8/9 interface */ len = res_query(request, ns_c_in, ns_t_srv, reply, sizeof(reply)); # ifndef T_SRV # define T_SRV ns_t_srv # endif #else /* Bind 4 interface */ # ifndef T_SRV # define T_SRV 33 # endif len = res_query(request, C_IN, T_SRV, reply, sizeof(reply)); #endif if (len >= 0) { unsigned char *p; char host[DNSBUFSIZ]; int status; u_short port, priority, weight; /* Parse out query */ p = reply; #ifdef NS_HFIXEDSZ /* Bind 8/9 interface */ p += NS_HFIXEDSZ; #elif defined(HFIXEDSZ) /* Bind 4 interface w/ HFIXEDSZ */ p += HFIXEDSZ; #else /* Bind 4 interface w/o HFIXEDSZ */ p += sizeof(HEADER); #endif status = dn_expand(reply, reply + len, p, host, sizeof(host)); if (status < 0) { goto out; } p += status; p += 4; while (p < reply + len) { int type, size; int class ALLOW_UNUSED, ttl ALLOW_UNUSED; status = dn_expand(reply, reply + len, p, host, sizeof(host)); if (status < 0) { goto out; } p += status; type = (p[0] << 8) | p[1]; p += 2; class = (p[0] << 8) | p[1]; p += 2; ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; p += 4; size = (p[0] << 8) | p[1]; p += 2; if (type == T_SRV) { status = dn_expand(reply, reply + len, p + 6, host, sizeof(host)); if (status < 0) { goto out; } /* Get priority weight and port */ priority = (p[0] << 8) | p[1]; weight = (p[2] << 8) | p[3]; port = (p[4] << 8) | p[5]; if ( port == 0 || host[ 0 ] == '\0' ) { goto add_size; } hostent_head = (srv_record *) LDAP_REALLOC(hostent_head, (hostent_count+1)*(sizeof(srv_record))); if(hostent_head==NULL){ rc=LDAP_NO_MEMORY; goto out; } hostent_head[hostent_count].priority=priority; hostent_head[hostent_count].weight=weight; hostent_head[hostent_count].port=port; strncpy(hostent_head[hostent_count].hostname, host, MAXHOST-1); hostent_head[hostent_count].hostname[MAXHOST-1] = '\0'; hostent_count++; } add_size:; p += size; } if (!hostent_head) goto out; qsort(hostent_head, hostent_count, sizeof(srv_record), srv_cmp); if (!srv_seed) srv_srand(time(0L)); /* shuffle records of same priority */ j = 0; priority = hostent_head[0].priority; for (i=1; i<hostent_count; i++) { if (hostent_head[i].priority != priority) { priority = hostent_head[i].priority; if (i-j > 1) srv_shuffle(hostent_head+j, i-j); j = i; } } if (i-j > 1) srv_shuffle(hostent_head+j, i-j); for(i=0; i<hostent_count; i++){ int buflen; buflen = strlen(hostent_head[i].hostname) + STRLENOF(":65535 "); hostlist = (char *) LDAP_REALLOC(hostlist, cur+buflen+1); if (hostlist == NULL) { rc = LDAP_NO_MEMORY; goto out; } if(cur>0){ hostlist[cur++]=' '; } cur += sprintf(&hostlist[cur], "%s:%hu", hostent_head[i].hostname, hostent_head[i].port); } }
static int do_abandon( LDAP *ld, ber_int_t origid, ber_int_t msgid, LDAPControl **sctrls, LDAPControl **cctrls) { BerElement *ber; int i, err, sendabandon; ber_int_t *old_abandon; Sockbuf *sb; LDAPRequest *lr; #ifdef NEW_LOGGING LDAP_LOG ( OPERATION, ARGS, "do_abandon %d, msgid %d\n", origid, msgid, 0 ); #else Debug( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n", origid, msgid, 0 ); #endif sendabandon = 1; /* find the request that we are abandoning */ for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) { if ( lr->lr_msgid == msgid ) { /* this message */ break; } if ( lr->lr_origid == msgid ) {/* child: abandon it */ (void) do_abandon( ld, msgid, lr->lr_msgid, sctrls, cctrls ); } } if ( lr != NULL ) { if ( origid == msgid && lr->lr_parent != NULL ) { /* don't let caller abandon child requests! */ ld->ld_errno = LDAP_PARAM_ERROR; return( LDAP_PARAM_ERROR ); } if ( lr->lr_status != LDAP_REQST_INPROGRESS ) { /* no need to send abandon message */ sendabandon = 0; } } if ( ldap_msgdelete( ld, msgid ) == 0 ) { ld->ld_errno = LDAP_SUCCESS; return LDAP_SUCCESS; } err = 0; if ( sendabandon ) { if( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) { /* not connected */ err = -1; ld->ld_errno = LDAP_SERVER_DOWN; } else if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { /* BER element alocation failed */ err = -1; ld->ld_errno = LDAP_NO_MEMORY; } else { #ifdef LDAP_CONNECTIONLESS if ( LDAP_IS_UDP(ld) ) { err = ber_write( ber, ld->ld_options.ldo_peer, sizeof(struct sockaddr), 0); } if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == LDAP_VERSION2) { char *dn = ld->ld_options.ldo_cldapdn; if (!dn) dn = ""; err = ber_printf( ber, "{isti", /* '}' */ ++ld->ld_msgid, dn, LDAP_REQ_ABANDON, msgid ); } else #endif { /* create a message to send */ err = ber_printf( ber, "{iti", /* '}' */ ++ld->ld_msgid, LDAP_REQ_ABANDON, msgid ); } if( err == -1 ) { /* encoding error */ ld->ld_errno = LDAP_ENCODING_ERROR; } else { /* Put Server Controls */ if ( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) { err = -1; } else { /* close '{' */ err = ber_printf( ber, /*{*/ "N}" ); if( err == -1 ) { /* encoding error */ ld->ld_errno = LDAP_ENCODING_ERROR; } } } if ( err == -1 ) { ber_free( ber, 1 ); } else { /* send the message */ if ( lr != NULL ) { sb = lr->lr_conn->lconn_sb; } else { sb = ld->ld_sb; } if ( ber_flush( sb, ber, 1 ) != 0 ) { ld->ld_errno = LDAP_SERVER_DOWN; err = -1; } else { err = 0; } } } } if ( lr != NULL ) { if ( sendabandon || lr->lr_status == LDAP_REQST_WRITING ) { ldap_free_connection( ld, lr->lr_conn, 0, 1 ); } if ( origid == msgid ) { ldap_free_request( ld, lr ); } } i = 0; if ( ld->ld_abandoned != NULL ) { for ( ; ld->ld_abandoned[i] != -1; i++ ) ; /* NULL */ } old_abandon = ld->ld_abandoned; ld->ld_abandoned = (ber_int_t *) LDAP_REALLOC( (char *) ld->ld_abandoned, (i + 2) * sizeof(ber_int_t) ); if ( ld->ld_abandoned == NULL ) { ld->ld_abandoned = old_abandon; ld->ld_errno = LDAP_NO_MEMORY; return( ld->ld_errno ); } ld->ld_abandoned[i] = msgid; ld->ld_abandoned[i + 1] = -1; if ( err != -1 ) { ld->ld_errno = LDAP_SUCCESS; } return( ld->ld_errno ); }