Пример #1
0
static void
constraint_free( constraint *cp, int freeme )
{
	if (cp->restrict_lud)
		ldap_free_urldesc(cp->restrict_lud);
	if (!BER_BVISNULL(&cp->restrict_ndn))
		ch_free(cp->restrict_ndn.bv_val);
	if (cp->restrict_filter != NULL && cp->restrict_filter != slap_filter_objectClass_pres)
		filter_free(cp->restrict_filter);
	if (!BER_BVISNULL(&cp->restrict_val))
		ch_free(cp->restrict_val.bv_val);
	if (cp->re) {
		regfree(cp->re);
		ch_free(cp->re);
	}
	if (!BER_BVISNULL(&cp->val))
		ch_free(cp->val.bv_val);
	if (cp->lud)
		ldap_free_urldesc(cp->lud);
	if (cp->attrs)
		ch_free(cp->attrs);
	if (cp->ap)
		ch_free(cp->ap);
	if (freeme)
		ch_free(cp);
}
Пример #2
0
/* a bit dirty but leak free  */
char * ldap_parse_servers(const char * servers) {
    char * s = NULL;
    char * tmp = NULL, *urls[32];
    unsigned int num = 0 , i = 0 , asize = 0;
    LDAPURLDesc *urld[32];

    if (!servers)
        return NULL;

    /* local copy of the arg */
    s = strdup(servers);
    if (!s)
        return NULL;

    /* first separate into URL tokens */
    if ( tokenize(urls, sizeof(urls)/sizeof(*urls), s) < 0)
        return NULL;

    i = 0;
    while (urls[i]) {
        if (! ldap_is_ldap_url(urls[i]) ||
           (ldap_url_parse(urls[i], &urld[i]) != 0)) {
                return NULL;
        }
        i++;
    }

    /* now free(s) */
    free (s);

    /* how much memory do we need */
    num = i;
    for (i = 0 ; i < num ; i++)
        asize += strlen(urld[i]->lud_host)+11;

    /* alloc */
    s = (char *) calloc( asize+1 , sizeof(char));
    if (!s) {
        for (i = 0 ; i < num ; i++)
            ldap_free_urldesc(urld[i]);
        return NULL;
    }

    /* then build the final host string */
    for (i = 0 ; i < num ; i++) {
        /* built host part */
        tmp = ldap_build_host(urld[i]->lud_host, urld[i]->lud_port);
        strncat(s, tmp, strlen(tmp));
        ldap_free_urldesc(urld[i]);
        free(tmp);
    }

    return s;
}
Пример #3
0
static int
get_read_entries( char *filename, char *entries[], char *filters[] )
{
	FILE    *fp;
	int     entry = 0;

	if ( (fp = fopen( filename, "r" )) != NULL ) {
		char  line[BUFSIZ];

		while (( entry < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
			char *nl;

			if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
				*nl = '\0';
			if ( filters != NULL && line[0] == '+' ) {
				LDAPURLDesc	*lud;

				if ( ldap_url_parse( &line[1], &lud ) != LDAP_URL_SUCCESS ) {
					entry = -entry - 1;
					break;
				}

				if ( lud->lud_dn == NULL || lud->lud_dn[ 0 ] == '\0' ) {
					ldap_free_urldesc( lud );
					entry = -entry - 1;
					break;
				}

				entries[entry] = ArgDup( lud->lud_dn );

				if ( lud->lud_filter ) {
					filters[entry] = ArgDup( lud->lud_filter );

				} else {
					filters[entry] = ArgDup( "(objectClass=*)" );
				}
				ldap_free_urldesc( lud );

			} else {
				if ( filters != NULL )
					filters[entry] = NULL;

				entries[entry] = ArgDup( line );
			}

			entry++;

		}
		fclose( fp );
	}

	return( entry );
}
Пример #4
0
int ldap_url_search_async(
	char* _ldap_url,
	int* _ld_result_count,
	int* _msgidp,
	struct ld_session **ldsp)
{
	LDAPURLDesc *ludp;
	int rc;

	if (ldap_url_parse(_ldap_url, &ludp) != 0) {
		LM_ERR("invalid LDAP URL [%s]\n", ZSW(_ldap_url));
		if (ludp != NULL) {
			ldap_free_urldesc(ludp);
		}
		return -2;
	}
	if (ludp->lud_host == NULL)
	{
		LM_ERR(	"no ldap session name found in ldap URL [%s]\n",
			ZSW(_ldap_url));
		return -2;
	}


	LM_DBG(	"LDAP URL parsed into session_name"
		" [%s], base [%s], scope [%d], filter [%s]\n",
		ZSW(ludp->lud_host),
		ZSW(ludp->lud_dn),
		ludp->lud_scope,
		ZSW(ludp->lud_filter));

	rc = ldap_params_search_async(_ld_result_count,
		_msgidp,
		ludp->lud_host,
		ludp->lud_dn,
		ludp->lud_scope,
		ludp->lud_attrs,
		ludp->lud_filter);
	if (rc == 0 && *_msgidp >= 0) {
		if (get_connected_ldap_session(ludp->lud_host, ldsp)) {
			LM_ERR("[%s]: couldn't get ldap session\n", ludp->lud_host);
			return -1;
		}
	}


	ldap_free_urldesc(ludp);
	return rc;
}
Пример #5
0
int ld_uri(db_uri_t* uri)
{
	struct ld_uri* luri;

	luri = (struct ld_uri*)pkg_malloc(sizeof(struct ld_uri));
	if (luri == NULL) {
		ERR("ldap: No memory left\n");
		goto error;
	}
	memset(luri, '\0', sizeof(struct ld_uri));
	if (db_drv_init(&luri->drv, ld_uri_free) < 0) goto error;
    if (parse_ldap_uri(luri,  &uri->scheme, &uri->body) < 0) goto error;

	DB_SET_PAYLOAD(uri, luri);
	uri->cmp = ld_uri_cmp;
	return 0;

 error:
	if (luri) {
		if (luri->uri) pkg_free(luri->uri);
		if (luri->ldap_url) ldap_free_urldesc(luri->ldap_url);
		db_drv_free(&luri->drv);
		pkg_free(luri);
	}
	return -1;
}
Пример #6
0
static CURLcode ldap_setup_connection(struct connectdata *conn)
{
  ldapconninfo *li;
  LDAPURLDesc *lud;
  struct SessionHandle *data=conn->data;
  int rc, proto;
  CURLcode status;

  rc = ldap_url_parse(data->change.url, &lud);
  if(rc != LDAP_URL_SUCCESS) {
    const char *msg = "url parsing problem";
    status = CURLE_URL_MALFORMAT;
    if(rc > LDAP_URL_SUCCESS && rc <= LDAP_URL_ERR_BADEXTS) {
      if(rc == LDAP_URL_ERR_MEM)
        status = CURLE_OUT_OF_MEMORY;
      msg = url_errs[rc];
    }
    failf(conn->data, "LDAP local: %s", msg);
    return status;
  }
  proto = ldap_pvt_url_scheme2proto(lud->lud_scheme);
  ldap_free_urldesc(lud);

  li = calloc(1, sizeof(ldapconninfo));
  if(!li)
    return CURLE_OUT_OF_MEMORY;
  li->proto = proto;
  conn->proto.generic = li;
  connkeep(conn, "OpenLDAP default");
  /* TODO:
   * - provide option to choose SASL Binds instead of Simple
   */
  return CURLE_OK;
}
Пример #7
0
/// sets LDAP server's URI
/// @param[in] cnf   reference to common configuration struct
/// @param[in] arg   value of the command line argument
int ldaputils_config_set_uri(LdapUtilsConfig * cnf, const char * arg)
{
   if ((cnf->ludp))
   {
      if (cnf->host == cnf->ludp->lud_host)
         cnf->host = NULL;
      ldap_free_urldesc(cnf->ludp);
   };
   cnf->ludp = NULL;
   
   if (!(cnf->uri = arg))
      return(0);
   
   if ((ldap_url_parse(arg, &cnf->ludp)))
   {
      // TRANSLATORS: The following strings provide an error message if the
      // URI provided on the command line is an invalid LDAP URI.
      fprintf(stderr, _("%s: invalid LDAP URI\n"), PROGRAM_NAME);
      fprintf(stderr, _("Try `%s --help' for more information.\n"), PROGRAM_NAME);
      return(1);
   };
   
   cnf->host  = cnf->ludp->lud_host;
   cnf->port  = cnf->ludp->lud_port;
   
   return(0);
}
Пример #8
0
int
ldap_initialize(LDAP **ldp, char *url)
{
    int rc = 0;
    LDAP *ld = NULL;
    LDAPURLDesc *ludp = NULL;

    /*
     * For now, we don't use any DN that may be provided.  And on Solaris
     * (based on Mozilla's LDAP client code), we need the _nodn form to parse
     * "ldap://host" without a trailing slash.
     *
     * Also, this version won't handle an input string which contains multiple
     * URLs, unlike the OpenLDAP ldap_initialize.  See
     * https://bugzilla.mozilla.org/show_bug.cgi?id=353336#c1 .
     */
#ifdef HAVE_LDAP_URL_PARSE_NODN
    rc = ldap_url_parse_nodn(url, &ludp);
#else
    rc = ldap_url_parse(url, &ludp);
#endif
    if (rc == 0) {
        ld = ldap_init(ludp->lud_host, ludp->lud_port);
        if (ld != NULL)
            *ldp = ld;
        else
            rc = KRB5_KDB_ACCESS_ERROR;
        ldap_free_urldesc(ludp);
    }
    return rc;
}
Пример #9
0
static void
map_ldap_free(
		struct ldap_map_data *data
)
{
	assert( data != NULL );

	if ( data->lm_url != NULL ) {
		free( data->lm_url );
	}

	if ( data->lm_lud != NULL ) {
		ldap_free_urldesc( data->lm_lud );
	}

	if ( data->lm_binddn != NULL ) {
		free( data->lm_binddn );
	}

	if ( data->lm_cred.bv_val != NULL ) {
		memset( data->lm_cred.bv_val, 0, data->lm_cred.bv_len );
		free( data->lm_cred.bv_val );
		data->lm_cred.bv_val = NULL;
		data->lm_cred.bv_len = 0;
	}

	if ( data->lm_when != MAP_LDAP_EVERYTIME && data->lm_ld != NULL ) {
		ldap_unbind_ext( data->lm_ld, NULL, NULL );
	}

	free( data );
}
Пример #10
0
ldap_handle::~ldap_handle()

{
	release_message();

	if (ldap)
		ldap_unbind_ext(ldap, NULL, NULL);

	if (uri)
		ldap_free_urldesc(uri);
}
Пример #11
0
/* validate URL for global referral use
 *   LDAP URLs must not have:
 *     DN, attrs, scope, nor filter
 *   Any non-LDAP URL is okay
 *
 *   XXYYZ: should return an error string
 */
int validate_global_referral( const char *url )
{
	int rc;
	LDAPURLDesc *lurl;

	rc = ldap_url_parse_ext( url, &lurl, LDAP_PVT_URL_PARSE_NONE );

	switch( rc ) {
	case LDAP_URL_SUCCESS:
		break;

	case LDAP_URL_ERR_BADSCHEME:
		/* not LDAP hence valid */
		Debug( LDAP_DEBUG_CONFIG, "referral \"%s\": not LDAP.\n", url, 0, 0 );
		return 0;

	default:
		/* other error, bail */
		Debug( LDAP_DEBUG_ANY,
			"referral: invalid URL (%s): %s (%d)\n",
			url, "" /* ldap_url_error2str(rc) */, rc );
		return 1;
	}

	rc = 0;

	if( lurl->lud_dn && *lurl->lud_dn ) {
		Debug( LDAP_DEBUG_ANY,
			"referral: URL (%s): contains DN\n",
			url, 0, 0 );
		rc = 1;

	} else if( lurl->lud_attrs ) {
		Debug( LDAP_DEBUG_ANY,
			"referral: URL (%s): requests attributes\n",
			url, 0, 0 );
		rc = 1;

	} else if( lurl->lud_scope != LDAP_SCOPE_DEFAULT ) {
		Debug( LDAP_DEBUG_ANY,
			"referral: URL (%s): contains explicit scope\n",
			url, 0, 0 );
		rc = 1;

	} else if( lurl->lud_filter ) {
		Debug( LDAP_DEBUG_ANY,
			"referral: URL (%s): contains explicit filter\n",
			url, 0, 0 );
		rc = 1;
	}

	ldap_free_urldesc( lurl );
	return rc;
}
Пример #12
0
static void ld_uri_free(db_uri_t* uri, struct ld_uri* payload)
{
	if (payload == NULL) return;
	if (payload->ldap_url) ldap_free_urldesc(payload->ldap_url);
	if (payload->uri) pkg_free(payload->uri);
    if (payload->username) pkg_free(payload->username);
    if (payload->password) pkg_free(payload->password);
    if (payload->ca_list) pkg_free(payload->ca_list);
    if (payload->req_cert) pkg_free(payload->req_cert);
	db_drv_free(&payload->drv);
	pkg_free(payload);
}
Пример #13
0
int ldap_url_search(
	char* _ldap_url,
	int* _ld_result_count)
{
	LDAPURLDesc *ludp;
	int rc;

	if (ldap_url_parse(_ldap_url, &ludp) != 0) {
		LM_ERR("invalid LDAP URL [%s]\n", ZSW(_ldap_url));
		if (ludp != NULL) {
			ldap_free_urldesc(ludp);
		}
		return -2;
	}
	if (ludp->lud_host == NULL)
	{
		LM_ERR(	"no ldap session name found in ldap URL [%s]\n",
			ZSW(_ldap_url));
		return -2;
	}


	LM_DBG(	"LDAP URL parsed into session_name"
		" [%s], base [%s], scope [%d], filter [%s]\n",
		ZSW(ludp->lud_host),
		ZSW(ludp->lud_dn),
		ludp->lud_scope,
		ZSW(ludp->lud_filter));

	rc = ldap_params_search(_ld_result_count,
		ludp->lud_host,
		ludp->lud_dn,
		ludp->lud_scope,
		ludp->lud_attrs,
		ludp->lud_filter);
	ldap_free_urldesc(ludp);
	return rc;
}
Пример #14
0
void be_ldap_destroy(void *handle)
{
	struct ldap_backend *conf = (struct ldap_backend *)handle;

	if (conf) {
		ldap_free_urldesc(conf->lud);
		free(conf->ldap_uri);

		if (conf->connstr)
			free(conf->connstr);
		if (conf->ld)
			ldap_unbind(conf->ld);
		free(conf);
	}
}
Пример #15
0
static int
dynlist_db_destroy(
	BackendDB	*be,
	ConfigReply	*cr )
{
	slap_overinst	*on = (slap_overinst *) be->bd_info;

	if ( on->on_bi.bi_private ) {
		dynlist_info_t	*dli = (dynlist_info_t *)on->on_bi.bi_private,
				*dli_next;

		for ( dli_next = dli; dli_next; dli = dli_next ) {
			dynlist_map_t *dlm;
			dynlist_map_t *dlm_next;

			dli_next = dli->dli_next;

			if ( !BER_BVISNULL( &dli->dli_uri ) ) {
				ch_free( dli->dli_uri.bv_val );
			}

			if ( dli->dli_lud != NULL ) {
				ldap_free_urldesc( dli->dli_lud );
			}

			if ( !BER_BVISNULL( &dli->dli_uri_nbase ) ) {
				ber_memfree( dli->dli_uri_nbase.bv_val );
			}

			if ( dli->dli_uri_filter != NULL ) {
				filter_free( dli->dli_uri_filter );
			}

			ch_free( dli->dli_default_filter.bv_val );

			dlm = dli->dli_dlm;
			while ( dlm != NULL ) {
				dlm_next = dlm->dlm_next;
				ch_free( dlm );
				dlm = dlm_next;
			}
			ch_free( dli );
		}
	}

	return 0;
}
Пример #16
0
static CURLcode ldap_do(struct connectdata *conn, bool *done)
{
  ldapconninfo *li = conn->proto.generic;
  ldapreqinfo *lr;
  CURLcode status = CURLE_OK;
  int rc = 0;
  LDAPURLDesc *ludp = NULL;
  int msgid;
  struct SessionHandle *data=conn->data;

  connkeep(conn, "OpenLDAP do");

  infof(data, "LDAP local: %s\n", data->change.url);

  rc = ldap_url_parse(data->change.url, &ludp);
  if(rc != LDAP_URL_SUCCESS) {
    const char *msg = "url parsing problem";
    status = CURLE_URL_MALFORMAT;
    if(rc > LDAP_URL_SUCCESS && rc <= LDAP_URL_ERR_BADEXTS) {
      if(rc == LDAP_URL_ERR_MEM)
        status = CURLE_OUT_OF_MEMORY;
      msg = url_errs[rc];
    }
    failf(conn->data, "LDAP local: %s", msg);
    return status;
  }

  rc = ldap_search_ext(li->ld, ludp->lud_dn, ludp->lud_scope,
                       ludp->lud_filter, ludp->lud_attrs, 0,
                       NULL, NULL, NULL, 0, &msgid);
  ldap_free_urldesc(ludp);
  if(rc != LDAP_SUCCESS) {
    failf(data, "LDAP local: ldap_search_ext %s", ldap_err2string(rc));
    return CURLE_LDAP_SEARCH_FAILED;
  }
  lr = calloc(1, sizeof(ldapreqinfo));
  if(!lr)
    return CURLE_OUT_OF_MEMORY;
  lr->msgid = msgid;
  data->req.protop = lr;
  Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, NULL, -1, NULL);
  *done = TRUE;
  return CURLE_OK;
}
Пример #17
0
static void
ldaphost_free(ldaphost *p) {
#ifdef TRACE_BY_LDAP
fprintf(stderr, "TRACE_BY_LDAP ldaphost_free:\n");
#endif
	if (p == NULL) return;
	if (p->url    != NULL) OPENSSL_free(p->url);
	if (p->binddn != NULL) OPENSSL_free(p->binddn);
	if (p->bindpw != NULL) OPENSSL_free(p->bindpw);
	if (p->ldapurl != NULL) {
		ldap_free_urldesc(p->ldapurl);
		p->ldapurl = NULL;
	}
	if (p->ld != NULL) {
		/* how to free ld ???*/
		p->ld = NULL;
	}
	OPENSSL_free(p);
}
Пример #18
0
static void
exit_ldap(struct object *o)
{
    if (THIS->server_url) {
        ldap_free_urldesc(THIS->server_url);
        THIS->server_url = NULL;
    }

    free_string(base_str);
    free_string(scope_str);
    free_string(filter_str);
    free_string(attrs_str);
    free_string(attrsonly_str);
    free_string(timeout_str);
    free_string(empty_str);
    free_string(modify_op);
    free_string(modify_type);
    free_string(modify_values);
}
Пример #19
0
nsresult
nsLDAPURL::SetPathInternal(const nsCString &aPath)
{
  LDAPURLDesc *desc;

  // This is from the LDAP C-SDK, which currently doesn't
  // support everything from RFC 2255... :(
  //
  int err = ldap_url_parse(aPath.get(), &desc);
  switch (err) {
  case LDAP_SUCCESS: {
    // The base URL can pick up the host & port details and deal with them
    // better than we can
    mDN = desc->lud_dn;
    mScope = desc->lud_scope;
    mFilter = desc->lud_filter;
    mOptions = desc->lud_options;
    nsresult rv = SetAttributeArray(desc->lud_attrs);
    if (NS_FAILED(rv))
      return rv;

    ldap_free_urldesc(desc);
    return NS_OK;
  }

  case LDAP_URL_ERR_NOTLDAP:
  case LDAP_URL_ERR_NODN:
  case LDAP_URL_ERR_BADSCOPE:
    return NS_ERROR_MALFORMED_URI;

  case LDAP_URL_ERR_MEM:
    NS_ERROR("nsLDAPURL::SetSpec: out of memory ");
    return NS_ERROR_OUT_OF_MEMORY;

  case LDAP_URL_ERR_PARAM: 
    return NS_ERROR_INVALID_POINTER;
  }

  // This shouldn't happen...
  return NS_ERROR_UNEXPECTED;
}
Пример #20
0
/**
 * seahorse_ldap_is_valid_uri
 * @uri: The uri to check
 * 
 * Returns: Whether the passed uri is valid for an ldap key source
 */
