예제 #1
0
void nsldapi_handle_reconnect( LDAP *ld )
{

	LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_handle_reconnect\n", 0, 0, 0 );
	
	/*
	 * if the default connection has been lost and is now marked dead,
	 * dispose of the default connection so it will get re-established.
	 *
	 * if not, clear the bind DN and status to ensure that we don't
	 * report the wrong bind DN to a different thread while waiting
	 * for our bind result to return from the server.
	 */
	LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
	if ( NULL != ld->ld_defconn ) {
	    if ( LDAP_CONNST_DEAD == ld->ld_defconn->lconn_status ) {
			nsldapi_free_connection( ld, ld->ld_defconn, NULL, NULL, 1, 0 );
			ld->ld_defconn = NULL;
	    } else if ( ld->ld_defconn->lconn_binddn != NULL ) {
			NSLDAPI_FREE( ld->ld_defconn->lconn_binddn );
			ld->ld_defconn->lconn_binddn = NULL;
			ld->ld_defconn->lconn_bound = 0;
	    }
	}
	LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
}
예제 #2
0
파일: request.c 프로젝트: andreiw/polaris
void
nsldapi_free_request( LDAP *ld, LDAPRequest *lr, int free_conn )
{
	LDAPRequest	*tmplr, *nextlr;

	LDAPDebug( LDAP_DEBUG_TRACE,
		"nsldapi_free_request 0x%x (origid %d, msgid %d)\n",
		lr, lr->lr_origid, lr->lr_msgid );

	if ( lr->lr_parent != NULL ) {
		--lr->lr_parent->lr_outrefcnt;
	}

	/* free all of our spawned referrals (child requests) */
	for ( tmplr = lr->lr_child; tmplr != NULL; tmplr = nextlr ) {
		nextlr = tmplr->lr_sibling;
		nsldapi_free_request( ld, tmplr, free_conn );
	}

	if ( free_conn ) {
		nsldapi_free_connection( ld, lr->lr_conn, NULL, NULL, 0, 1 );
	}

	if ( lr->lr_prev == NULL ) {
		ld->ld_requests = lr->lr_next;
	} else {
		lr->lr_prev->lr_next = lr->lr_next;
	}

	if ( lr->lr_next != NULL ) {
		lr->lr_next->lr_prev = lr->lr_prev;
	}

	if ( lr->lr_ber != NULL ) {
		ber_free( lr->lr_ber, 1 );
	}

	if ( lr->lr_res_error != NULL ) {
		NSLDAPI_FREE( lr->lr_res_error );
	}

	if ( lr->lr_res_matched != NULL ) {
		NSLDAPI_FREE( lr->lr_res_matched );
	}

	if ( lr->lr_binddn != NULL ) {
		NSLDAPI_FREE( lr->lr_binddn );
	}
	NSLDAPI_FREE( lr );
}
예제 #3
0
파일: request.c 프로젝트: andreiw/polaris
LDAPConn *
nsldapi_new_connection( LDAP *ld, LDAPServer **srvlistp, int use_ldsb,
	int connect, int bind )
{
    int	rc;
    
	LDAPConn	*lc;
	LDAPServer	*prevsrv, *srv;
	Sockbuf		*sb = NULL;

	/*
	 * make a new LDAP server connection
	 */
	if (( lc = (LDAPConn *)NSLDAPI_CALLOC( 1, sizeof( LDAPConn ))) == NULL
	    || ( !use_ldsb && ( sb = ber_sockbuf_alloc()) == NULL )) {
		if ( lc != NULL ) {
			NSLDAPI_FREE( (char *)lc );
		}
		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
		return( NULL );
	}

	LDAP_MUTEX_LOCK( ld, LDAP_OPTION_LOCK );
	if ( !use_ldsb ) {
		/*
		 * we have allocated a new sockbuf
		 * set I/O routines to match those in default LDAP sockbuf
		 */
		IFP				sb_fn;
		struct lber_x_ext_io_fns	extiofns;
		
		extiofns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;

		if ( ber_sockbuf_get_option( ld->ld_sbp,
		    LBER_SOCKBUF_OPT_EXT_IO_FNS, &extiofns ) == 0 ) {
			ber_sockbuf_set_option( sb,
			    LBER_SOCKBUF_OPT_EXT_IO_FNS, &extiofns );
		}
		if ( ber_sockbuf_get_option( ld->ld_sbp,
		    LBER_SOCKBUF_OPT_READ_FN, (void *)&sb_fn ) == 0
		    && sb_fn != NULL ) {
			ber_sockbuf_set_option( sb, LBER_SOCKBUF_OPT_READ_FN,
			    (void *)sb_fn );
		}
		if ( ber_sockbuf_get_option( ld->ld_sbp,
		    LBER_SOCKBUF_OPT_WRITE_FN, (void *)&sb_fn ) == 0
		    && sb_fn != NULL ) {
			ber_sockbuf_set_option( sb, LBER_SOCKBUF_OPT_WRITE_FN,
			    (void *)sb_fn );
		}
	}

	lc->lconn_sb = ( use_ldsb ) ? ld->ld_sbp : sb;
	lc->lconn_version = ld->ld_version;	/* inherited */
	LDAP_MUTEX_UNLOCK( ld, LDAP_OPTION_LOCK );

	if ( connect ) {
		prevsrv = NULL;
        /* 
         * save the return code for later
         */ 
		for ( srv = *srvlistp; srv != NULL; srv = srv->lsrv_next ) {
			rc = nsldapi_connect_to_host( ld, lc->lconn_sb,
				   srv->lsrv_host, srv->lsrv_port,
			       (  srv->lsrv_options & LDAP_SRV_OPT_SECURE ) != 0,
					&lc->lconn_krbinstance );
			if (rc != -1) {
				break;
			}
			prevsrv = srv;
		}

		if ( srv == NULL ) {
		    if ( !use_ldsb ) {
			NSLDAPI_FREE( (char *)lc->lconn_sb );
		    }
		    NSLDAPI_FREE( (char *)lc );
		    /* nsldapi_open_ldap_connection has already set ld_errno */
		    return( NULL );
		}

		if ( prevsrv == NULL ) {
		    *srvlistp = srv->lsrv_next;
		} else {
		    prevsrv->lsrv_next = srv->lsrv_next;
		}
		lc->lconn_server = srv;
	}

	if (ld->ld_options & LDAP_BITOPT_ASYNC && rc == -2)
    {
        lc->lconn_status = LDAP_CONNST_CONNECTING;
    }
    else {
        lc->lconn_status = LDAP_CONNST_CONNECTED;
    }
    
	lc->lconn_next = ld->ld_conns;
	ld->ld_conns = lc;

	/*
	 * XXX for now, we always do a synchronous bind.  This will have
	 * to change in the long run...
	 */
	if ( bind ) {
		int		err, lderr, freepasswd, authmethod;
		char		*binddn, *passwd;
		LDAPConn	*savedefconn;

		freepasswd = err = 0;

		if ( ld->ld_rebind_fn == NULL ) {
			binddn = passwd = "";
			authmethod = LDAP_AUTH_SIMPLE;
		} else {
			if (( lderr = (*ld->ld_rebind_fn)( ld, &binddn, &passwd,
			    &authmethod, 0, ld->ld_rebind_arg ))
			    == LDAP_SUCCESS ) {
				freepasswd = 1;
			} else {
				LDAP_SET_LDERRNO( ld, lderr, NULL, NULL );
				err = -1;
			}
		}


		if ( err == 0 ) {
			savedefconn = ld->ld_defconn;
			ld->ld_defconn = lc;
			++lc->lconn_refcnt;	/* avoid premature free */

			/*
			 * when binding, we will back down as low as LDAPv2
			 * if we get back "protocol error" from bind attempts
			 */
			for ( ;; ) {
				/* LDAP_MUTEX_UNLOCK(ld, LDAP_CONN_LOCK); */
				if (( lderr = ldap_bind_s( ld, binddn, passwd,
				    authmethod )) == LDAP_SUCCESS ) {
					/* LDAP_MUTEX_LOCK(ld, LDAP_CONN_LOCK); */
					break;
				}
				/* LDAP_MUTEX_LOCK(ld, LDAP_CONN_LOCK); */
				if ( lc->lconn_version <= LDAP_VERSION2
				    || lderr != LDAP_PROTOCOL_ERROR ) {
					err = -1;
					break;
				}
				--lc->lconn_version;	/* try lower version */
			}
			--lc->lconn_refcnt;
			ld->ld_defconn = savedefconn;
		}

		if ( freepasswd ) {
			(*ld->ld_rebind_fn)( ld, &binddn, &passwd,
				&authmethod, 1, ld->ld_rebind_arg );
		}

		if ( err != 0 ) {
			nsldapi_free_connection( ld, lc, NULL, NULL, 1, 0 );
			lc = NULL;
		}
	}

	return( lc );
}
예제 #4
0
파일: request.c 프로젝트: andreiw/polaris
/* returns the message id of the request or -1 if an error occurs */
int
nsldapi_send_server_request(
    LDAP *ld,			/* session handle */
    BerElement *ber,		/* message to send */
    int msgid,			/* ID of message to send */
    LDAPRequest *parentreq,	/* non-NULL for referred requests */
    LDAPServer *srvlist,	/* servers to connect to (NULL for default) */
    LDAPConn *lc,		/* connection to use (NULL for default) */
    char *bindreqdn,		/* non-NULL for bind requests */
    int bind			/* perform a bind after opening new conn.? */
)
{
	LDAPRequest	*lr;
	int		err;
	int		incparent;	/* did we bump parent's ref count? */

	LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_send_server_request\n", 0, 0, 0 );

	incparent = 0;
	LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
	if ( lc == NULL ) {
		if ( srvlist == NULL ) {
			if ( ld->ld_defconn == NULL ) {
				LDAP_MUTEX_LOCK( ld, LDAP_OPTION_LOCK );
				if ( bindreqdn == NULL && ( ld->ld_options
				    & LDAP_BITOPT_RECONNECT ) != 0 ) {
					LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN,
					    NULL, NULL );
					ber_free( ber, 1 );
					LDAP_MUTEX_UNLOCK( ld, LDAP_OPTION_LOCK );
					LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
					return( -1 );
				}
				LDAP_MUTEX_UNLOCK( ld, LDAP_OPTION_LOCK );

				if ( nsldapi_open_ldap_defconn( ld ) < 0 ) {
					ber_free( ber, 1 );
					LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
					return( -1 );
				}
			}
			lc = ld->ld_defconn;
		} else {
			if (( lc = find_connection( ld, srvlist, 1 )) ==
			    NULL ) {
				if ( bind && (parentreq != NULL) ) {
					/* Remember the bind in the parent */
					incparent = 1;
					++parentreq->lr_outrefcnt;
				}

				lc = nsldapi_new_connection( ld, &srvlist, 0,
					1, bind );
			}
			free_servers( srvlist );
		}
	}


    /*
     * the logic here is:
     * if 
     * 1. no connections exists, 
     * or 
     * 2. if the connection is either not in the connected 
     *     or connecting state in an async io model
     * or 
     * 3. the connection is notin a connected state with normal (non async io)
     */
	if (   lc == NULL
		|| (  (ld->ld_options & LDAP_BITOPT_ASYNC 
               && lc->lconn_status != LDAP_CONNST_CONNECTING
		    && lc->lconn_status != LDAP_CONNST_CONNECTED)
              || (!(ld->ld_options & LDAP_BITOPT_ASYNC )
		    && lc->lconn_status != LDAP_CONNST_CONNECTED) ) ) {

		ber_free( ber, 1 );
		if ( lc != NULL ) {
			LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL );
		}
		if ( incparent ) {
			/* Forget about the bind */
			--parentreq->lr_outrefcnt; 
		}
		LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
		return( -1 );
	}

	use_connection( ld, lc );
	if (( lr = (LDAPRequest *)NSLDAPI_CALLOC( 1, sizeof( LDAPRequest ))) ==
	    NULL || ( bindreqdn != NULL && ( bindreqdn =
	    nsldapi_strdup( bindreqdn )) == NULL )) {
		if ( lr != NULL ) {
			NSLDAPI_FREE( lr );
		}
		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
		nsldapi_free_connection( ld, lc, NULL, NULL, 0, 0 );
		ber_free( ber, 1 );
		if ( incparent ) {
			/* Forget about the bind */
			--parentreq->lr_outrefcnt; 
		}
		LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
		return( -1 );
	} 
	lr->lr_binddn = bindreqdn;
	lr->lr_msgid = msgid;
	lr->lr_status = LDAP_REQST_INPROGRESS;
	lr->lr_res_errno = LDAP_SUCCESS;	/* optimistic */
	lr->lr_ber = ber;
	lr->lr_conn = lc;

	if ( parentreq != NULL ) {	/* sub-request */
		if ( !incparent ) { 
			/* Increment if we didn't do it before the bind */
			++parentreq->lr_outrefcnt;
		}
		lr->lr_origid = parentreq->lr_origid;
		lr->lr_parentcnt = parentreq->lr_parentcnt + 1;
		lr->lr_parent = parentreq;
		if ( parentreq->lr_child != NULL ) {
			lr->lr_sibling = parentreq->lr_child;
		}
		parentreq->lr_child = lr;
	} else {			/* original request */
		lr->lr_origid = lr->lr_msgid;
	}

	LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
	if (( lr->lr_next = ld->ld_requests ) != NULL ) {
		lr->lr_next->lr_prev = lr;
	}
	ld->ld_requests = lr;
	lr->lr_prev = NULL;

	if (( err = nsldapi_ber_flush( ld, lc->lconn_sb, ber, 0, 1 )) != 0 ) {

		/* need to continue write later */
		if (ld->ld_options & LDAP_BITOPT_ASYNC && err == -2 ) {	
			lr->lr_status = LDAP_REQST_WRITING;
			nsldapi_iostatus_interest_write( ld, lc->lconn_sb );
		} else {

			LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL );
			nsldapi_free_request( ld, lr, 0 );
			nsldapi_free_connection( ld, lc, NULL, NULL, 0, 0 );
			LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
			LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
			return( -1 );
		}

	} else {
		if ( parentreq == NULL ) {
			ber->ber_end = ber->ber_ptr;
			ber->ber_ptr = ber->ber_buf;
		}

		/* sent -- waiting for a response */
		if (ld->ld_options & LDAP_BITOPT_ASYNC) {
			lc->lconn_status = LDAP_CONNST_CONNECTED;
		}

		nsldapi_iostatus_interest_read( ld, lc->lconn_sb );
	}
	LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
	LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );

	LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
	return( msgid );
}
예제 #5
0
/*
 * Abandon all outstanding requests for msgid (included child requests
 * spawned when chasing referrals).  This function calls itself recursively.
 * No locking is done is this function so it must be done by the caller.
 * Returns an LDAP error code and sets it in LDAP *ld as well
 */
