Ejemplo n.º 1
0
/**
 * Handle APR_LDAP_OPT_TLS
 *
 * This function sets the type of TLS to be applied to this connection.
 * The options are:
 * APR_LDAP_NONE: no encryption
 * APR_LDAP_SSL: SSL encryption (ldaps://)
 * APR_LDAP_STARTTLS: STARTTLS encryption
 * APR_LDAP_STOPTLS: Stop existing TLS connecttion
 */
static void option_set_tls(apr_pool_t *pool, LDAP *ldap, const void *invalue,
                          apr_ldap_err_t *result)
{
#if APR_HAS_LDAP_SSL /* compiled with ssl support */

    int tls = * (const int *)invalue;

    /* Netscape/Mozilla/Solaris SDK */
#if APR_HAS_NETSCAPE_LDAPSDK || APR_HAS_SOLARIS_LDAPSDK || APR_HAS_MOZILLA_LDAPSK
#if APR_HAS_LDAPSSL_INSTALL_ROUTINES
    if (tls == APR_LDAP_SSL) {
        result->rc = ldapssl_install_routines(ldap);
#ifdef LDAP_OPT_SSL
        /* apparently Netscape and Mozilla need this too, Solaris doesn't */
        if (result->rc == LDAP_SUCCESS) {
            result->rc = ldap_set_option(ldap, LDAP_OPT_SSL, LDAP_OPT_ON);
        }
#endif
        if (result->rc != LDAP_SUCCESS) {
            result->msg = ldap_err2string(result->rc);
            result->reason = "LDAP: Could not switch SSL on for this "
                             "connection.";
        }
    }
    else if (tls == APR_LDAP_STARTTLS) {
        result->reason = "LDAP: STARTTLS is not supported by the "
                         "Netscape/Mozilla/Solaris SDK";
        result->rc = -1;
    }
    else if (tls == APR_LDAP_STOPTLS) {
        result->reason = "LDAP: STOPTLS is not supported by the "
                         "Netscape/Mozilla/Solaris SDK";
        result->rc = -1;
    }
#else
    if (tls != APR_LDAP_NONE) {
        result->reason = "LDAP: SSL/TLS is not supported by this version "
                         "of the Netscape/Mozilla/Solaris SDK";
        result->rc = -1;
    }
#endif
#endif

    /* Novell SDK */
#if APR_HAS_NOVELL_LDAPSDK
    /* ldapssl_install_routines(ldap)
     * Behavior is unpredictable when other LDAP functions are called
     * between the ldap_init function and the ldapssl_install_routines
     * function.
     * 
     * STARTTLS is supported by the ldap_start_tls_s() method
     */
    if (tls == APR_LDAP_SSL) {
        result->rc = ldapssl_install_routines(ldap);
        if (result->rc != LDAP_SUCCESS) {
            result->msg = ldap_err2string(result->rc);
            result->reason = "LDAP: Could not switch SSL on for this "
                             "connection.";
        }
    }
    if (tls == APR_LDAP_STARTTLS) {
        result->rc = ldapssl_start_tls(ldap);
        if (result->rc != LDAP_SUCCESS) {
            result->msg = ldap_err2string(result->rc);
            result->reason = "LDAP: Could not start TLS on this connection";
        }
    }
    else if (tls == APR_LDAP_STOPTLS) {
        result->rc = ldapssl_stop_tls(ldap);
        if (result->rc != LDAP_SUCCESS) {
            result->msg = ldap_err2string(result->rc);
            result->reason = "LDAP: Could not stop TLS on this connection";
        }
    }
#endif

    /* OpenLDAP SDK */
#if APR_HAS_OPENLDAP_LDAPSDK
#ifdef LDAP_OPT_X_TLS
    if (tls == APR_LDAP_SSL) {
        int SSLmode = LDAP_OPT_X_TLS_HARD;
        result->rc = ldap_set_option(ldap, LDAP_OPT_X_TLS, &SSLmode);
        if (result->rc != LDAP_SUCCESS) {
            result->reason = "LDAP: ldap_set_option failed. "
                             "Could not set LDAP_OPT_X_TLS to "
                             "LDAP_OPT_X_TLS_HARD";
            result->msg = ldap_err2string(result->rc);
        }   
    }
    else if (tls == APR_LDAP_STARTTLS) {
        result->rc = ldap_start_tls_s(ldap, NULL, NULL);
        if (result->rc != LDAP_SUCCESS) {
            result->reason = "LDAP: ldap_start_tls_s() failed";
            result->msg = ldap_err2string(result->rc);
        }
    }
    else if (tls == APR_LDAP_STOPTLS) {
        result->reason = "LDAP: STOPTLS is not supported by the "
                         "OpenLDAP SDK";
        result->rc = -1;
    }
#else
    if (tls != APR_LDAP_NONE) {
        result->reason = "LDAP: SSL/TLS not yet supported by APR on this "
                         "version of the OpenLDAP toolkit";
        result->rc = -1;
    }
#endif
#endif

    /* Microsoft SDK */
#if APR_HAS_MICROSOFT_LDAPSDK
    if (tls == APR_LDAP_NONE) {
        ULONG ul = (ULONG) LDAP_OPT_OFF;
        result->rc = ldap_set_option(ldap, LDAP_OPT_SSL, &ul);
        if (result->rc != LDAP_SUCCESS) {
            result->reason = "LDAP: an attempt to set LDAP_OPT_SSL off "
                             "failed.";
            result->msg = ldap_err2string(result->rc);
        }
    }
    else if (tls == APR_LDAP_SSL) {
        ULONG ul = (ULONG) LDAP_OPT_ON;
        result->rc = ldap_set_option(ldap, LDAP_OPT_SSL, &ul);
        if (result->rc != LDAP_SUCCESS) {
            result->reason = "LDAP: an attempt to set LDAP_OPT_SSL on "
                             "failed.";
            result->msg = ldap_err2string(result->rc);
        }
    }
#if APR_HAS_LDAP_START_TLS_S
    else if (tls == APR_LDAP_STARTTLS) {
        result->rc = ldap_start_tls_s(ldap, NULL, NULL, NULL, NULL);
        if (result->rc != LDAP_SUCCESS) {
            result->reason = "LDAP: ldap_start_tls_s() failed";
            result->msg = ldap_err2string(result->rc);
        }
    }
    else if (tls == APR_LDAP_STOPTLS) {
        result->rc = ldap_stop_tls_s(ldap);
        if (result->rc != LDAP_SUCCESS) {
            result->reason = "LDAP: ldap_stop_tls_s() failed";
            result->msg = ldap_err2string(result->rc);
        }
    }
#endif
#endif

#if APR_HAS_OTHER_LDAPSDK
    if (tls != APR_LDAP_NONE) {
        result->reason = "LDAP: SSL/TLS is currently not supported by "
                         "APR on this LDAP SDK";
        result->rc = -1;
    }
#endif

#endif /* APR_HAS_LDAP_SSL */

}
Ejemplo n.º 2
0
/*
 * Do an LDAP lookup to the server described in the info argument.
 *
 * Args      info -- LDAP info for server.
 *         string -- String to lookup.
 *           cust -- Possible custom filter description.
 *         wp_err -- We set this is we get a white pages error.
 *  name_in_error -- Caller sets this if they want us to include the server
 *                   name in error messages.
 *
 * Returns  Results of lookup, NULL if lookup failed.
 */