gboolean              
seahorse_ldap_is_valid_uri (const gchar *uri)
{
    LDAPURLDesc *url;
    int r;
    
    g_return_val_if_fail (uri && *uri, FALSE);
    
    r = ldap_url_parse (uri, &url);
    if (r == LDAP_URL_SUCCESS) {
        
        /* Some checks to make sure it's a simple URI */
        if (!(url->lud_host && url->lud_host[0]) || 
            (url->lud_dn && url->lud_dn[0]) || 
            (url->lud_attrs || url->lud_attrs))
            r = LDAP_URL_ERR_PARAM;
        
        ldap_free_urldesc (url);
    }
        
    return r == LDAP_URL_SUCCESS;
}
Пример #21
0
/** Instantiate the module
 *
 * Creates a new instance of the module reading parameters from a configuration section.
 *
 * @param conf to parse.
 * @param instance Where to write pointer to configuration data.
 * @return 0 on success < 0 on failure.
 */
static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
	static bool version_done;

	CONF_SECTION *options;
	ldap_instance_t *inst = instance;

	inst->cs = conf;

	options = cf_section_sub_find(conf, "options");
	if (!options || !cf_pair_find(options, "chase_referrals")) {
		inst->chase_referrals_unset = true;	 /* use OpenLDAP defaults */
	}

	inst->xlat_name = cf_section_name2(conf);
	if (!inst->xlat_name) {
		inst->xlat_name = cf_section_name1(conf);
	}


	/*
	 *	Only needs to be done once, prevents races in environment
	 *	initialisation within libldap.
	 *
	 *	See: https://github.com/arr2036/ldapperf/issues/2
	 */
