Esempio n. 1
0
int
ldap_int_check_async_open( LDAP *ld, ber_socket_t sd )
{
	struct timeval tv = { 0 };
	int rc;

	rc = ldap_int_poll( ld, sd, &tv, 1 );
	switch ( rc ) {
	case 0:
		/* now ready to start tls */
		ld->ld_defconn->lconn_status = LDAP_CONNST_CONNECTED;
		break;

	default:
		ld->ld_errno = LDAP_CONNECT_ERROR;
		return -1;

	case -2:
		/* connect not completed yet */
		ld->ld_errno = LDAP_X_CONNECTING;
		return rc;
	}

#ifdef HAVE_TLS
	if ( ld->ld_options.ldo_tls_mode == LDAP_OPT_X_TLS_HARD ||
		!strcmp( ld->ld_defconn->lconn_server->lud_scheme, "ldaps" )) {

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

		rc = ldap_int_tls_start( ld, ld->ld_defconn, ld->ld_defconn->lconn_server );

		--ld->ld_defconn->lconn_refcnt;
	}
#endif
	return rc;
}
Esempio n. 2
0
int
ldap_send_server_request(
	LDAP *ld,
	BerElement *ber,
	ber_int_t msgid,
	LDAPRequest *parentreq,
	LDAPURLDesc **srvlist,
	LDAPConn *lc,
	LDAPreqinfo *bind,
	int m_noconn,
	int m_res )
{
	LDAPRequest	*lr;
	int		incparent, rc;

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

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

	LDAP_CONN_LOCK_IF(m_noconn);
	if ( lc == NULL ) {
		if ( srvlist == NULL ) {
			lc = ld->ld_defconn;
		} else {
			lc = find_connection( ld, *srvlist, 1 );
			if ( lc == NULL ) {
				if ( (bind != NULL) && (parentreq != NULL) ) {
					/* Remember the bind in the parent */
					incparent = 1;
					++parentreq->lr_outrefcnt;
				}
				lc = ldap_new_connection( ld, srvlist, 0,
					1, bind, 1, m_res );
			}
		}
	}

	/* async connect... */
	if ( lc != NULL && lc->lconn_status == LDAP_CONNST_CONNECTING ) {
		ber_socket_t	sd = AC_SOCKET_ERROR;
		struct timeval	tv = { 0 };

		ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_GET_FD, &sd );

		/* poll ... */
		switch ( ldap_int_poll( ld, sd, &tv, 1 ) ) {
		case 0:
			/* go on! */
			lc->lconn_status = LDAP_CONNST_CONNECTED;
			break;

		case -2:
			/* async only occurs if a network timeout is set */

			/* honor network timeout */
			LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex );
			if ( time( NULL ) - lc->lconn_created <= ld->ld_options.ldo_tm_net.tv_sec )
			{
				/* caller will have to call again */
				ld->ld_errno = LDAP_X_CONNECTING;
			}
			LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex );
			/* fallthru */

		default:
			/* error */
			break;
		}
	}

	if ( lc == NULL || lc->lconn_status != LDAP_CONNST_CONNECTED ) {
		if ( ld->ld_errno == LDAP_SUCCESS ) {
			ld->ld_errno = LDAP_SERVER_DOWN;
		}

		ber_free( ber, 1 );
		if ( incparent ) {
			/* Forget about the bind */
			--parentreq->lr_outrefcnt; 
		}
		LDAP_CONN_UNLOCK_IF(m_noconn);
		return( -1 );
	}

	use_connection( ld, lc );

#ifdef LDAP_CONNECTIONLESS
	if ( LDAP_IS_UDP( ld )) {
		BerElement tmpber = *ber;
		ber_rewind( &tmpber );
		LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex );
		rc = ber_write( &tmpber, ld->ld_options.ldo_peer,
			sizeof( struct sockaddr_storage ), 0 );
		LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex );
		if ( rc == -1 ) {
			ld->ld_errno = LDAP_ENCODING_ERROR;
			LDAP_CONN_UNLOCK_IF(m_noconn);
			return rc;
		}
	}