static int do_abandon(LDAP *ld, int origid, int msgid,
                      LDAPControl **serverctrls, LDAPControl **clientctrls) {
  BerElement *ber;
  int i, bererr, lderr, sendabandon;
  LDAPRequest *lr = NULL;

  /*
   * An abandon request looks like this:
   * AbandonRequest ::= MessageID
   */
  LDAPDebug(LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n", origid, msgid,
            0);

  /* optimistic */
  lderr = LDAP_SUCCESS;

  /*
   * Find the request that we are abandoning.  Don't send an
   * abandon message unless there is something to abandon.
   */
  sendabandon = 0;
  for (lr = ld->ld_requests; lr != NULL; lr = lr->lr_next) {
    if (lr->lr_msgid == msgid) { /* this message */
      if (origid == msgid && lr->lr_parent != NULL) {
        /* don't let caller abandon child requests! */
        lderr = LDAP_PARAM_ERROR;
        goto set_errorcode_and_return;
      }
      if (lr->lr_status == LDAP_REQST_INPROGRESS) {
        /*
         * We only need to send an abandon message if
         * the request is in progress.
         */
        sendabandon = 1;
      }
      break;
    }
    if (lr->lr_origid == msgid) { /* child:  abandon it */
      (void)do_abandon(ld, msgid, lr->lr_msgid, serverctrls, clientctrls);
      /* we ignore errors from child abandons... */
    }
  }

  if (ldap_msgdelete(ld, msgid) == 0) {
    /* we had all the results and deleted them */
    goto set_errorcode_and_return;
  }

  if (lr != NULL && sendabandon) {
    /* create a message to send */
    if ((lderr = nsldapi_alloc_ber_with_options(ld, &ber)) == LDAP_SUCCESS) {
      int abandon_msgid;

      LDAP_MUTEX_LOCK(ld, LDAP_MSGID_LOCK);
      abandon_msgid = ++ld->ld_msgid;
      LDAP_MUTEX_UNLOCK(ld, LDAP_MSGID_LOCK);
#ifdef CLDAP
      if (ld->ld_dbp->sb_naddr > 0) {
        bererr = ber_printf(ber, "{isti", abandon_msgid, ld->ld_cldapdn,
                            LDAP_REQ_ABANDON, msgid);
      } else {
#endif /* CLDAP */
        bererr =
            ber_printf(ber, "{iti", abandon_msgid, LDAP_REQ_ABANDON, msgid);
#ifdef CLDAP
      }
#endif /* CLDAP */

      if (bererr == -1 || (lderr = nsldapi_put_controls(ld, serverctrls, 1,
                                                        ber)) != LDAP_SUCCESS) {
        lderr = LDAP_ENCODING_ERROR;
        ber_free(ber, 1);
      } else {
        /* try to send the message */
        lderr =
            nsldapi_send_abandon_message(ld, lr->lr_conn, ber, abandon_msgid);
      }
    }
  }

  if (lr != NULL) {
    /*
     * Always call nsldapi_free_connection() so that the connection's
     * ref count is correctly decremented.  It is OK to always pass
     * 1 for the "unbind" parameter because doing so will only affect
     * connections that resulted from a child request (because the
     * default connection's ref count never goes to zero).
     */
    nsldapi_free_connection(ld, lr->lr_conn, NULL, NULL, 0 /* do not force */,
                            1 /* send unbind before closing */);

    /*
     * Free the entire request chain if we finished abandoning everything.
     */
    if (origid == msgid) {
      nsldapi_free_request(ld, lr, 0);
    }
  }

  /*
   * Record the abandoned message ID (used to discard any server responses
   * that arrive later).
   */
  LDAP_MUTEX_LOCK(ld, LDAP_ABANDON_LOCK);
  if (ld->ld_abandoned == NULL) {
    if ((ld->ld_abandoned = (int *)NSLDAPI_MALLOC(2 * sizeof(int))) == NULL) {
      lderr = LDAP_NO_MEMORY;
      LDAP_MUTEX_UNLOCK(ld, LDAP_ABANDON_LOCK);
      goto set_errorcode_and_return;
    }
    i = 0;
  } else {
    for (i = 0; ld->ld_abandoned[i] != -1; i++)
      ; /* NULL */
    if ((ld->ld_abandoned = (int *)NSLDAPI_REALLOC(
             (char *)ld->ld_abandoned, (i + 2) * sizeof(int))) == NULL) {
      lderr = LDAP_NO_MEMORY;
      LDAP_MUTEX_UNLOCK(ld, LDAP_ABANDON_LOCK);
      goto set_errorcode_and_return;
    }
  }
  ld->ld_abandoned[i] = msgid;
  ld->ld_abandoned[i + 1] = -1;
  LDAP_MUTEX_UNLOCK(ld, LDAP_ABANDON_LOCK);

set_errorcode_and_return:
  LDAP_SET_LDERRNO(ld, lderr, NULL, NULL);
  return (lderr);
}
예제 #6
0
/*
 * simple_bindifnot_s() is like ldap_simple_bind_s() except that it only does
 * a bind if the default connection is not currently bound.
 * If a successful bind using the same DN has already taken place we just
 * return LDAP_SUCCESS without conversing with the server at all.
 */