#ifdef HAVE_LDAP_INITIALIZE
	ldap_initialize(&inst->handle, "");
#else
	inst->handle = ldap_init("", 0);
#endif

	/*
	 *	Get version info from the LDAP API.
	 */
	if (!version_done) {
		static LDAPAPIInfo info;	/* static to quiet valgrind about this being uninitialised */
		int ldap_errno;

		version_done = true;

		ldap_errno = ldap_get_option(NULL, LDAP_OPT_API_INFO, &info);
		if (ldap_errno == LDAP_OPT_SUCCESS) {
			if (strcmp(info.ldapai_vendor_name, LDAP_VENDOR_NAME) != 0) {
				WARN("rlm_ldap: libldap vendor changed since the server was built");
				WARN("rlm_ldap: linked: %s, built: %s", info.ldapai_vendor_name, LDAP_VENDOR_NAME);
			}

			if (info.ldapai_vendor_version != LDAP_VENDOR_VERSION) {
				WARN("rlm_ldap: libldap version changed since the server was built");
				WARN("rlm_ldap: linked: %i, built: %i",
				     info.ldapai_vendor_version, LDAP_VENDOR_VERSION);
			}

			INFO("rlm_ldap: libldap vendor: %s, version: %i", info.ldapai_vendor_name,
			     info.ldapai_vendor_version);

			ldap_memfree(info.ldapai_vendor_name);
			ldap_memfree(info.ldapai_extensions);
		} else {
			DEBUG("rlm_ldap: Falling back to build time libldap version info.  Query for LDAP_OPT_API_INFO "
			      "returned: %i", ldap_errno);
			INFO("rlm_ldap: libldap vendor: %s, version: %i.%i.%i", LDAP_VENDOR_NAME,
			     LDAP_VENDOR_VERSION_MAJOR, LDAP_VENDOR_VERSION_MINOR, LDAP_VENDOR_VERSION_PATCH);
		}
	}

	/*
	 *	If the configuration parameters can't be parsed, then fail.
	 */
	if ((parse_sub_section(inst, conf, &inst->accounting, RLM_COMPONENT_ACCT) < 0) ||
	    (parse_sub_section(inst, conf, &inst->postauth, RLM_COMPONENT_POST_AUTH) < 0)) {
		cf_log_err_cs(conf, "Failed parsing configuration");

		goto error;
	}

	/*
	 *	Sanity checks for cacheable groups code.
	 */
	if (inst->cacheable_group_name && inst->groupobj_membership_filter) {
		if (!inst->groupobj_name_attr) {
			cf_log_err_cs(conf, "Directive 'group.name_attribute' must be set if cacheable "
				      "group names are enabled");

			goto error;
		}
	}

	/*
	 *	Split original server value out into URI, server and port
	 *	so whatever initialization function we use later will have
	 *	the server information in the format it needs.
	 */
	if (ldap_is_ldap_url(inst->server)) {
		LDAPURLDesc *ldap_url;
		int port;

		if (ldap_url_parse(inst->server, &ldap_url)){
			cf_log_err_cs(conf, "Parsing LDAP URL \"%s\" failed", inst->server);
			return -1;
		}

		/*
		 *	Figure out the port from the URL
		 */
		if (ldap_url->lud_port == 0) {
			if (strcmp(ldap_url->lud_scheme, "ldaps://") == 0) {
				if (inst->start_tls == true) {
				start_tls_error:
					cf_log_err_cs(conf, "ldaps:// scheme is not compatible with 'start_tls'");
					return -1;
				}
				port = 636;
			} else {
				port = 384;
			}
		} else {
			port = ldap_url->lud_port;
		}

		inst->uri = inst->server;
		inst->server = talloc_strdup(inst, ldap_url->lud_host);

		if ((inst->port != 384) && (port != inst->port)) {
			WARN("Non-default 'port' directive %i set to %i by LDAP URI", inst->port, port);
		}
		inst->port = port;

		/*
		 *	@todo We could set a few other top level
		 *	directives using the URL, like base_dn
		 *	and scope.
		 */

		ldap_free_urldesc(ldap_url);
	/*
	 *	We need to construct an LDAP URI
	 */
	} else {
		switch (inst->port) {
		default:
		case 384:
			inst->uri = talloc_asprintf(inst, "ldap://%s:%i/", inst->server, inst->port);
			break;

		case 636:
			if (inst->start_tls == true) goto start_tls_error;
			inst->uri = talloc_asprintf(inst, "ldaps://%s:%i/", inst->server, inst->port);
			break;
		}
	}

#ifdef LDAP_OPT_X_TLS_NEVER
	/*
	 *	Workaround for servers which support LDAPS but not START TLS
	 */
	if (inst->port == LDAPS_PORT || inst->tls_mode) {
		inst->tls_mode = LDAP_OPT_X_TLS_HARD;
	} else {
		inst->tls_mode = 0;
	}
#endif

	/*
	 *	Convert dereference strings to enumerated constants
	 */
	if (inst->dereference_str) {
		inst->dereference = fr_str2int(ldap_dereference, inst->dereference_str, -1);
		if (inst->dereference < 0) {
			cf_log_err_cs(conf, "Invalid 'dereference' value \"%s\", expected 'never', 'searching', "
				      "'finding' or 'always'", inst->dereference_str);
			goto error;
		}
	}