#endif

	/* If we still have an incomplete write, try to finish it before
	 * dealing with the new request. If we don't finish here, return
	 * LDAP_BUSY and let the caller retry later. We only allow a single
	 * request to be in WRITING state.
	 */
	rc = 0;
	if ( ld->ld_requests &&
		ld->ld_requests->lr_status == LDAP_REQST_WRITING &&
		ldap_int_flush_request( ld, ld->ld_requests ) < 0 )
	{
		rc = -1;
	}
	if ( rc ) {
		LDAP_CONN_UNLOCK_IF(m_noconn);
		return rc;
	}

	lr = (LDAPRequest *)LDAP_CALLOC( 1, sizeof( LDAPRequest ) );
	if ( lr == NULL ) {
		ld->ld_errno = LDAP_NO_MEMORY;
		ldap_free_connection( ld, lc, 0, 0 );
		ber_free( ber, 1 );
		if ( incparent ) {
			/* Forget about the bind */
			--parentreq->lr_outrefcnt; 
		}
		LDAP_CONN_UNLOCK_IF(m_noconn);
		return( -1 );
	} 
	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;
		lr->lr_parent = parentreq;
		lr->lr_refnext = parentreq->lr_child;
		parentreq->lr_child = lr;
	} else {			/* original request */
		lr->lr_origid = lr->lr_msgid;
	}

	/* Extract requestDN for future reference */
#ifdef LDAP_CONNECTIONLESS
	if ( !LDAP_IS_UDP(ld) )
#endif
	{
		BerElement tmpber = *ber;
		ber_int_t	bint;
		ber_tag_t	tag, rtag;

		ber_reset( &tmpber, 1 );
		rtag = ber_scanf( &tmpber, "{it", /*}*/ &bint, &tag );
		switch ( tag ) {
		case LDAP_REQ_BIND:
			rtag = ber_scanf( &tmpber, "{i" /*}*/, &bint );
			break;
		case LDAP_REQ_DELETE:
			break;
		default:
			rtag = ber_scanf( &tmpber, "{" /*}*/ );
		case LDAP_REQ_ABANDON:
			break;
		}
		if ( tag != LDAP_REQ_ABANDON ) {
			ber_skip_tag( &tmpber, &lr->lr_dn.bv_len );
			lr->lr_dn.bv_val = tmpber.ber_ptr;
		}
	}

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

	ld->ld_errno = LDAP_SUCCESS;
	if ( ldap_int_flush_request( ld, lr ) == -1 ) {
		msgid = -1;
	}

	LDAP_CONN_UNLOCK_IF(m_noconn);
	return( msgid );
}
Esempio n. 3
0
int
ldap_int_tls_start ( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv )
{
	Sockbuf *sb;
	char *host;
	void *ssl;
	int ret;
#ifdef LDAP_USE_NON_BLOCKING_TLS
	struct timeval start_time_tv, tv, tv0;
	ber_socket_t	sd = AC_SOCKET_ERROR;
#endif /* LDAP_USE_NON_BLOCKING_TLS */

	if ( !conn )
		return LDAP_PARAM_ERROR;

	sb = conn->lconn_sb;
	if( srv ) {
		host = srv->lud_host;
	} else {
 		host = conn->lconn_server->lud_host;
	}

	/* avoid NULL host */
	if( host == NULL ) {
		host = "localhost";
	}

	(void) tls_init( tls_imp );

#ifdef LDAP_USE_NON_BLOCKING_TLS
	/*
	 * Use non-blocking io during SSL Handshake when a timeout is configured
	 */
	if ( ld->ld_options.ldo_tm_net.tv_sec >= 0 ) {
		ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_SET_NONBLOCK, sb );
		ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
		tv = ld->ld_options.ldo_tm_net;
		tv0 = tv;
#ifdef HAVE_GETTIMEOFDAY
		gettimeofday( &start_time_tv, NULL );
#else /* ! HAVE_GETTIMEOFDAY */
		time( &start_time_tv.tv_sec );
		start_time_tv.tv_usec = 0;
#endif /* ! HAVE_GETTIMEOFDAY */
	}

