Пример #1
0
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 );
}
Пример #2
0
static char *safe_realloc( char **buf, int len )
{
	char *tmpbuf;
	tmpbuf = LDAP_REALLOC( *buf, len );
	if (tmpbuf) {
		*buf=tmpbuf;
	} 
	return tmpbuf;
}
Пример #3
0
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;
}
Пример #4
0
/*
 * Chase v3 referrals
 *
 * Parameters:
 *  (IN) ld = LDAP connection handle
 *  (IN) lr = LDAP Request structure
 *  (IN) refs = array of pointers to referral strings that we will chase
 *              The array will be free'd by this function when no longer needed
 *  (IN) sref != 0 if following search reference
 *  (OUT) errstrp = Place to return a string of referrals which could not be followed
 *  (OUT) hadrefp = 1 if sucessfully followed referral
 *
 * Return value - number of referrals followed
 *
 * Protected by res_mutex, conn_mutex and req_mutex	(try_read1msg)
 */
int
ldap_chase_v3referrals( LDAP *ld, LDAPRequest *lr, char **refs, int sref, char **errstrp, int *hadrefp )
{
	char		*unfollowed;
	int		 unfollowedcnt = 0;
	LDAPRequest	*origreq;
	LDAPURLDesc	*srv = NULL;
	BerElement	*ber;
	char		**refarray = NULL;
	LDAPConn	*lc;
	int			 rc, count, i, j, id;
	LDAPreqinfo  rinfo;
	LDAP_NEXTREF_PROC	*nextref_proc = ld->ld_nextref_proc ? ld->ld_nextref_proc : ldap_int_nextref;

	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex );
	Debug( LDAP_DEBUG_TRACE, "ldap_chase_v3referrals\n", 0, 0, 0 );

	ld->ld_errno = LDAP_SUCCESS;	/* optimistic */
	*hadrefp = 0;

	unfollowed = NULL;
	rc = count = 0;

	/* If no referrals in array, return */
	if ( (refs == NULL) || ( (refs)[0] == NULL) ) {
		rc = 0;
		goto done;
	}

	/* Check for hop limit exceeded */
	if ( lr->lr_parentcnt >= ld->ld_refhoplimit ) {
		Debug( LDAP_DEBUG_ANY,
		    "more than %d referral hops (dropping)\n", ld->ld_refhoplimit, 0, 0 );
		ld->ld_errno = LDAP_REFERRAL_LIMIT_EXCEEDED;
		rc = -1;
		goto done;
	}

	/* find original request */
	for ( origreq = lr;
		origreq->lr_parent != NULL;
		origreq = origreq->lr_parent )
	{
		/* empty */ ;
	}

	refarray = refs;
	refs = NULL;

	/* parse out & follow referrals */
	/* NOTE: if nextref_proc == ldap_int_nextref, params is ignored */
	i = -1;
	for ( nextref_proc( ld, &refarray, &i, ld->ld_nextref_params );
			i != -1;
			nextref_proc( ld, &refarray, &i, ld->ld_nextref_params ) )
	{

		/* Parse the referral URL */
		rc = ldap_url_parse_ext( refarray[i], &srv, LDAP_PVT_URL_PARSE_NOEMPTY_DN );
		if ( rc != LDAP_URL_SUCCESS ) {
			/* ldap_url_parse_ext() returns LDAP_URL_* errors
			 * which do not map on API errors */
			ld->ld_errno = LDAP_PARAM_ERROR;
			rc = -1;
			goto done;
		}

		if( srv->lud_crit_exts ) {
			int ok = 0;
#ifdef HAVE_TLS
			/* If StartTLS is the only critical ext, OK. */
			if ( find_tls_ext( srv ) == 2 && srv->lud_crit_exts == 1 )
				ok = 1;
#endif
			if ( !ok ) {
				/* we do not support any other extensions */
				ld->ld_errno = LDAP_NOT_SUPPORTED;
				rc = -1;
				goto done;
			}
		}

		/* check connection for re-bind in progress */
		if (( lc = find_connection( ld, srv, 1 )) != NULL ) {
			/* See if we've already requested this DN with this conn */
			LDAPRequest *lp;
			int looped = 0;
			ber_len_t len = srv->lud_dn ? strlen( srv->lud_dn ) : 0;
			for ( lp = origreq; lp; ) {
				if ( lp->lr_conn == lc
					&& len == lp->lr_dn.bv_len
					&& len
					&& strncmp( srv->lud_dn, lp->lr_dn.bv_val, len ) == 0 )
				{
					looped = 1;
					break;
				}
				if ( lp == origreq ) {
					lp = lp->lr_child;
				} else {
					lp = lp->lr_refnext;
				}
			}
			if ( looped ) {
				ldap_free_urllist( srv );
				srv = NULL;
				ld->ld_errno = LDAP_CLIENT_LOOP;
				rc = -1;
				continue;
			}

			if ( lc->lconn_rebind_inprogress ) {
				/* We are already chasing a referral or search reference and a
				 * bind on that connection is in progress.  We must queue
				 * referrals on that connection, so we don't get a request
				 * going out before the bind operation completes. This happens
				 * if two search references come in one behind the other
				 * for the same server with different contexts.
				 */
				Debug( LDAP_DEBUG_TRACE,
					"ldap_chase_v3referrals: queue referral \"%s\"\n",
					refarray[i], 0, 0);
				if( lc->lconn_rebind_queue == NULL ) {
					/* Create a referral list */
					lc->lconn_rebind_queue =
						(char ***) LDAP_MALLOC( sizeof(void *) * 2);

					if( lc->lconn_rebind_queue == NULL) {
						ld->ld_errno = LDAP_NO_MEMORY;
						rc = -1;
						goto done;
					}

					lc->lconn_rebind_queue[0] = refarray;
					lc->lconn_rebind_queue[1] = NULL;
					refarray = NULL;

				} else {
					/* Count how many referral arrays we already have */
					for( j = 0; lc->lconn_rebind_queue[j] != NULL; j++) {
						/* empty */;
					}

					/* Add the new referral to the list */
					lc->lconn_rebind_queue = (char ***) LDAP_REALLOC(
						lc->lconn_rebind_queue, sizeof(void *) * (j + 2));

					if( lc->lconn_rebind_queue == NULL ) {
						ld->ld_errno = LDAP_NO_MEMORY;
						rc = -1;
						goto done;
					}
					lc->lconn_rebind_queue[j] = refarray;
					lc->lconn_rebind_queue[j+1] = NULL;
					refarray = NULL;
				}

				/* We have queued the referral/reference, now just return */
				rc = 0;
				*hadrefp = 1;
				count = 1; /* Pretend we already followed referral */
				goto done;
			}
		} 
		/* Re-encode the request with the new starting point of the search.
		 * Note: In the future we also need to replace the filter if one
		 * was provided with the search reference
		 */

		/* For references we don't want old dn if new dn empty */
		if ( sref && srv->lud_dn == NULL ) {
			srv->lud_dn = LDAP_STRDUP( "" );
		}

		LDAP_NEXT_MSGID( ld, id );
		ber = re_encode_request( ld, origreq->lr_ber, id,
			sref, srv, &rinfo.ri_request );

		if( ber == NULL ) {
			ld->ld_errno = LDAP_ENCODING_ERROR;
			rc = -1;
			goto done;
		}

		Debug( LDAP_DEBUG_TRACE,
			"ldap_chase_v3referral: msgid %d, url \"%s\"\n",
			lr->lr_msgid, refarray[i], 0);

		/* Send the new request to the server - may require a bind */
		rinfo.ri_msgid = origreq->lr_origid;
		rinfo.ri_url = refarray[i];
		rc = ldap_send_server_request( ld, ber, id,
			origreq, &srv, NULL, &rinfo, 0, 1 );
		if ( rc < 0 ) {
			/* Failure, try next referral in the list */
			Debug( LDAP_DEBUG_ANY, "Unable to chase referral \"%s\" (%d: %s)\n", 
				refarray[i], ld->ld_errno, ldap_err2string( ld->ld_errno ) );
			unfollowedcnt += ldap_append_referral( ld, &unfollowed, refarray[i] );
			ldap_free_urllist( srv );
			srv = NULL;
			ld->ld_errno = LDAP_REFERRAL;
		} else {
			/* Success, no need to try this referral list further */
			rc = 0;
			++count;
			*hadrefp = 1;

			/* check if there is a queue of referrals that came in during bind */
			if ( lc == NULL) {
				lc = find_connection( ld, srv, 1 );
				if ( lc == NULL ) {
					ld->ld_errno = LDAP_OPERATIONS_ERROR;
					rc = -1;
					LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
					goto done;
				}
			}

			if ( lc->lconn_rebind_queue != NULL ) {
				/* Release resources of previous list */
				LDAP_VFREE( refarray );
				refarray = NULL;
				ldap_free_urllist( srv );
				srv = NULL;

				/* Pull entries off end of queue so list always null terminated */
				for( j = 0; lc->lconn_rebind_queue[j] != NULL; j++ )
					;
				refarray = lc->lconn_rebind_queue[j - 1];
				lc->lconn_rebind_queue[j-1] = NULL;
				/* we pulled off last entry from queue, free queue */
				if ( j == 1 ) {
					LDAP_FREE( lc->lconn_rebind_queue );
					lc->lconn_rebind_queue = NULL;
				}
				/* restart the loop the with new referral list */
				i = -1;
				continue;
			}
			break; /* referral followed, break out of for loop */
		}
	} /* end for loop */
done:
	LDAP_VFREE( refarray );
	ldap_free_urllist( srv );
	LDAP_FREE( *errstrp );
	
	if( rc == 0 ) {
		*errstrp = NULL;
		LDAP_FREE( unfollowed );
		return count;
	} else {
		*errstrp = unfollowed;
		return rc;
	}
}
Пример #5
0
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;
}
Пример #6
0
/*
 * 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;
	}
    }
Пример #7
0
void *
ldap_memrealloc( void* p, ber_len_t s )
{
	return LDAP_REALLOC( p, s );
}
Пример #8
0
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;
}
Пример #9
0
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;
}
Пример #10
0
/* 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;
}
Пример #11
0
/*
 * 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);
    }
    }
Пример #12
0
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 );
}