#if LDAP_SET_REBIND_PROC_ARGS != 3
	/*
	 *	The 2-argument rebind doesn't take an instance variable.  Our rebind function needs the instance
	 *	variable for the username, password, etc.
	 */
	if (inst->rebind == true) {
		cf_log_err_cs(conf, "Cannot use 'rebind' directive as this version of libldap "
			      "does not support the API that we need");

		goto error;
	}
#endif

	/*
	 *	Convert scope strings to enumerated constants
	 */
	inst->userobj_scope = fr_str2int(ldap_scope, inst->userobj_scope_str, -1);
	if (inst->userobj_scope < 0) {
		cf_log_err_cs(conf, "Invalid 'user.scope' value \"%s\", expected 'sub', 'one'"
#ifdef LDAP_SCOPE_CHILDREN
			      ", 'base' or 'children'"
#else
			      " or 'base'"
#endif
			 , inst->userobj_scope_str);
		goto error;
	}

	inst->groupobj_scope = fr_str2int(ldap_scope, inst->groupobj_scope_str, -1);
	if (inst->groupobj_scope < 0) {
		cf_log_err_cs(conf, "Invalid 'group.scope' value \"%s\", expected 'sub', 'one'"
#ifdef LDAP_SCOPE_CHILDREN
			      ", 'base' or 'children'"
#else
			      " or 'base'"
#endif
			 , inst->groupobj_scope_str);
		goto error;
	}

	inst->clientobj_scope = fr_str2int(ldap_scope, inst->clientobj_scope_str, -1);
	if (inst->clientobj_scope < 0) {
		cf_log_err_cs(conf, "Invalid 'client.scope' value \"%s\", expected 'sub', 'one'"
#ifdef LDAP_SCOPE_CHILDREN
			      ", 'base' or 'children'"
#else
			      " or 'base'"
#endif
			 , inst->clientobj_scope_str);
		goto error;
	}

	if (inst->tls_require_cert_str) {
#ifdef LDAP_OPT_X_TLS_NEVER
		/*
		 *	Convert cert strictness to enumerated constants
		 */
		inst->tls_require_cert = fr_str2int(ldap_tls_require_cert, inst->tls_require_cert_str, -1);
		if (inst->tls_require_cert < 0) {
			cf_log_err_cs(conf, "Invalid 'tls.require_cert' value \"%s\", expected 'never', "
				      "'demand', 'allow', 'try' or 'hard'", inst->tls_require_cert_str);
			goto error;
		}
#else
		cf_log_err_cs(conf, "Modifying 'tls.require_cert' is not supported by current "
			      "version of libldap. Please upgrade or substitute current libldap and "
			      "rebuild this module");

		goto error;
#endif
	}
	/*
	 *	Build the attribute map
	 */
	if (map_afrom_cs(&inst->user_map, cf_section_sub_find(inst->cs, "update"),
			 PAIR_LIST_REPLY, PAIR_LIST_REQUEST, rlm_ldap_map_verify, inst,
			 LDAP_MAX_ATTRMAP) < 0) {
		return -1;
	}

	/*
	 *	Group comparison checks.
	 */
	if (cf_section_name2(conf)) {
		static ATTR_FLAGS flags;
		char buffer[256];

		snprintf(buffer, sizeof(buffer), "%s-Ldap-Group", inst->xlat_name);
		if (dict_addattr(buffer, -1, 0, PW_TYPE_STRING, flags) < 0) {
			LDAP_ERR("Error creating group attribute: %s", fr_strerror());

			return -1;
		}
		inst->group_da = dict_attrbyname(buffer);
		if (!inst->group_da) {
			LDAP_ERR("Failed creating attribute %s", buffer);

			goto error;
		}

		paircompare_register(inst->group_da, dict_attrbyvalue(PW_USER_NAME, 0), false, rlm_ldap_groupcmp, inst);
	/*
	 *	Were the default instance
	 */
	} else {
		inst->group_da = dict_attrbyvalue(PW_LDAP_GROUP, 0);
		paircompare_register(dict_attrbyvalue(PW_LDAP_GROUP, 0), dict_attrbyvalue(PW_USER_NAME, 0),
				false, rlm_ldap_groupcmp, inst);
	}

	xlat_register(inst->xlat_name, ldap_xlat, rlm_ldap_escape_func, inst);

	/*
	 *	Setup the cache attribute
	 */
	if (inst->cache_attribute) {
		static ATTR_FLAGS flags;

		if (dict_addattr(inst->cache_attribute, -1, 0, PW_TYPE_STRING, flags) < 0) {
			LDAP_ERR("Error creating cache attribute: %s", fr_strerror());

			goto error;
		}
		inst->cache_da = dict_attrbyname(inst->cache_attribute);
	} else {
		inst->cache_da = inst->group_da;	/* Default to the group_da */
	}

	/*
	 *	Initialize the socket pool.
	 */
	inst->pool = fr_connection_pool_module_init(inst->cs, inst, mod_conn_create, NULL, NULL);
	if (!inst->pool) goto error;

	/*
	 *	Bulk load dynamic clients.
	 */
	if (inst->do_clients) {
		CONF_SECTION *cs;

		cs = cf_section_sub_find(inst->cs, "client");
		if (!cs) {
			cf_log_err_cs(conf, "Told to load clients but no client section found");
			goto error;
		}

		cs = cf_section_sub_find(cs, "attribute");
		if (!cs) {
			cf_log_err_cs(conf, "Told to load clients but no attribute section found");
			goto error;
		}

		if (rlm_ldap_client_load(inst, cs) < 0) {
			cf_log_err_cs(conf, "Error loading clients");

			return -1;
		}
	}

	return 0;

error:
	return -1;
}
Пример #22
0
static int
_mu_conn_setup (LDAP **pld)
{
  int rc;
  LDAPURLDesc *ludlist, **ludp;
  char **urls = NULL;
  int nurls = 0;
  char *ldapuri = NULL;
  LDAP *ld = NULL;
  int protocol = LDAP_VERSION3; /* FIXME: must be configurable */
  
  if (ldap_param.debug)
    {
      if (ber_set_option (NULL, LBER_OPT_DEBUG_LEVEL, &ldap_param.debug)
	  != LBER_OPT_SUCCESS )
	mu_error (_("cannot set LBER_OPT_DEBUG_LEVEL %d"), ldap_param.debug);

      if (ldap_set_option (NULL, LDAP_OPT_DEBUG_LEVEL, &ldap_param.debug)
	  != LDAP_OPT_SUCCESS )
	mu_error (_("could not set LDAP_OPT_DEBUG_LEVEL %d"),
		  ldap_param.debug);
    }

  if (ldap_param.url)
    {
      rc = ldap_url_parse (ldap_param.url, &ludlist);
      if (rc != LDAP_URL_SUCCESS)
	{
	  mu_error (_("cannot parse LDAP URL(s)=%s (%d)"),
		    ldap_param.url, rc);
	  return 1;
	}
      
      for (ludp = &ludlist; *ludp; )
	{
	  LDAPURLDesc *lud = *ludp;
	  char **tmp;
	  
	  if (lud->lud_dn && lud->lud_dn[0]
	      && (lud->lud_host == NULL || lud->lud_host[0] == '\0'))
	    {
	      /* if no host but a DN is provided, try DNS SRV to gather the
		 host list */
	      char *domain = NULL, *hostlist = NULL;
	      size_t i;
	      struct mu_wordsplit ws;
	      
	      if (ldap_dn2domain (lud->lud_dn, &domain) || !domain)
		{
		  mu_error (_("DNS SRV: cannot convert DN=\"%s\" into a domain"),
			    lud->lud_dn );
		  goto dnssrv_free;
		}
	      
	      rc = ldap_domain2hostlist (domain, &hostlist);
	      if (rc)
		{
		  mu_error (_("DNS SRV: cannot convert domain=%s into a hostlist"),
			    domain);
		  goto dnssrv_free;
		}

	      if (mu_wordsplit (hostlist, &ws, MU_WRDSF_DEFFLAGS))
		{
		  mu_error (_("DNS SRV: could not parse hostlist=\"%s\": %s"),
			    hostlist, mu_wordsplit_strerror (&ws));
		  goto dnssrv_free;
		}
	      
	      tmp = realloc (urls, sizeof(char *) * (nurls + ws.ws_wordc + 1));
	      if (!tmp)
		{
		  mu_error ("DNS SRV %s", mu_strerror (errno));
		  goto dnssrv_free;
		}
	      
	      urls = tmp;
	      urls[nurls] = NULL;
	      
	      for (i = 0; i < ws.ws_wordc; i++)
		{
		  urls[nurls + i + 1] = NULL;
		  rc = mu_asprintf (&urls[nurls + i],
				    "%s://%s",
				    lud->lud_scheme, ws.ws_wordv[i]);
		  if (rc)
		    {
		      mu_error ("DNS SRV %s", mu_strerror (rc));
		      goto dnssrv_free;
		    }
		}
	      
	      nurls += i;
	      
	    dnssrv_free:
	      mu_wordsplit_free (&ws);
	      ber_memfree (hostlist);
	      ber_memfree (domain);
	    }
	  else
	    {
	      tmp = realloc (urls, sizeof(char *) * (nurls + 2));
	      if (!tmp)
		{
		  mu_error ("DNS SRV %s", mu_strerror (errno));
		  break;
		}
	      urls = tmp;
	      urls[nurls + 1] = NULL;
	      
	      urls[nurls] = ldap_url_desc2str (lud);
	      if (!urls[nurls])
		{
		  mu_error ("DNS SRV %s", mu_strerror (errno));
		  break;
		}
	      nurls++;
	    }
	  
	  *ludp = lud->lud_next;
	  
	  lud->lud_next = NULL;
	  ldap_free_urldesc (lud);
	}

      if (ludlist)
	{
	  ldap_free_urldesc (ludlist);
	  return 1;
	}
      else if (!urls)
	return 1;
      
      rc = mu_argcv_string (nurls, urls, &ldapuri);
      if (rc)
	{
	  mu_error ("%s", mu_strerror (rc));
	  return 1;
	}
      
      ber_memvfree ((void **)urls);
    }

  mu_diag_output (MU_DIAG_INFO,
		  "constructed LDAP URI: %s", ldapuri ? ldapuri : "<DEFAULT>");

  rc = ldap_initialize (&ld, ldapuri);
  if (rc != LDAP_SUCCESS)
    {
      mu_error (_("cannot create LDAP session handle for URI=%s (%d): %s"),
		ldapuri, rc, ldap_err2string (rc));

      free (ldapuri);
      return 1;
    }
  free (ldapuri);
  
  ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION, &protocol);

  if (ldap_param.tls)
    {
      rc = ldap_start_tls_s (ld, NULL, NULL);
      if (rc != LDAP_SUCCESS)
	{
	  char *msg = NULL;
	  ldap_get_option (ld,
			   LDAP_OPT_DIAGNOSTIC_MESSAGE,
			   (void*)&msg);
	  
	  mu_error (_("ldap_start_tls failed: %s"), ldap_err2string (rc));
	  mu_error (_("TLS diagnostics: %s"), msg);
	  ldap_memfree (msg);

	  ldap_unbind_ext (ld, NULL, NULL);
	  
	  return 1;
	}
    }

  /* FIXME: Timeouts, SASL, etc. */
  *pld = ld;
  return 0;
}
Пример #23
0
/** Expand an LDAP URL into a query, and return a string result from that query.
 *
 */