#endif /* LDAP_USE_NON_BLOCKING_TLS */

	ld->ld_errno = LDAP_SUCCESS;
	ret = ldap_int_tls_connect( ld, conn );

#ifdef LDAP_USE_NON_BLOCKING_TLS
	while ( ret > 0 ) { /* this should only happen for non-blocking io */
		int wr=0;

		if ( sb->sb_trans_needs_read ) {
			wr=0;
		} else if ( sb->sb_trans_needs_write ) {
			wr=1;
		}
		Debug( LDAP_DEBUG_TRACE, "ldap_int_tls_start: ldap_int_tls_connect needs %s\n",
				wr ? "write": "read", 0, 0);

		ret = ldap_int_poll( ld, sd, &tv, wr);
		if ( ret < 0 ) {
			ld->ld_errno = LDAP_TIMEOUT;
			break;
		} else {
			/* ldap_int_poll called ldap_pvt_ndelay_off */
			ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_SET_NONBLOCK, sb );
			ret = ldap_int_tls_connect( ld, conn );
			if ( ret > 0 ) { /* need to call tls_connect once more */
				struct timeval curr_time_tv, delta_tv;

				/* This is mostly copied from result.c:wait4msg(), should
				 * probably be moved into a separate function */
#ifdef HAVE_GETTIMEOFDAY
				gettimeofday( &curr_time_tv, NULL );
#else /* ! HAVE_GETTIMEOFDAY */
				time( &curr_time_tv.tv_sec );
				curr_time_tv.tv_usec = 0;
#endif /* ! HAVE_GETTIMEOFDAY */

				/* delta = curr - start */
				delta_tv.tv_sec = curr_time_tv.tv_sec - start_time_tv.tv_sec;
				delta_tv.tv_usec = curr_time_tv.tv_usec - start_time_tv.tv_usec;
				if ( delta_tv.tv_usec < 0 ) {
					delta_tv.tv_sec--;
					delta_tv.tv_usec += 1000000;
				}

				/* tv0 < delta ? */
				if ( ( tv0.tv_sec < delta_tv.tv_sec ) ||
					 ( ( tv0.tv_sec == delta_tv.tv_sec ) &&
					   ( tv0.tv_usec < delta_tv.tv_usec ) ) )
				{
					ret = -1;
					ld->ld_errno = LDAP_TIMEOUT;
					break;
				} else {
					/* timeout -= delta_time */
					tv0.tv_sec -= delta_tv.tv_sec;
					tv0.tv_usec -= delta_tv.tv_usec;
					if ( tv0.tv_usec < 0 ) {
						tv0.tv_sec--;
						tv0.tv_usec += 1000000;
					}
					start_time_tv.tv_sec = curr_time_tv.tv_sec;
					start_time_tv.tv_usec = curr_time_tv.tv_usec;
				}
				tv = tv0;
				Debug( LDAP_DEBUG_TRACE, "ldap_int_tls_start: ld %p %ld s %ld us to go\n",
					(void *)ld, (long) tv.tv_sec, (long) tv.tv_usec );
			}
		}
	}
	if ( ld->ld_options.ldo_tm_net.tv_sec >= 0 ) {
		ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_SET_NONBLOCK, NULL );
	}
#endif /* LDAP_USE_NON_BLOCKING_TLS */

	if ( ret < 0 ) {
		if ( ld->ld_errno == LDAP_SUCCESS )
			ld->ld_errno = LDAP_CONNECT_ERROR;
		return (ld->ld_errno);
	}

	ssl = ldap_pvt_tls_sb_ctx( sb );
	assert( ssl != NULL );

	/* 
	 * compare host with name(s) in certificate
	 */
	if (ld->ld_options.ldo_tls_require_cert != LDAP_OPT_X_TLS_NEVER &&
	    ld->ld_options.ldo_tls_require_cert != LDAP_OPT_X_TLS_ALLOW) {
		ld->ld_errno = ldap_pvt_tls_check_hostname( ld, ssl, host );
		if (ld->ld_errno != LDAP_SUCCESS) {
			return ld->ld_errno;
		}
	}

	return LDAP_SUCCESS;
}