static int
simple_bindifnot_s( LDAP *ld, const char *dn, const char *passwd )
{
	int		msgid, rc;
	LDAPMessage	*result;
	char		*binddn;

	LDAPDebug( LDAP_DEBUG_TRACE, "simple_bindifnot_s\n", 0, 0, 0 );

	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
		return( LDAP_PARAM_ERROR );
	}

	if ( dn == NULL ) {
		dn = "";	/* to make comparisons simpler */
	}

	/*
	 * if we are already bound using the same DN, just return LDAP_SUCCESS.
	 */
	if ( NULL != ( binddn = nsldapi_get_binddn( ld ))
	    && 0 == strcmp( dn, binddn )) {
		rc = LDAP_SUCCESS;
		LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
		return rc;
	}

	/*
	 * if the default connection has been lost and is now marked dead,
	 * dispose of the default connection so it will get re-established.
	 *
	 * if not, clear the bind DN and status to ensure that we don't
	 * report the wrong bind DN to a different thread while waiting
	 * for our bind result to return from the server.
	 */
	LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
	if ( NULL != ld->ld_defconn ) {
	    if ( LDAP_CONNST_DEAD == ld->ld_defconn->lconn_status ) {
		nsldapi_free_connection( ld, ld->ld_defconn, NULL, NULL, 1, 0 );
		ld->ld_defconn = NULL;
	    } else if ( ld->ld_defconn->lconn_binddn != NULL ) {
		NSLDAPI_FREE( ld->ld_defconn->lconn_binddn );
		ld->ld_defconn->lconn_binddn = NULL;
		ld->ld_defconn->lconn_bound = 0;
	    }
	}
	LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );

	/*
	 * finally, bind (this will open a new connection if necessary)
	 *
	 * do everything under the protection of the result lock to
	 * ensure that only one thread will be in this code at a time.
	 * XXXmcs: we should use a condition variable instead?
	 */
	LDAP_MUTEX_LOCK( ld, LDAP_RESULT_LOCK );
	if ( (msgid = simple_bind_nolock( ld, dn, passwd, 0 )) == -1 ) {
		rc = LDAP_GET_LDERRNO( ld, NULL, NULL );
		goto unlock_and_return;
	}

	/*
	 * Note that at this point the bind request is on its way to the
	 * server and at any time now we will either be bound as the new
	 * DN (if the bind succeeded) or we will be bound as anonymous (if
	 * the bind failed).
	 */

	/*
	 * Wait for the bind result.  Code inside result.c:read1msg()
	 * takes care of setting the connection's bind DN and status.
	 */
	if ( nsldapi_result_nolock( ld, msgid, 1, 0, (struct timeval *) 0,
	    &result ) == -1 ) {
		rc = LDAP_GET_LDERRNO( ld, NULL, NULL );
		goto unlock_and_return;
	}

	rc = ldap_result2error( ld, result, 1 );

unlock_and_return:
	LDAP_MUTEX_UNLOCK( ld, LDAP_RESULT_LOCK );
	return( rc );
}