static ssize_t ldap_xlat(void *instance, REQUEST *request, char const *fmt, char *out, size_t freespace)
{
	ldap_rcode_t status;
	size_t len = 0;
	ldap_instance_t *inst = instance;
	LDAPURLDesc *ldap_url;
	LDAPMessage *result = NULL;
	LDAPMessage *entry = NULL;
	struct berval **values;
	ldap_handle_t *conn;
	int ldap_errno;
	char const *url;
	char const **attrs;

	url = fmt;

	if (!ldap_is_ldap_url(url)) {
		REDEBUG("String passed does not look like an LDAP URL");
		return -1;
	}

	if (ldap_url_parse(url, &ldap_url)){
		REDEBUG("Parsing LDAP URL failed");
		return -1;
	}

	/*
	 *	Nothing, empty string, "*" string, or got 2 things, die.
	 */
	if (!ldap_url->lud_attrs || !ldap_url->lud_attrs[0] ||
	    !*ldap_url->lud_attrs[0] ||
	    (strcmp(ldap_url->lud_attrs[0], "*") == 0) ||
	    ldap_url->lud_attrs[1]) {
		REDEBUG("Bad attributes list in LDAP URL. URL must specify exactly one attribute to retrieve");

		goto free_urldesc;
	}

	if (ldap_url->lud_host &&
	    ((strcmp(inst->server, ldap_url->lud_host) != 0) ||
	     ((uint32_t) ldap_url->lud_port != inst->port))) {
		REDEBUG("LDAP expansions must specify the same host and port as the their module instance");

		goto free_urldesc;
	}

	conn = mod_conn_get(inst, request);
	if (!conn) goto free_urldesc;

	memcpy(&attrs, &ldap_url->lud_attrs, sizeof(attrs));

	status = rlm_ldap_search(inst, request, &conn, ldap_url->lud_dn, ldap_url->lud_scope, ldap_url->lud_filter,
				 attrs, &result);
	switch (status) {
	case LDAP_PROC_SUCCESS:
		break;

	default:
		goto free_socket;
	}

	rad_assert(conn);
	rad_assert(result);

	entry = ldap_first_entry(conn->handle, result);
	if (!entry) {
		ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
		REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
		len = -1;
		goto free_result;
	}

	values = ldap_get_values_len(conn->handle, entry, ldap_url->lud_attrs[0]);
	if (!values) {
		RDEBUG("No \"%s\" attributes found in specified object", ldap_url->lud_attrs[0]);
		goto free_result;
	}

	if (values[0]->bv_len >= freespace) goto free_values;

	memcpy(out, values[0]->bv_val, values[0]->bv_len + 1);	/* +1 as strlcpy expects buffer size */
	len = values[0]->bv_len;

free_values:
	ldap_value_free_len(values);
free_result:
	ldap_msgfree(result);
free_socket:
	mod_conn_release(inst, conn);
free_urldesc:
	ldap_free_urldesc(ldap_url);

	return len;
}
Пример #24
0
static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
{
  CURLcode result = CURLE_OK;
  int rc = 0;
  LDAP *server = NULL;
  LDAPURLDesc *ludp = NULL;
  LDAPMessage *ldapmsg = NULL;
  LDAPMessage *entryIterator;
  int num = 0;
  struct SessionHandle *data=conn->data;
  int ldap_proto = LDAP_VERSION3;
  int ldap_ssl = 0;
  char *val_b64 = NULL;
  size_t val_b64_sz = 0;
  curl_off_t dlsize = 0;
#ifdef LDAP_OPT_NETWORK_TIMEOUT
  struct timeval ldap_timeout = {10,0}; /* 10 sec connection/search timeout */
#endif

  *done = TRUE; /* unconditionally */
  infof(data, "LDAP local: LDAP Vendor = %s ; LDAP Version = %d\n",
          LDAP_VENDOR_NAME, LDAP_VENDOR_VERSION);
  infof(data, "LDAP local: %s\n", data->change.url);

#ifdef HAVE_LDAP_URL_PARSE
  rc = ldap_url_parse(data->change.url, &ludp);
#else
  rc = _ldap_url_parse(conn, &ludp);
#endif
  if(rc != 0) {
    failf(data, "LDAP local: %s", ldap_err2string(rc));
    result = CURLE_LDAP_INVALID_URL;
    goto quit;
  }

  /* Get the URL scheme ( either ldap or ldaps ) */
  if(conn->given->flags & PROTOPT_SSL)
    ldap_ssl = 1;
  infof(data, "LDAP local: trying to establish %s connection\n",
          ldap_ssl ? "encrypted" : "cleartext");

#ifdef LDAP_OPT_NETWORK_TIMEOUT
  ldap_set_option(NULL, LDAP_OPT_NETWORK_TIMEOUT, &ldap_timeout);
#endif
  ldap_set_option(NULL, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);

  if(ldap_ssl) {
#ifdef HAVE_LDAP_SSL
#ifdef CURL_LDAP_WIN
    /* Win32 LDAP SDK doesn't support insecure mode without CA! */
    server = ldap_sslinit(conn->host.name, (int)conn->port, 1);
    ldap_set_option(server, LDAP_OPT_SSL, LDAP_OPT_ON);
#else
    int ldap_option;
    char* ldap_ca = data->set.str[STRING_SSL_CAFILE];
#if defined(CURL_HAS_NOVELL_LDAPSDK)
    rc = ldapssl_client_init(NULL, NULL);
    if(rc != LDAP_SUCCESS) {
      failf(data, "LDAP local: ldapssl_client_init %s", ldap_err2string(rc));
      result = CURLE_SSL_CERTPROBLEM;
      goto quit;
    }
    if(data->set.ssl.verifypeer) {
      /* Novell SDK supports DER or BASE64 files. */
      int cert_type = LDAPSSL_CERT_FILETYPE_B64;
      if((data->set.str[STRING_CERT_TYPE]) &&
         (Curl_raw_equal(data->set.str[STRING_CERT_TYPE], "DER")))
        cert_type = LDAPSSL_CERT_FILETYPE_DER;
      if(!ldap_ca) {
        failf(data, "LDAP local: ERROR %s CA cert not set!",
              (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"));
        result = CURLE_SSL_CERTPROBLEM;
        goto quit;
      }
      infof(data, "LDAP local: using %s CA cert '%s'\n",
              (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"),
              ldap_ca);
      rc = ldapssl_add_trusted_cert(ldap_ca, cert_type);
      if(rc != LDAP_SUCCESS) {
        failf(data, "LDAP local: ERROR setting %s CA cert: %s",
                (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"),
                ldap_err2string(rc));
        result = CURLE_SSL_CERTPROBLEM;
        goto quit;
      }
      ldap_option = LDAPSSL_VERIFY_SERVER;
    }
    else
      ldap_option = LDAPSSL_VERIFY_NONE;
    rc = ldapssl_set_verify_mode(ldap_option);
    if(rc != LDAP_SUCCESS) {
      failf(data, "LDAP local: ERROR setting cert verify mode: %s",
              ldap_err2string(rc));
      result = CURLE_SSL_CERTPROBLEM;
      goto quit;
    }
    server = ldapssl_init(conn->host.name, (int)conn->port, 1);
    if(server == NULL) {
      failf(data, "LDAP local: Cannot connect to %s:%ld",
              conn->host.name, conn->port);
      result = CURLE_COULDNT_CONNECT;
      goto quit;
    }
#elif defined(LDAP_OPT_X_TLS)
    if(data->set.ssl.verifypeer) {
      /* OpenLDAP SDK supports BASE64 files. */
      if((data->set.str[STRING_CERT_TYPE]) &&
         (!Curl_raw_equal(data->set.str[STRING_CERT_TYPE], "PEM"))) {
        failf(data, "LDAP local: ERROR OpenLDAP only supports PEM cert-type!");
        result = CURLE_SSL_CERTPROBLEM;
        goto quit;
      }
      if(!ldap_ca) {
        failf(data, "LDAP local: ERROR PEM CA cert not set!");
        result = CURLE_SSL_CERTPROBLEM;
        goto quit;
      }
      infof(data, "LDAP local: using PEM CA cert: %s\n", ldap_ca);
      rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, ldap_ca);
      if(rc != LDAP_SUCCESS) {
        failf(data, "LDAP local: ERROR setting PEM CA cert: %s",
                ldap_err2string(rc));
        result = CURLE_SSL_CERTPROBLEM;
        goto quit;
      }
      ldap_option = LDAP_OPT_X_TLS_DEMAND;
    }
    else
      ldap_option = LDAP_OPT_X_TLS_NEVER;

    rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &ldap_option);
    if(rc != LDAP_SUCCESS) {
      failf(data, "LDAP local: ERROR setting cert verify mode: %s",
              ldap_err2string(rc));
      result = CURLE_SSL_CERTPROBLEM;
      goto quit;
    }
    server = ldap_init(conn->host.name, (int)conn->port);
    if(server == NULL) {
      failf(data, "LDAP local: Cannot connect to %s:%ld",
              conn->host.name, conn->port);
      result = CURLE_COULDNT_CONNECT;
      goto quit;
    }
    ldap_option = LDAP_OPT_X_TLS_HARD;
    rc = ldap_set_option(server, LDAP_OPT_X_TLS, &ldap_option);
    if(rc != LDAP_SUCCESS) {
      failf(data, "LDAP local: ERROR setting SSL/TLS mode: %s",
              ldap_err2string(rc));
      result = CURLE_SSL_CERTPROBLEM;
      goto quit;
    }
/*
    rc = ldap_start_tls_s(server, NULL, NULL);
    if(rc != LDAP_SUCCESS) {
      failf(data, "LDAP local: ERROR starting SSL/TLS mode: %s",
              ldap_err2string(rc));
      result = CURLE_SSL_CERTPROBLEM;
      goto quit;
    }
*/
#else
    /* we should probably never come up to here since configure
       should check in first place if we can support LDAP SSL/TLS */
    failf(data, "LDAP local: SSL/TLS not supported with this version "
            "of the OpenLDAP toolkit\n");
    result = CURLE_SSL_CERTPROBLEM;
    goto quit;
#endif
#endif
#endif /* CURL_LDAP_USE_SSL */
  }
  else {
    server = ldap_init(conn->host.name, (int)conn->port);
    if(server == NULL) {
      failf(data, "LDAP local: Cannot connect to %s:%ld",
              conn->host.name, conn->port);
      result = CURLE_COULDNT_CONNECT;
      goto quit;
    }
  }
#ifdef CURL_LDAP_WIN
  ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
#endif

  rc = ldap_simple_bind_s(server,
                          conn->bits.user_passwd ? conn->user : NULL,
                          conn->bits.user_passwd ? conn->passwd : NULL);
  if(!ldap_ssl && rc != 0) {
    ldap_proto = LDAP_VERSION2;
    ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
    rc = ldap_simple_bind_s(server,
                            conn->bits.user_passwd ? conn->user : NULL,
                            conn->bits.user_passwd ? conn->passwd : NULL);
  }
  if(rc != 0) {
    failf(data, "LDAP local: ldap_simple_bind_s %s", ldap_err2string(rc));
    result = CURLE_LDAP_CANNOT_BIND;
    goto quit;
  }

  rc = ldap_search_s(server, ludp->lud_dn, ludp->lud_scope,
                     ludp->lud_filter, ludp->lud_attrs, 0, &ldapmsg);

  if(rc != 0 && rc != LDAP_SIZELIMIT_EXCEEDED) {
    failf(data, "LDAP remote: %s", ldap_err2string(rc));
    result = CURLE_LDAP_SEARCH_FAILED;
    goto quit;
  }

  for(num = 0, entryIterator = ldap_first_entry(server, ldapmsg);
      entryIterator;
      entryIterator = ldap_next_entry(server, entryIterator), num++) {
    BerElement *ber = NULL;
    char  *attribute;       /*! suspicious that this isn't 'const' */
    char  *dn = ldap_get_dn(server, entryIterator);
    int i;

    result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4);
    if(result)
      goto quit;

    result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)dn, 0);
    if(result)
      goto quit;

    result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
    if(result)
      goto quit;

    dlsize += strlen(dn)+5;

    for(attribute = ldap_first_attribute(server, entryIterator, &ber);
        attribute;
        attribute = ldap_next_attribute(server, entryIterator, ber)) {
      BerValue **vals = ldap_get_values_len(server, entryIterator, attribute);

      if(vals != NULL) {
        for(i = 0; (vals[i] != NULL); i++) {
          result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1);
          if(result)
            goto quit;

          result = Curl_client_write(conn, CLIENTWRITE_BODY,
                                     (char *)attribute, 0);
          if(result)
            goto quit;

          result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2);
          if(result)
            goto quit;
          dlsize += strlen(attribute)+3;

          if((strlen(attribute) > 7) &&
              (strcmp(";binary",
                      (char *)attribute +
                      (strlen((char *)attribute) - 7)) == 0)) {
            /* Binary attribute, encode to base64. */
            CURLcode error = Curl_base64_encode(data,
                                                vals[i]->bv_val,
                                                vals[i]->bv_len,
                                                &val_b64,
                                                &val_b64_sz);
            if(error) {
              ldap_value_free_len(vals);
              ldap_memfree(attribute);
              ldap_memfree(dn);
              if(ber)
                ber_free(ber, 0);
              result = error;
              goto quit;
            }
            if(val_b64_sz > 0) {
              result = Curl_client_write(conn, CLIENTWRITE_BODY, val_b64,
                                         val_b64_sz);
              free(val_b64);
              if(result)
                goto quit;
              dlsize += val_b64_sz;
            }
          }
          else {
            result = Curl_client_write(conn, CLIENTWRITE_BODY, vals[i]->bv_val,
                                       vals[i]->bv_len);
            if(result)
              goto quit;
            dlsize += vals[i]->bv_len;
          }
          result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
          if(result)
            goto quit;
          dlsize++;
        }

        /* Free memory used to store values */
        ldap_value_free_len(vals);
      }
      result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
      if(result)
        goto quit;
      dlsize++;
      Curl_pgrsSetDownloadCounter(data, dlsize);
      ldap_memfree(attribute);
    }
    ldap_memfree(dn);
    if(ber)
       ber_free(ber, 0);
  }