LDAP_SERV_RES_S *
ldap_lookup(LDAP_SERV_S *info, char *string, CUSTOM_FILT_S *cust,
	    WP_ERR_S *wp_err, int name_in_error)
{
    char     ebuf[900];
    char     buf[900];
    char    *serv, *base, *serv_errstr;
    char    *mailattr, *snattr, *gnattr, *cnattr;
    int      we_cancel = 0, we_turned_on = 0;
    LDAP_SERV_RES_S *serv_res = NULL;
    LDAP *ld;
    long  pwdtrial = 0L;
    int   ld_errnum;
    char *ld_errstr;


    if(!info)
      return(serv_res);

    serv = cpystr((info->serv && *info->serv) ? info->serv : "?");

    if(name_in_error)
      snprintf(ebuf, sizeof(ebuf), " (%s)",
	      (info->nick && *info->nick) ? info->nick : serv);
    else
      ebuf[0] = '\0';

    serv_errstr = cpystr(ebuf);
    base = cpystr(info->base ? info->base : "");

    if(info->port < 0)
      info->port = LDAP_PORT;

    if(info->type < 0)
      info->type = DEF_LDAP_TYPE;

    if(info->srch < 0)
      info->srch = DEF_LDAP_SRCH;
	
    if(info->time < 0)
      info->time = DEF_LDAP_TIME;

    if(info->size < 0)
      info->size = DEF_LDAP_SIZE;

    if(info->scope < 0)
      info->scope = DEF_LDAP_SCOPE;

    mailattr = (info->mailattr && info->mailattr[0]) ? info->mailattr
						     : DEF_LDAP_MAILATTR;
    snattr = (info->snattr && info->snattr[0]) ? info->snattr
						     : DEF_LDAP_SNATTR;
    gnattr = (info->gnattr && info->gnattr[0]) ? info->gnattr
						     : DEF_LDAP_GNATTR;
    cnattr = (info->cnattr && info->cnattr[0]) ? info->cnattr
						     : DEF_LDAP_CNATTR;

    /*
     * We may want to keep ldap handles open, but at least for
     * now, re-open them every time.
     */

    dprint((3, "ldap_lookup(%s,%d)\n", serv ? serv : "?", info->port));

    snprintf(ebuf, sizeof(ebuf), "Searching%s%s%s on %s",
	    (string && *string) ? " for \"" : "",
	    (string && *string) ? string : "",
	    (string && *string) ? "\"" : "",
	    serv);
    we_turned_on = intr_handling_on();		/* this erases keymenu */
    we_cancel = busy_cue(ebuf, NULL, 0);
    if(wp_err->mangled)
      *(wp_err->mangled) = 1;

#ifdef _SOLARIS_SDK
    if(info->tls || info->tlsmust)
      ldapssl_client_init(NULL, NULL);
    if((ld = ldap_init(serv, info->port)) == NULL)
#else
#if (LDAPAPI >= 11)
    if((ld = ldap_init(serv, info->port)) == NULL)
#else
    if((ld = ldap_open(serv, info->port)) == NULL)
#endif
#endif
    {
      /* TRANSLATORS: All of the three args together are an error message */
      snprintf(ebuf, sizeof(ebuf), _("Access to LDAP server failed: %s%s(%s)"),
	      errno ? error_description(errno) : "",
	      errno ? " " : "",
	      serv);
      wp_err->wp_err_occurred = 1;
      if(wp_err->error)
	fs_give((void **)&wp_err->error);

      wp_err->error = cpystr(ebuf);
      if(we_cancel)
        cancel_busy_cue(-1);

      q_status_message(SM_ORDER, 3, 5, wp_err->error);
      display_message('x');
      dprint((2, "%s\n", ebuf));
    }
    else if(!ps_global->intr_pending){
      int proto = 3, tlsmustbail = 0;
      char pwd[NETMAXPASSWD], user[NETMAXUSER];
      char *passwd = NULL;
      char hostbuf[1024];
      NETMBX mb;
#ifndef _WINDOWS
      int rc;
#endif

      memset(&mb, 0, sizeof(mb));

#ifdef _SOLARIS_SDK
      if(info->tls || info->tlsmust)
	rc = ldapssl_install_routines(ld);
#endif

      if(ldap_v3_is_supported(ld) &&
	 our_ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &proto) == 0){
	dprint((5, "ldap: using version 3 protocol\n"));
      }

      /*
       * If we don't set RESTART then the select() waiting for the answer
       * in libldap will be interrupted and stopped by our busy_cue.
       */
      our_ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON);

      /*
       * If we need to authenticate, get the password. We are not
       * supporting SASL authentication, just LDAP simple.
       */
      if(info->binddn && info->binddn[0]){
	  char pmt[500];
	  char *space;

	  snprintf(hostbuf, sizeof(hostbuf), "{%s}dummy", info->serv ? info->serv : "?");

	  /*
	   * We don't handle multiple space-delimited hosts well.
	   * We don't know which we're asking for a password for.
	   * We're not connected yet so we can't know.
	   */
	  if((space=strindex(hostbuf, ' ')) != NULL)
	    *space = '\0';

	  mail_valid_net_parse_work(hostbuf, &mb, "ldap");
	  mb.port = info->port;
	  mb.tlsflag = (info->tls || info->tlsmust) ? 1 : 0;

try_password_again:

	  if(mb.tlsflag
	     && (pwdtrial > 0 || 
#ifndef _WINDOWS
#ifdef _SOLARIS_SDK
		 (rc == LDAP_SUCCESS)
#else /* !_SOLARIS_SDK */
		 ((rc=ldap_start_tls_s(ld, NULL, NULL)) == LDAP_SUCCESS)
#endif /* !_SOLARIS_SDK */
#else /* _WINDOWS */
		 0  /* TODO: find a way to do this in Windows */
#endif /* _WINDOWS */
		 ))
	    mb.tlsflag = 1;
	  else
	    mb.tlsflag = 0;

	  if((info->tls || info->tlsmust) && !mb.tlsflag){
	    q_status_message(SM_ORDER, 3, 5, "Not able to start TLS encryption for LDAP server");
	    if(info->tlsmust)
	      tlsmustbail++;
	  }

	  if(!tlsmustbail){
	      snprintf(pmt, sizeof(pmt), "  %s", (info->nick && *info->nick) ? info->nick : serv);
	      mm_login_work(&mb, user, pwd, pwdtrial, pmt, info->binddn);
	      if(pwd && pwd[0])
		passwd = pwd;
	  }
      }


      /*
       * LDAPv2 requires the bind. v3 doesn't require it but we want
       * to tell the server we're v3 if the server supports v3, and if the
       * server doesn't support v3 the bind is required.
       */
      if(tlsmustbail || ldap_simple_bind_s(ld, info->binddn, passwd) != LDAP_SUCCESS){
	wp_err->wp_err_occurred = 1;

	ld_errnum = our_ldap_get_lderrno(ld, NULL, &ld_errstr);

        if(!tlsmustbail && info->binddn && info->binddn[0] && pwdtrial < 2L
	   && ld_errnum == LDAP_INVALID_CREDENTIALS){
	  pwdtrial++;
          q_status_message(SM_ORDER, 3, 5, _("Invalid password"));
	  goto try_password_again;
	}

	snprintf(ebuf, sizeof(ebuf), _("LDAP server failed: %s%s%s%s"),
		ldap_err2string(ld_errnum),
		serv_errstr,
		(ld_errstr && *ld_errstr) ? ": " : "",
		(ld_errstr && *ld_errstr) ? ld_errstr : "");

        if(wp_err->error)
	  fs_give((void **)&wp_err->error);

        if(we_cancel)
          cancel_busy_cue(-1);

	ldap_unbind(ld);
        wp_err->error = cpystr(ebuf);
        q_status_message(SM_ORDER, 3, 5, wp_err->error);
        display_message('x');
	dprint((2, "%s\n", ebuf));
      }
      else if(!ps_global->intr_pending){
	int          srch_res, args, slen, flen;
#define TEMPLATELEN 512
	char         filt_template[TEMPLATELEN + 1];
	char         filt_format[2*TEMPLATELEN + 1];
	char         filter[2*TEMPLATELEN + 1];
	char         scp[2*TEMPLATELEN + 1];
	char        *p, *q;
	LDAPMessage *res = NULL;
	int intr_happened = 0;
	int tl;

	tl = (info->time == 0) ? info->time : info->time + 10;

	our_ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &tl);
	our_ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &info->size);

	/*
	 * If a custom filter has been passed in and it doesn't include a
	 * request to combine it with the configured filter, then replace
	 * any configured filter with the passed in filter.
	 */
	if(cust && cust->filt && !cust->combine){
	    if(info->cust)
	      fs_give((void **)&info->cust);
	    
	    info->cust = cpystr(cust->filt);
	}

	if(info->cust && *info->cust){	/* use custom filter if present */
	    strncpy(filt_template, info->cust, sizeof(filt_template));
	    filt_template[sizeof(filt_template)-1] = '\0';
	}
	else{				/* else use configured filter */
	    switch(info->type){
	      case LDAP_TYPE_SUR:
		snprintf(filt_template, sizeof(filt_template), "(%s=%%s)", snattr);
		break;
	      case LDAP_TYPE_GIVEN:
		snprintf(filt_template, sizeof(filt_template), "(%s=%%s)", gnattr);
		break;
	      case LDAP_TYPE_EMAIL:
		snprintf(filt_template, sizeof(filt_template), "(%s=%%s)", mailattr);
		break;
	      case LDAP_TYPE_CN_EMAIL:
		snprintf(filt_template, sizeof(filt_template), "(|(%s=%%s)(%s=%%s))", cnattr,
			mailattr);
		break;
	      case LDAP_TYPE_SUR_GIVEN:
		snprintf(filt_template, sizeof(filt_template), "(|(%s=%%s)(%s=%%s))",
			snattr, gnattr);
		break;
	      case LDAP_TYPE_SEVERAL:
		snprintf(filt_template, sizeof(filt_template),
			"(|(%s=%%s)(%s=%%s)(%s=%%s)(%s=%%s))",
			cnattr, mailattr, snattr, gnattr);
		break;
	      default:
	      case LDAP_TYPE_CN:
		snprintf(filt_template, sizeof(filt_template), "(%s=%%s)", cnattr);
		break;
	    }
	}

	/* just copy if custom */
	if(info->cust && *info->cust)
	  info->srch = LDAP_SRCH_EQUALS;

	p = filt_template;
	q = filt_format;
	memset((void *)filt_format, 0, sizeof(filt_format));
	args = 0;
	while(*p && (q - filt_format) + 4 < sizeof(filt_format)){
	    if(*p == '%' && *(p+1) == 's'){
		args++;
		switch(info->srch){
		  /* Exact match */
		  case LDAP_SRCH_EQUALS:
		    *q++ = *p++;
		    *q++ = *p++;
		    break;

		  /* Append wildcard after %s */
		  case LDAP_SRCH_BEGINS:
		    *q++ = *p++;
		    *q++ = *p++;
		    *q++ = '*';
		    break;

		  /* Insert wildcard before %s */
		  case LDAP_SRCH_ENDS:
		    *q++ = '*';
		    *q++ = *p++;
		    *q++ = *p++;
		    break;

		  /* Put wildcard before and after %s */
		  default:
		  case LDAP_SRCH_CONTAINS:
		    *q++ = '*';
		    *q++ = *p++;
		    *q++ = *p++;
		    *q++ = '*';
		    break;
		}
	    }
	    else
	      *q++ = *p++;
	}

	if(q - filt_format < sizeof(filt_format))
	  *q = '\0';

	filt_format[sizeof(filt_format)-1] = '\0';

	/*
	 * If combine is lit we put the custom filter and the filt_format
	 * filter and combine them with an &.
	 */
	if(cust && cust->filt && cust->combine){
	    char *combined;
	    size_t l;

	    l = strlen(filt_format) + strlen(cust->filt) + 3;
	    combined = (char *) fs_get((l+1) * sizeof(char));
	    snprintf(combined, l+1, "(&%s%s)", cust->filt, filt_format);
	    strncpy(filt_format, combined, sizeof(filt_format));
	    filt_format[sizeof(filt_format)-1] = '\0';
	    fs_give((void **) &combined);
	}

	/*
	 * Ad hoc attempt to make "Steve Hubert" match
	 * Steven Hubert but not Steven Shubert.
	 * We replace a <SPACE> with * <SPACE> (not * <SPACE> *).
	 */
	memset((void *)scp, 0, sizeof(scp));
	if(info->nosub)
	  strncpy(scp, string, sizeof(scp));
	else{
	    p = string;
	    q = scp;
	    while(*p && (q - scp) + 1 < sizeof(scp)){
		if(*p == SPACE && *(p+1) != SPACE){
		    *q++ = '*';
		    *q++ = *p++;
		}
		else
		  *q++ = *p++;
	    }
	}

	scp[sizeof(scp)-1] = '\0';

	slen = strlen(scp);
	flen = strlen(filt_format);
	/* truncate string if it will overflow filter */
	if(args*slen + flen - 2*args > sizeof(filter)-1)
	  scp[(sizeof(filter)-1 - flen)/args] = '\0';

	/*
	 * Replace %s's with scp.
	 */
	switch(args){
	  case 0:
	    snprintf(filter, sizeof(filter), "%s", filt_format);
	    break;
	  case 1:
	    snprintf(filter, sizeof(filter), filt_format, scp);
	    break;
	  case 2:
	    snprintf(filter, sizeof(filter), filt_format, scp, scp);
	    break;
	  case 3:
	    snprintf(filter, sizeof(filter), filt_format, scp, scp, scp);
	    break;
	  case 4:
	    snprintf(filter, sizeof(filter), filt_format, scp, scp, scp, scp);
	    break;
	  case 5:
	    snprintf(filter, sizeof(filter), filt_format, scp, scp, scp, scp, scp);
	    break;
	  case 6:
	    snprintf(filter, sizeof(filter), filt_format, scp, scp, scp, scp, scp, scp);
	    break;
	  case 7:
	    snprintf(filter, sizeof(filter), filt_format, scp, scp, scp, scp, scp, scp, scp);
	    break;
	  case 8:
	    snprintf(filter, sizeof(filter), filt_format, scp, scp, scp, scp, scp, scp, scp,
		    scp);
	    break;
	  case 9:
	    snprintf(filter, sizeof(filter), filt_format, scp, scp, scp, scp, scp, scp, scp,
		    scp, scp);
	    break;
	  case 10:
	  default:
	    snprintf(filter, sizeof(filter), filt_format, scp, scp, scp, scp, scp, scp, scp,
		    scp, scp, scp);
	    break;
	}

	/* replace double *'s with single *'s in filter */
	for(p = q = filter; *p; p++)
	  if(*p != '*' || p == filter || *(p-1) != '*')
	    *q++ = *p;

	*q = '\0';

	(void) removing_double_quotes(base);
	dprint((5, "about to ldap_search(\"%s\", %s)\n",
	       base ? base : "?", filter ? filter : "?"));
        if(ps_global->intr_pending)
	  srch_res = LDAP_PROTOCOL_ERROR;
	else{
	  int msgid;
	  time_t start_time;

	  start_time = time((time_t *)0);

	  dprint((6, "ldap_lookup: calling ldap_search\n"));
	  msgid = ldap_search(ld, base, info->scope, filter, NULL, 0);

	  if(msgid == -1)
	    srch_res = our_ldap_get_lderrno(ld, NULL, NULL);
	  else{
	    int lres;
	    /*
	     * Warning: struct timeval is not portable. However, since it is
	     * part of LDAP api it must be portable to all platforms LDAP
	     * has been ported to.
	     */
	    struct timeval t;

	    t.tv_sec  = 1; t.tv_usec = 0;
	      
	    do {
	      if(ps_global->intr_pending)
		intr_happened = 1;

	      dprint((6, "ldap_result(id=%d): ", msgid));
	      if((lres=ldap_result(ld, msgid, LDAP_MSG_ALL, &t, &res)) == -1){
	        /* error */
		srch_res = our_ldap_get_lderrno(ld, NULL, NULL);
	        dprint((6, "error (-1 returned): ld_errno=%d\n",
			   srch_res));
	      }
	      else if(lres == 0){  /* timeout, no results available */
		if(intr_happened){
		  ldap_abandon(ld, msgid);
		  srch_res = LDAP_PROTOCOL_ERROR;
		  if(our_ldap_get_lderrno(ld, NULL, NULL) == LDAP_SUCCESS)
		    our_ldap_set_lderrno(ld, LDAP_PROTOCOL_ERROR, NULL, NULL);

	          dprint((6, "timeout, intr: srch_res=%d\n",
			     srch_res));
		}
		else if(info->time > 0 &&
			((long)time((time_t *)0) - start_time) > info->time){
		  /* try for partial results */
		  t.tv_sec  = 0; t.tv_usec = 0;
		  lres = ldap_result(ld, msgid, LDAP_MSG_RECEIVED, &t, &res);
		  if(lres > 0 && lres != LDAP_RES_SEARCH_RESULT){
		    srch_res = LDAP_SUCCESS;
		    dprint((6, "partial result: lres=0x%x\n", lres));
		  }
		  else{
		    if(lres == 0)
		      ldap_abandon(ld, msgid);

		    srch_res = LDAP_TIMEOUT;
		    if(our_ldap_get_lderrno(ld, NULL, NULL) == LDAP_SUCCESS)
		      our_ldap_set_lderrno(ld, LDAP_TIMEOUT, NULL, NULL);

	            dprint((6,
			       "timeout, total_time (%d), srch_res=%d\n",
			       info->time, srch_res));
		  }
		}
		else{
	          dprint((6, "timeout\n"));
		}
	      }
	      else{
		srch_res = ldap_result2error(ld, res, 0);
	        dprint((6, "lres=0x%x, srch_res=%d\n", lres,
			   srch_res));
	      }
	    }while(lres == 0 &&
		    !(intr_happened ||
		      (info->time > 0 &&
		       ((long)time((time_t *)0) - start_time) > info->time)));
	  }
	}

	if(intr_happened){
	  wp_exit = 1;
          if(we_cancel)
            cancel_busy_cue(-1);

	  if(wp_err->error)
	    fs_give((void **)&wp_err->error);
	  else{
	    q_status_message(SM_ORDER, 0, 1, "Interrupt");
	    display_message('x');
	    fflush(stdout);
	  }

	  if(res)
	    ldap_msgfree(res);
	  if(ld)
	    ldap_unbind(ld);
	  
	  res = NULL; ld  = NULL;
	}
	else if(srch_res != LDAP_SUCCESS &&
	   srch_res != LDAP_TIMELIMIT_EXCEEDED &&
	   srch_res != LDAP_RESULTS_TOO_LARGE &&
	   srch_res != LDAP_TIMEOUT &&
	   srch_res != LDAP_SIZELIMIT_EXCEEDED){
	  wp_err->wp_err_occurred = 1;

	  ld_errnum = our_ldap_get_lderrno(ld, NULL, &ld_errstr);

	  snprintf(ebuf, sizeof(ebuf), _("LDAP search failed: %s%s%s%s"),
		  ldap_err2string(ld_errnum),
		  serv_errstr,
		  (ld_errstr && *ld_errstr) ? ": " : "",
		  (ld_errstr && *ld_errstr) ? ld_errstr : "");

          if(wp_err->error)
	    fs_give((void **)&wp_err->error);

          wp_err->error = cpystr(ebuf);
          if(we_cancel)
            cancel_busy_cue(-1);

          q_status_message(SM_ORDER, 3, 5, wp_err->error);
          display_message('x');
	  dprint((2, "%s\n", ebuf));
	  if(res)
	    ldap_msgfree(res);
	  if(ld)
	    ldap_unbind(ld);
	  
	  res = NULL; ld  = NULL;
	}
	else{
	  int cnt;

	  cnt = ldap_count_entries(ld, res);

	  if(cnt > 0){

	    if(srch_res == LDAP_TIMELIMIT_EXCEEDED ||
	       srch_res == LDAP_RESULTS_TOO_LARGE ||
	       srch_res == LDAP_TIMEOUT ||
	       srch_res == LDAP_SIZELIMIT_EXCEEDED){
	      wp_err->wp_err_occurred = 1;
	      ld_errnum = our_ldap_get_lderrno(ld, NULL, &ld_errstr);

	      snprintf(ebuf, sizeof(ebuf), _("LDAP partial results: %s%s%s%s"),
		      ldap_err2string(ld_errnum),
		      serv_errstr,
		      (ld_errstr && *ld_errstr) ? ": " : "",
		      (ld_errstr && *ld_errstr) ? ld_errstr : "");
	      dprint((2, "%s\n", ebuf));
	      if(wp_err->error)
		fs_give((void **)&wp_err->error);

	      wp_err->error = cpystr(ebuf);
	      if(we_cancel)
		cancel_busy_cue(-1);

	      q_status_message(SM_ORDER, 3, 5, wp_err->error);
	      display_message('x');
	    }

	    dprint((5, "Matched %d entries on %s\n",
	           cnt, serv ? serv : "?"));

	    serv_res = (LDAP_SERV_RES_S *)fs_get(sizeof(LDAP_SERV_RES_S));
	    memset((void *)serv_res, 0, sizeof(*serv_res));
	    serv_res->ld   = ld;
	    serv_res->res  = res;
	    serv_res->info_used = copy_ldap_serv_info(info);
	    /* Save by reference? */
	    if(info->ref){
		snprintf(buf, sizeof(buf), "%s:%s", serv, comatose(info->port));
		serv_res->serv = cpystr(buf);
	    }
	    else
	      serv_res->serv = NULL;

	    serv_res->next = NULL;
	  }
	  else{
	    if(srch_res == LDAP_TIMELIMIT_EXCEEDED ||
	       srch_res == LDAP_RESULTS_TOO_LARGE ||
	       srch_res == LDAP_TIMEOUT ||
	       srch_res == LDAP_SIZELIMIT_EXCEEDED){
	      wp_err->wp_err_occurred = 1;
	      wp_err->ldap_errno      = srch_res;

	      ld_errnum = our_ldap_get_lderrno(ld, NULL, &ld_errstr);

	      snprintf(ebuf, sizeof(ebuf), _("LDAP search failed: %s%s%s%s"),
		      ldap_err2string(ld_errnum),
		      serv_errstr,
		      (ld_errstr && *ld_errstr) ? ": " : "",
		      (ld_errstr && *ld_errstr) ? ld_errstr : "");

	      if(wp_err->error)
		fs_give((void **)&wp_err->error);

	      wp_err->error = cpystr(ebuf);
	      if(we_cancel)
		cancel_busy_cue(-1);

	      q_status_message(SM_ORDER, 3, 5, wp_err->error);
	      display_message('x');
	      dprint((2, "%s\n", ebuf));
	    }

	    dprint((5, "Matched 0 entries on %s\n",
		   serv ? serv : "?"));
	    if(res)
	      ldap_msgfree(res);
	    if(ld)
	      ldap_unbind(ld);

	    res = NULL; ld  = NULL;
	  }
	}
      }
    }

    if(we_cancel)
      cancel_busy_cue(-1);

    if(we_turned_on)
      intr_handling_off();

    if(serv)
      fs_give((void **)&serv);
    if(base)
      fs_give((void **)&base);
    if(serv_errstr)
      fs_give((void **)&serv_errstr);

    return(serv_res);
}