/*
* Copyright 2001-2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
/*
* Copyright (c) 1995 Regents of the University of Michigan.
* All rights reserved.
*/
/*
* request.c - sending of ldap requests; handling of referrals
*/
#if 0
#ifndef lint
static char copyright[] = "@(#) Copyright (c) 1995 Regents of the University of Michigan.\nAll rights reserved.\n";
#endif
#endif
#include "ldap-int.h"
#ifdef LDAP_DNS
#endif /* LDAP_DNS */
/* returns an LDAP error code and also sets error inside LDAP * */
int
{
int err;
} else {
err = LDAP_SUCCESS;
#ifdef STR_TRANSLATION
#endif /* STR_TRANSLATION */
}
return( err );
}
void
{
#ifdef STR_TRANSLATION
}
#endif /* STR_TRANSLATION */
}
/* returns the message id of the request or -1 if an error occurs */
int
{
#ifdef LDAP_DNS
return( -1 );
}
#ifdef LDAP_DEBUG
if ( ldap_debug & LDAP_DEBUG_TRACE ) {
"LDAP server %s: dn %s, port %d\n",
ber_err_print( msg );
}
}
#endif /* LDAP_DEBUG */
} else {
#endif /* LDAP_DNS */
/*
* use of DNS is turned off or this is an LDAP DN...
* use our default connection
*/
#ifdef LDAP_DNS
}
#endif /* LDAP_DNS */
}
/* returns the message id of the request or -1 if an error occurs */
int
int msgid, /* ID of message to send */
char *bindreqdn, /* non-NULL for bind requests */
int bind /* perform a bind after opening new conn.? */
)
{
int err;
incparent = 0;
& LDAP_BITOPT_RECONNECT ) != 0 ) {
return( -1 );
}
if ( nsldapi_open_ldap_defconn( ld ) < 0 ) {
return( -1 );
}
}
} else {
NULL ) {
/* Remember the bind in the parent */
incparent = 1;
}
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 ( incparent ) {
/* Forget about the bind */
}
return( -1 );
}
NSLDAPI_FREE( lr );
}
if ( incparent ) {
/* Forget about the bind */
}
return( -1 );
}
if ( !incparent ) {
/* Increment if we didn't do it before the bind */
}
}
} else { /* original request */
}
}
/* need to continue write later */
} else {
return( -1 );
}
} else {
}
/* sent -- waiting for a response */
}
}
return( msgid );
}
/*
* returns -1 if a fatal error occurs. If async is non-zero and the flush
* would block, -2 is returned.
*/
int
int async )
{
int terrno;
for ( ;; ) {
/*
* ber_flush() doesn't set errno on EOF, so we pre-set it to
* zero to avoid getting tricked by leftover "EAGAIN" errors
*/
LDAP_SET_ERRNO( ld, 0 );
return( 0 ); /* success */
}
return( -1 ); /* fatal error */
}
}
else if ( !NSLDAPI_ERRNO_IO_INPROGRESS( terrno )) {
return( -1 ); /* fatal error */
}
if ( async ) {
return( -2 ); /* would block */
}
}
}
LDAPConn *
{
int rc;
/*
* make a new LDAP server connection
*/
NSLDAPI_FREE( (char *)lc );
}
return( NULL );
}
if ( !use_ldsb ) {
/*
* we have allocated a new sockbuf
* set I/O routines to match those in default LDAP sockbuf
*/
LBER_SOCKBUF_OPT_EXT_IO_FNS, &extiofns ) == 0 ) {
}
LBER_SOCKBUF_OPT_READ_FN, (void *)&sb_fn ) == 0
(void *)sb_fn );
}
LBER_SOCKBUF_OPT_WRITE_FN, (void *)&sb_fn ) == 0
(void *)sb_fn );
}
}
if ( connect ) {
/*
* save the return code for later
*/
&lc->lconn_krbinstance );
if (rc != -1) {
break;
}
}
if ( !use_ldsb ) {
}
NSLDAPI_FREE( (char *)lc );
/* nsldapi_open_ldap_connection has already set ld_errno */
return( NULL );
}
} else {
}
}
{
}
else {
}
/*
* XXX for now, we always do a synchronous bind. This will have
* to change in the long run...
*/
if ( bind ) {
freepasswd = err = 0;
} else {
== LDAP_SUCCESS ) {
freepasswd = 1;
} else {
err = -1;
}
}
if ( err == 0 ) {
/*
* 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); */
authmethod )) == LDAP_SUCCESS ) {
/* LDAP_MUTEX_LOCK(ld, LDAP_CONN_LOCK); */
break;
}
/* LDAP_MUTEX_LOCK(ld, LDAP_CONN_LOCK); */
|| lderr != LDAP_PROTOCOL_ERROR ) {
err = -1;
break;
}
}
--lc->lconn_refcnt;
}
if ( freepasswd ) {
}
if ( err != 0 ) {
}
}
return( lc );
}
static LDAPConn *
/*
* return an existing connection (if any) to the server srv
* if "any" is non-zero, check for any server in the "srv" chain
*/
{
&& ls->lsrv_options ==
return( lc );
}
if ( !any ) {
break;
}
}
}
return( NULL );
}
static void
{
++lc->lconn_refcnt;
}
void
{
if ( unbind ) {
}
}
} else {
}
break;
}
}
}
/*
* if this is the default connection (lc->lconn_sb==ld->ld_sbp)
* we do not free the Sockbuf here since it will be freed
* later inside ldap_unbind().
*/
}
}
}
NSLDAPI_FREE( lc );
0, 0, 0 );
} else {
lc->lconn_refcnt, 0, 0 );
}
}
#ifdef LDAP_DEBUG
void
{
/* CTIME for this platform doesn't use this. */
#endif
ber_err_print( msg );
LDAP_SRV_OPT_SECURE ) ? "Yes" :
" (default)" : "" );
ber_err_print( msg );
}
LDAP_CONNST_CONNECTING ) ? "Connecting" :
"Connected" );
ber_err_print( msg );
sizeof(buf) ));
ber_err_print( msg );
ber_err_print( " partial response has been received:\n" );
}
ber_err_print( "\n" );
if ( !all ) {
break;
}
}
}
void
{
ber_err_print( "** Outstanding Requests:\n" );
ber_err_print( " Empty\n" );
}
LDAP_REQST_INPROGRESS ) ? "InProgress" :
"Writing" );
ber_err_print( msg );
ber_err_print( msg );
ber_err_print( msg );
}
}
ber_err_print( "** Response Queue:\n" );
ber_err_print( " Empty\n" );
}
ber_err_print( msg );
ber_err_print( " chained responses:\n" );
" * msgid %d, type %d\n",
l->lm_msgid, l->lm_msgtype );
ber_err_print( msg );
}
}
}
}
#endif /* LDAP_DEBUG */
void
{
"nsldapi_free_request 0x%x (origid %d, msgid %d)\n",
}
/* free all of our spawned referrals (child requests) */
}
if ( free_conn ) {
}
} else {
}
}
}
}
}
}
NSLDAPI_FREE( lr );
}
static void
{
}
}
NSLDAPI_FREE( srvlist );
}
}
/*
* Initiate chasing of LDAPv2+ (Umich extension) referrals.
*
* Returns an LDAP error code.
*
* Note that *hadrefp will be set to 1 if one or more referrals were found in
* "*errstrp" (even if we can't chase them) and zero if none were found.
*
* XXX merging of errors in this routine needs to be improved.
*/
int
int *totalcountp, int *chasingcountp )
{
*totalcountp = *chasingcountp = 0;
return( LDAP_SUCCESS );
}
LDAP_REF_STR, LDAP_REF_STR_LEN ) == 0 ) {
*p = '\0';
p += LDAP_REF_STR_LEN;
break;
}
}
if ( len < LDAP_REF_STR_LEN ) {
return( LDAP_SUCCESS );
}
"more than %d referral hops (dropping)\n",
ld->ld_refhoplimit, 0, 0 );
return( LDAP_REFERRAL_LIMIT_EXCEEDED );
}
/* find original request */
;
}
unfollowed = NULL;
rc = LDAP_SUCCESS;
/* parse out & follow referrals */
*p++ = '\0';
} else {
p = NULL;
}
++*totalcountp;
&unknown );
ref )) != LDAP_SUCCESS ) {
}
} else {
++*chasingcountp;
}
}
NSLDAPI_FREE( *errstrp );
*errstrp = unfollowed;
return( rc );
}
/* returns an LDAP error code */
int
{
*totalcountp = *chasingcountp = 0;
return( LDAP_SUCCESS );
}
*totalcountp = 1;
"more than %d referral hops (dropping)\n",
ld->ld_refhoplimit, 0, 0 );
return( LDAP_REFERRAL_LIMIT_EXCEEDED );
}
/* find original request */
;
}
/*
* in LDAPv3, we just need to follow one referral in the set.
* we dp this by stopping as soon as we succeed in initiating a
* chase on any referral (basically this means we were able to connect
* to the server and bind).
*/
*chasingcountp = 1;
break;
}
}
/* XXXmcs: should we save unfollowed referrals somewhere? */
return( rc ); /* last error is as good as any other I guess... */
}
/*
* 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
{
*unknownp = 0;
*unknownp = 1;
rc = LDAP_SUCCESS;
goto cleanup_and_return;
}
/* XXXmcs: can't tell if secure is supported by connect callback */
*unknownp = 1;
rc = LDAP_SUCCESS;
goto cleanup_and_return;
}
goto cleanup_and_return;
}
== NULL ) {
rc = LDAP_NO_MEMORY;
goto cleanup_and_return;
}
} else {
"chase_one_referral: using hostname '%s' from original "
"request on new request\n",
} else {
"chase_one_referral: using hostname '%s' as specified "
"on new request\n",
}
NSLDAPI_FREE((char *)srv);
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
*/
"chase_one_referral: using port (%d) from original "
"request on new request\n",
"chase_one_referral: using default port (%d) \n",
} else {
"chase_one_referral: using port (%d) as specified on "
"new request\n",
}
if ( secure ) {
}
} else {
rc = LDAP_SUCCESS;
}
if ( ludp != NULLLDAPURLDESC ) {
}
return( rc );
}
/* returns an LDAP error code */
int
{
int first;
if ( *referralsp == NULL ) {
first = 1;
LDAP_REF_STR_LEN + 1 );
} else {
first = 0;
}
if ( *referralsp == NULL ) {
return( LDAP_NO_MEMORY );
}
if ( first ) {
} else {
}
strcat( *referralsp, s );
return( LDAP_SUCCESS );
}
/* returns an LDAP error code */
static int
BerElement **berp )
{
/*
* XXX this routine knows way too much about how the lber library works!
*/
int rc;
"re_encode_request: new msgid %d, new dn <%s>\n",
/*
* All LDAP requests are sequences that start with a message id. For
* everything except delete requests, this is followed by a sequence
* that is tagged with the operation code. For deletes, there is just
* a DN that is tagged with the operation code.
*/
/* skip past msgid and get operation tag */
return( LDAP_DECODING_ERROR );
}
/*
* XXXmcs: we don't support scope or filters in search referrals yet,
* so if either were present we return an error which is probably
* better than just ignoring the extra info.
*/
if ( tag == LDAP_REQ_SEARCH &&
return( LDAP_LOCAL_ERROR );
}
if ( tag == LDAP_REQ_BIND ) {
/* bind requests have a version number before the DN */
} else if ( tag == LDAP_REQ_DELETE ) {
/* delete requests DNs are not within a sequence */
} else {
}
if ( rc == LBER_ERROR ) {
return( LDAP_DECODING_ERROR );
}
} else {
NSLDAPI_FREE( orig_dn );
}
/* allocate and build the new request */
!= LDAP_SUCCESS ) {
NSLDAPI_FREE( orig_dn );
}
return( rc );
}
if ( tag == LDAP_REQ_BIND ) {
} else if ( tag == LDAP_REQ_DELETE ) {
} else {
}
NSLDAPI_FREE( orig_dn );
}
/*
* can't use "dn" or "orig_dn" from this point on (they've been freed)
*/
if ( rc == -1 ) {
return( LDAP_ENCODING_ERROR );
}
if ( tag != LDAP_REQ_DELETE &&
return( LDAP_ENCODING_ERROR );
}
#ifdef LDAP_DEBUG
if ( ldap_debug & LDAP_DEBUG_PACKETS ) {
0, 0, 0 );
}
#endif /* LDAP_DEBUG */
return( LDAP_SUCCESS );
}
{
break;
}
}
return( lr );
}
/*
* nsldapi_connection_lost_nolock() resets "ld" to a non-connected, known
* state. It should be called whenever a fatal error occurs on the
* Sockbuf "sb." sb == NULL means we don't know specifically where
* the problem was so we assume all connections are bad.
*/
void
{
/*
* change status of all pending requests that are associated with "sb
* to "connection dead."
* also change the connection status to "dead" and remove it from
* the list of sockets we are interested in.
*/
}
}
}
}
#ifdef LDAP_DNS
static LDAPServer *
{
int i, port;
++domain;
} else {
}
return( NULL );
}
p = host;
} else {
*p++ = '\0';
}
server_dn = ++p;
if ( *server_dn == '\0' ) {
}
}
} else {
}
sizeof( LDAPServer ))) == NULL ) {
free_servers( srvlist );
break; /* exit loop & return */
}
/* add to end of list of servers */
} else {
}
/* copy in info. */
free_servers( srvlist );
break; /* exit loop & return */
}
}
}
ldap_value_free( dxs );
}
return( srvlist );
}
#endif /* LDAP_DNS */