quit:
  if(ldapmsg) {
    ldap_msgfree(ldapmsg);
    LDAP_TRACE (("Received %d entries\n", num));
  }
  if(rc == LDAP_SIZELIMIT_EXCEEDED)
    infof(data, "There are more than %d entries\n", num);
  if(ludp)
    ldap_free_urldesc(ludp);
  if(server)
    ldap_unbind_s(server);
#if defined(HAVE_LDAP_SSL) && defined(CURL_HAS_NOVELL_LDAPSDK)
  if(ldap_ssl)
    ldapssl_client_deinit();
#endif /* HAVE_LDAP_SSL && CURL_HAS_NOVELL_LDAPSDK */

  /* no data to transfer */
  Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
  connclose(conn, "LDAP connection always disable re-use");

  return result;
}
Пример #25
0
/*
 * always protected by conn_mutex
 * optionally protected by req_mutex and res_mutex
 */
LDAPConn *
ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb,
	int connect, LDAPreqinfo *bind, int m_req, int m_res )
{
	LDAPConn	*lc;
	int		async = 0;

	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
	Debug( LDAP_DEBUG_TRACE, "ldap_new_connection %d %d %d\n",
		use_ldsb, connect, (bind != NULL) );
	/*
	 * make a new LDAP server connection
	 * XXX open connection synchronously for now
	 */
	lc = (LDAPConn *)LDAP_CALLOC( 1, sizeof( LDAPConn ) );
	if ( lc == NULL ) {
		ld->ld_errno = LDAP_NO_MEMORY;
		return( NULL );
	}
	
	if ( use_ldsb ) {
		assert( ld->ld_sb != NULL );
		lc->lconn_sb = ld->ld_sb;

	} else {
		lc->lconn_sb = ber_sockbuf_alloc();
		if ( lc->lconn_sb == NULL ) {
			LDAP_FREE( (char *)lc );
			ld->ld_errno = LDAP_NO_MEMORY;
			return( NULL );
		}
	}

	if ( connect ) {
		LDAPURLDesc	**srvp, *srv = NULL;

		async = LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_CONNECT_ASYNC );

		for ( srvp = srvlist; *srvp != NULL; srvp = &(*srvp)->lud_next ) {
			int		rc;

			rc = ldap_int_open_connection( ld, lc, *srvp, async );
			if ( rc != -1 ) {
				srv = *srvp;

				if ( ld->ld_urllist_proc && ( !async || rc != -2 ) ) {
					ld->ld_urllist_proc( ld, srvlist, srvp, ld->ld_urllist_params );
				}

				break;
			}
		}

		if ( srv == NULL ) {
			if ( !use_ldsb ) {
				ber_sockbuf_free( lc->lconn_sb );
			}
			LDAP_FREE( (char *)lc );
			ld->ld_errno = LDAP_SERVER_DOWN;
			return( NULL );
		}

		lc->lconn_server = ldap_url_dup( srv );
	}

	lc->lconn_status = async ? LDAP_CONNST_CONNECTING : LDAP_CONNST_CONNECTED;
	lc->lconn_next = ld->ld_conns;
	ld->ld_conns = lc;

	if ( connect ) {
#ifdef HAVE_TLS
		if ( lc->lconn_server->lud_exts ) {
			int rc, ext = find_tls_ext( lc->lconn_server );
			if ( ext ) {
				LDAPConn	*savedefconn;

				savedefconn = ld->ld_defconn;
				++lc->lconn_refcnt;	/* avoid premature free */
				ld->ld_defconn = lc;

				LDAP_REQ_UNLOCK_IF(m_req);
				LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
				LDAP_RES_UNLOCK_IF(m_res);
				rc = ldap_start_tls_s( ld, NULL, NULL );
				LDAP_RES_LOCK_IF(m_res);
				LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
				LDAP_REQ_LOCK_IF(m_req);
				ld->ld_defconn = savedefconn;
				--lc->lconn_refcnt;

				if ( rc != LDAP_SUCCESS && ext == 2 ) {
					ldap_free_connection( ld, lc, 1, 0 );
					return NULL;
				}
			}
		}
#endif
	}

	if ( bind != NULL ) {
		int		err = 0;
		LDAPConn	*savedefconn;

		/* Set flag to prevent additional referrals
		 * from being processed on this
		 * connection until the bind has completed
		 */
		lc->lconn_rebind_inprogress = 1;
		/* V3 rebind function */
		if ( ld->ld_rebind_proc != NULL) {
			LDAPURLDesc	*srvfunc;

			srvfunc = ldap_url_dup( *srvlist );
			if ( srvfunc == NULL ) {
				ld->ld_errno = LDAP_NO_MEMORY;
				err = -1;
			} else {
				savedefconn = ld->ld_defconn;
				++lc->lconn_refcnt;	/* avoid premature free */
				ld->ld_defconn = lc;

				Debug( LDAP_DEBUG_TRACE, "Call application rebind_proc\n", 0, 0, 0);
				LDAP_REQ_UNLOCK_IF(m_req);
				LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
				LDAP_RES_UNLOCK_IF(m_res);
				err = (*ld->ld_rebind_proc)( ld,
					bind->ri_url, bind->ri_request, bind->ri_msgid,
					ld->ld_rebind_params );
				LDAP_RES_LOCK_IF(m_res);
				LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
				LDAP_REQ_LOCK_IF(m_req);

				ld->ld_defconn = savedefconn;
				--lc->lconn_refcnt;

				if ( err != 0 ) {
					err = -1;
					ldap_free_connection( ld, lc, 1, 0 );
					lc = NULL;
				}
				ldap_free_urldesc( srvfunc );
			}

		} else {
			int		msgid, rc;
			struct berval	passwd = BER_BVNULL;

			savedefconn = ld->ld_defconn;
			++lc->lconn_refcnt;	/* avoid premature free */
			ld->ld_defconn = lc;

			Debug( LDAP_DEBUG_TRACE,
				"anonymous rebind via ldap_sasl_bind(\"\")\n",
				0, 0, 0);

			LDAP_REQ_UNLOCK_IF(m_req);
			LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
			LDAP_RES_UNLOCK_IF(m_res);
			rc = ldap_sasl_bind( ld, "", LDAP_SASL_SIMPLE, &passwd,
				NULL, NULL, &msgid );
			if ( rc != LDAP_SUCCESS ) {
				err = -1;

			} else {
				for ( err = 1; err > 0; ) {
					struct timeval	tv = { 0, 100000 };
					LDAPMessage	*res = NULL;

					switch ( ldap_result( ld, msgid, LDAP_MSG_ALL, &tv, &res ) ) {
					case -1:
						err = -1;
						break;

					case 0:
#ifdef LDAP_R_COMPILE
						ldap_pvt_thread_yield();
#endif
						break;

					case LDAP_RES_BIND:
						rc = ldap_parse_result( ld, res, &err, NULL, NULL, NULL, NULL, 1 );
						if ( rc != LDAP_SUCCESS ) {
							err = -1;

						} else if ( err != LDAP_SUCCESS ) {
							err = -1;
						}
						/* else err == LDAP_SUCCESS == 0 */
						break;

					default:
						Debug( LDAP_DEBUG_TRACE,
							"ldap_new_connection %p: "
							"unexpected response %d "
							"from BIND request id=%d\n",
							(void *) ld, ldap_msgtype( res ), msgid );
						err = -1;
						break;
					}
				}
			}
			LDAP_RES_LOCK_IF(m_res);
			LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
			LDAP_REQ_LOCK_IF(m_req);
			ld->ld_defconn = savedefconn;
			--lc->lconn_refcnt;

			if ( err != 0 ) {
				ldap_free_connection( ld, lc, 1, 0 );
				lc = NULL;
			}
		}
		if ( lc != NULL )
			lc->lconn_rebind_inprogress = 0;
	}
	return( lc );
}
Пример #26
0
/*
 * call-seq:
 *    OpenLDAP.split_url( str )   -> array
 *
 * Split an LDAP URL into an array of its parts:
 * - uri_scheme
 * - host
 * - port
 * - base
 * - attrs
 * - scope
 * - filter
 * - exts
 * - crit_exts
 */
static VALUE
ropenldap_s_split_url( VALUE UNUSED(module), VALUE urlstring )
{
	const char *url = StringValueCStr( urlstring );
	LDAPURLDesc *urldesc;
	VALUE rval = Qnil, obj = Qnil;

	if ( !ldap_is_ldap_url(url) )
		rb_raise( rb_eArgError, "Not an LDAP URL." );

	/* Parse the URL */
	if ( ldap_url_parse(url, &urldesc) != 0 )
		rb_raise( rb_eRuntimeError, "Error parsing %s as an LDAP URL!", url );

	rval = rb_ary_new2( 9 );

	/* Scheme */
	if ( urldesc->lud_scheme ) {
		ropenldap_log( "debug", "  parsed scheme: %s", urldesc->lud_scheme );
		obj = rb_str_new2( urldesc->lud_scheme );
		OBJ_INFECT( obj, urlstring );
		rb_ary_store( rval, 0L, obj );
	}

	/* LDAP host to contact */
	if ( urldesc->lud_host ) {
		ropenldap_log( "debug", "  parsed host: %s", urldesc->lud_host );
		obj = rb_str_new2( urldesc->lud_host );
		OBJ_INFECT( obj, urlstring );
		rb_ary_store( rval, 1L, obj );
	}

	/* Port */
	rb_ary_store( rval, 2L, INT2FIX(urldesc->lud_port) );

	/* Base DN */
	if ( urldesc->lud_dn ) {
		ropenldap_log( "debug", "  parsed DN: %s", urldesc->lud_dn );
		obj = rb_str_new2( urldesc->lud_dn );
		OBJ_INFECT( obj, urlstring );
		rb_ary_store( rval, 3L, obj );
	}

	/* Attributes */
	rb_ary_store( rval, 4L, ropenldap_rb_string_array(urldesc->lud_attrs) );

	/* Numeric scope (LDAP_SCOPE_*) */
	rb_ary_store( rval, 5L, INT2FIX(urldesc->lud_scope) );

	/* Filter */
	if ( urldesc->lud_filter ) {
		ropenldap_log( "debug", "  parsed filter: %s", urldesc->lud_filter );
		obj = rb_str_new2( urldesc->lud_filter );
		OBJ_INFECT( obj, urlstring );
		rb_ary_store( rval, 6L, obj );
	}

	/* lists of LDAP extensions */
	rb_ary_store( rval, 7L, ropenldap_rb_string_array(urldesc->lud_exts) );

	/* Critical extension/s flag */
	rb_ary_store( rval, 8L, urldesc->lud_crit_exts ? Qtrue : Qfalse );

	ldap_free_urldesc( urldesc );

	return rval;
}
Пример #27
0
BerVarray referral_rewrite(
	BerVarray in,
	struct berval *base,
	struct berval *target,
	int scope )
{
	int		i;
	BerVarray	refs;
	struct berval	*iv, *jv;

	if ( in == NULL ) {
		return NULL;
	}

	for ( i = 0; !BER_BVISNULL( &in[i] ); i++ ) {
		/* just count them */
	}

	if ( i < 1 ) {
		return NULL;
	}

	refs = ch_malloc( ( i + 1 ) * sizeof( struct berval ) );

	for ( iv = in, jv = refs; !BER_BVISNULL( iv ); iv++ ) {
		LDAPURLDesc	*url;
		char		*dn;
		int		rc;
		
		rc = ldap_url_parse_ext( iv->bv_val, &url, LDAP_PVT_URL_PARSE_NONE );
		if ( rc == LDAP_URL_ERR_BADSCHEME ) {
			ber_dupbv( jv++, iv );
			continue;

		} else if ( rc != LDAP_URL_SUCCESS ) {
			continue;
		}

		dn = url->lud_dn;
		url->lud_dn = referral_dn_muck( ( dn && *dn ) ? dn : NULL,
				base, target );
		ldap_memfree( dn );

		if ( url->lud_scope == LDAP_SCOPE_DEFAULT ) {
			url->lud_scope = scope;
		}

		jv->bv_val = ldap_url_desc2str( url );
		if ( jv->bv_val != NULL ) {
			jv->bv_len = strlen( jv->bv_val );

		} else {
			ber_dupbv( jv, iv );
		}
		jv++;

		ldap_free_urldesc( url );
	}

	if ( jv == refs ) {
		ch_free( refs );
		refs = NULL;

	} else {
		BER_BVZERO( jv );
	}

	return refs;
}
Пример #28
0
int
rewrite_xmap_destroy(
		struct rewrite_map **pmap
)
{
	struct rewrite_map *map;

	assert( pmap != NULL );
	assert( *pmap != NULL );

	map = *pmap;

	switch ( map->lm_type ) {
	case REWRITE_MAP_XPWDMAP:
#ifdef USE_REWRITE_LDAP_PVT_THREADS
		--xpasswd_mutex_init;
		if ( !xpasswd_mutex_init ) {
			ldap_pvt_thread_mutex_destroy( &xpasswd_mutex );
		}
#endif /* USE_REWRITE_LDAP_PVT_THREADS */

		break;

	case REWRITE_MAP_XFILEMAP:
#ifdef USE_REWRITE_LDAP_PVT_THREADS
		ldap_pvt_thread_mutex_lock( &map->lm_mutex );
#endif /* USE_REWRITE_LDAP_PVT_THREADS */

		if ( map->lm_args ) {
			fclose( ( FILE * )map->lm_args );
			map->lm_args = NULL;
		}

#ifdef USE_REWRITE_LDAP_PVT_THREADS
		ldap_pvt_thread_mutex_unlock( &map->lm_mutex );
		ldap_pvt_thread_mutex_destroy( &map->lm_mutex );
#endif /* USE_REWRITE_LDAP_PVT_THREADS */
		break;

	case REWRITE_MAP_XLDAPMAP:
#ifdef USE_REWRITE_LDAP_PVT_THREADS
		ldap_pvt_thread_mutex_lock( &map->lm_mutex );
#endif /* USE_REWRITE_LDAP_PVT_THREADS */

		if ( map->lm_args ) {
			ldap_free_urldesc( ( LDAPURLDesc * )map->lm_args );
			map->lm_args = NULL;
		}

#ifdef USE_REWRITE_LDAP_PVT_THREADS
		ldap_pvt_thread_mutex_unlock( &map->lm_mutex );
		ldap_pvt_thread_mutex_destroy( &map->lm_mutex );
#endif /* USE_REWRITE_LDAP_PVT_THREADS */
		break;

	default:
		break;

	}

	free( map->lm_name );
	free( map );
	*pmap = NULL;

	return 0;
}
Пример #29
0
/*
 * Map parsing
 * NOTE: these are old-fashion maps; new maps will be parsed on separate
 * config lines, and referred by name.
 */
struct rewrite_map *
rewrite_xmap_parse(
		struct rewrite_info *info,
		const char *s,
		const char **currpos
)
{
	struct rewrite_map *map;

	assert( info != NULL );
	assert( s != NULL );
	assert( currpos != NULL );

	Debug( LDAP_DEBUG_ARGS, "rewrite_xmap_parse: %s\n%s%s",
			s, "", "" );

	*currpos = NULL;

	map = calloc( sizeof( struct rewrite_map ), 1 );
	if ( map == NULL ) {
		Debug( LDAP_DEBUG_ANY, "rewrite_xmap_parse:"
				" calloc failed\n%s%s%s", "", "", "" );
		return NULL;
	}

	/*
	 * Experimental passwd map:
	 * replaces the uid with the matching gecos from /etc/passwd file 
	 */
	if ( strncasecmp(s, "xpasswd", 7 ) == 0 ) {
		map->lm_type = REWRITE_MAP_XPWDMAP;
		map->lm_name = strdup( "xpasswd" );
		if ( map->lm_name == NULL ) {
			free( map );
			return NULL;
		}

		assert( s[7] == '}' );
		*currpos = s + 8;

#ifdef USE_REWRITE_LDAP_PVT_THREADS
		if ( !xpasswd_mutex_init ) {
			if ( ldap_pvt_thread_mutex_init( &xpasswd_mutex ) ) {
				free( map );
				return NULL;
			}
		}
		++xpasswd_mutex_init;
#endif /* USE_REWRITE_LDAP_PVT_THREADS */

		/* Don't really care if fails */
		return map;
	
	/*
	 * Experimental file map:
	 * looks up key in a `key value' ascii file
	 */
	} else if ( strncasecmp( s, "xfile", 5 ) == 0 ) {
		char *filename;
		const char *p;
		int l;
		int c = 5;
		
		map->lm_type = REWRITE_MAP_XFILEMAP;
		
		if ( s[ c ] != '(' ) {
			free( map );
			return NULL;
		}

		/* Must start with '/' for security concerns */
		c++;
		if ( s[ c ] != '/' ) {
			free( map );
			return NULL;
		}

		for ( p = s + c; p[ 0 ] != '\0' && p[ 0 ] != ')'; p++ );
		if ( p[ 0 ] != ')' ) {
			free( map );
			return NULL;
		}

		l = p - s - c;
		filename = calloc( sizeof( char ), l + 1 );
		if ( filename == NULL ) {
			free( map );
			return NULL;
		}
		AC_MEMCPY( filename, s + c, l );
		filename[ l ] = '\0';
		
		map->lm_args = ( void * )fopen( filename, "r" );
		free( filename );

		if ( map->lm_args == NULL ) {
			free( map );
			return NULL;
		}

		*currpos = p + 1;

#ifdef USE_REWRITE_LDAP_PVT_THREADS
                if ( ldap_pvt_thread_mutex_init( &map->lm_mutex ) ) {
			fclose( ( FILE * )map->lm_args );
			free( map );
			return NULL;
		}
#endif /* USE_REWRITE_LDAP_PVT_THREADS */	
		
		return map;

	/*
         * Experimental ldap map:
         * looks up key on the fly (not implemented!)
         */
        } else if ( strncasecmp(s, "xldap", 5 ) == 0 ) {
		char *p;
		char *url;
		int l, rc;
		int c = 5;
		LDAPURLDesc *lud;

		if ( s[ c ] != '(' ) {
			free( map );
			return NULL;
		}
		c++;
		
		p = strchr( s, '}' );
		if ( p == NULL ) {
			free( map );
			return NULL;
		}
		p--;

		*currpos = p + 2;
	
		/*
		 * Add two bytes for urlencoding of '%s'
		 */
		l = p - s - c;
		url = calloc( sizeof( char ), l + 3 );
		if ( url == NULL ) {
			free( map );
			return NULL;
		}
		AC_MEMCPY( url, s + c, l );
		url[ l ] = '\0';

		/*
		 * Urlencodes the '%s' for ldap_url_parse
		 */
		p = strchr( url, '%' );
		if ( p != NULL ) {
			AC_MEMCPY( p + 3, p + 1, strlen( p + 1 ) + 1 );
			p[ 1 ] = '2';
			p[ 2 ] = '5';
		}

		rc =  ldap_url_parse( url, &lud );
		free( url );

		if ( rc != LDAP_SUCCESS ) {
			free( map );
			return NULL;
		}
		assert( lud != NULL );

		map->lm_args = ( void * )lud;
		map->lm_type = REWRITE_MAP_XLDAPMAP;

#ifdef USE_REWRITE_LDAP_PVT_THREADS
                if ( ldap_pvt_thread_mutex_init( &map->lm_mutex ) ) {
			ldap_free_urldesc( lud );
			free( map );
			return NULL;
		}
#endif /* USE_REWRITE_LDAP_PVT_THREADS */

		return map;
	
	/* Unhandled map */
	}

	free( map );
	return NULL;
}
Пример #30
0
/*
 * 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 );
}