LDAPv3 Referrals (using old style referral entries) initial commit.

Have not completed work on backends other than LDBM.
All send_() routines have new parameters (which will likely change
some more to support responses with controls).
slapd/back-ldbm only compiles.  NOT TESTED.  This is a work in progress.
This commit is contained in:
Kurt Zeilenga 1999-07-09 18:31:10 +00:00
parent 59a6663312
commit fe242e3ca7
33 changed files with 8194 additions and 2009 deletions

File diff suppressed because it is too large Load diff

View file

@ -12,24 +12,23 @@
* is provided ``as is'' without express or implied warranty.
*/
#include "portable.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <ac/socket.h>
#include "slap.h"
extern Backend *select_backend();
extern char *default_referral;
void
int
do_abandon(
Connection *conn,
Operation *op
)
{
int id;
Backend *be;
ber_int_t id;
Operation *o;
Operation **oo;
int rc, notfound;
Debug( LDAP_DEBUG_TRACE, "do_abandon\n", 0, 0, 0 );
@ -40,31 +39,63 @@ do_abandon(
*/
if ( ber_scanf( op->o_ber, "i", &id ) == LBER_ERROR ) {
Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0 ,0 );
return;
Debug( LDAP_DEBUG_ANY, "do_abandon: ber_scanf failed\n", 0, 0 ,0 );
send_ldap_disconnect( conn, op,
LDAP_PROTOCOL_ERROR, "decoding error" );
return -1;
}
if( (rc = get_ctrls( conn, op, 0 )) != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_ANY, "do_abandon: get_ctrls failed\n", 0, 0 ,0 );
return rc;
}
Debug( LDAP_DEBUG_ARGS, "do_abandon: id %d\n", id, 0 ,0 );
if( id <= 0 ) {
Debug( LDAP_DEBUG_ANY,
"do_abandon: bad msgid %ld\n", (long) id, 0, 0 );
return LDAP_SUCCESS;
}
notfound = 1; /* not found */
ldap_pvt_thread_mutex_lock( &conn->c_mutex );
/*
* find the operation being abandoned and set the o_abandon
* flag. It's up to the backend to periodically check this
* flag and abort the operation at a convenient time.
*/
pthread_mutex_lock( &conn->c_opsmutex );
for ( o = conn->c_ops; o != NULL; o = o->o_next ) {
if ( o->o_msgid == id )
break;
if ( o->o_msgid == id ) {
ldap_pvt_thread_mutex_lock( &o->o_abandonmutex );
o->o_abandon = 1;
ldap_pvt_thread_mutex_unlock( &o->o_abandonmutex );
notfound = 0;
goto done;
}
}
if ( o != NULL ) {
pthread_mutex_lock( &o->o_abandonmutex );
o->o_abandon = 1;
pthread_mutex_unlock( &o->o_abandonmutex );
} else {
Debug( LDAP_DEBUG_TRACE, "do_abandon: op not found\n", 0, 0,
0 );
for ( oo = &conn->c_pending_ops;
(*oo != NULL) && ((*oo)->o_msgid != id);
oo = &(*oo)->o_next )
{
/* EMPTY */ ;
}
pthread_mutex_unlock( &conn->c_opsmutex );
if( *oo != NULL ) {
o = *oo;
*oo = (*oo)->o_next;
slap_op_free( o );
notfound = 0;
}
done:
ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
Debug( LDAP_DEBUG_TRACE, "do_abandon: op=%ld %sfound\n",
id, notfound ? "not " : "", 0 );
return LDAP_SUCCESS;
}

View file

@ -10,36 +10,38 @@
* is provided ``as is'' without express or implied warranty.
*/
#include "portable.h"
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <ac/string.h>
#include <ac/time.h>
#include <ac/socket.h>
#include "slap.h"
extern Backend *select_backend();
extern char *dn_normalize();
static void add_created_attrs(Operation *op, Entry *e);
extern char *default_referral;
extern time_t currenttime;
extern pthread_mutex_t currenttime_mutex;
extern int global_lastmod;
static void add_created_attrs();
void
do_add( conn, op )
Connection *conn;
Operation *op;
int
do_add( Connection *conn, Operation *op )
{
BerElement *ber = op->o_ber;
char *dn, *last;
unsigned long len, tag;
ber_len_t len;
ber_tag_t tag;
Entry *e;
Backend *be;
int rc = LDAP_SUCCESS;
Debug( LDAP_DEBUG_TRACE, "do_add\n", 0, 0, 0 );
if( op->o_bind_in_progress ) {
Debug( LDAP_DEBUG_ANY, "do_add: SASL bind in progress.\n", 0, 0, 0 );
send_ldap_result( conn, op, LDAP_SASL_BIND_IN_PROGRESS, NULL,
"SASL bind in progress", NULL );
return LDAP_SASL_BIND_IN_PROGRESS;
}
/*
* Parse the add request. It looks like this:
*
@ -52,18 +54,23 @@ do_add( conn, op )
* }
*/
/* get the name */
if ( ber_scanf( ber, "{a", /*}*/ &dn ) == LBER_ERROR ) {
Debug( LDAP_DEBUG_ANY, "do_add: ber_scanf failed\n", 0, 0, 0 );
send_ldap_disconnect( conn, op,
LDAP_PROTOCOL_ERROR, "decoding error" );
return -1;
}
e = (Entry *) ch_calloc( 1, sizeof(Entry) );
/* get the name */
if ( ber_scanf( ber, "{a", &dn ) == LBER_ERROR ) {
Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
"decoding error" );
return;
}
e->e_dn = dn;
dn = dn_normalize( strdup( dn ) );
Debug( LDAP_DEBUG_ARGS, " do_add: dn (%s)\n", dn, 0, 0 );
e->e_ndn = dn_normalize_case( ch_strdup( dn ) );
e->e_private = NULL;
dn = NULL;
Debug( LDAP_DEBUG_ARGS, " do_add: ndn (%s)\n", e->e_ndn, 0, 0 );
/* get the attrs */
e->e_attrs = NULL;
@ -73,19 +80,20 @@ do_add( conn, op )
struct berval **vals;
if ( ber_scanf( ber, "{a{V}}", &type, &vals ) == LBER_ERROR ) {
send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR,
NULL, "decoding error" );
send_ldap_disconnect( conn, op,
LDAP_PROTOCOL_ERROR, "decoding error" );
entry_free( e );
return;
return -1;
}
if ( vals == NULL ) {
Debug( LDAP_DEBUG_ANY, "no values for type %s\n", type,
0, 0 );
send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
NULL );
send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR,
NULL, "no values for type", NULL );
free( type );
entry_free( e );
return;
return LDAP_PROTOCOL_ERROR;
}
attr_merge( e, type, vals );
@ -94,19 +102,34 @@ do_add( conn, op )
ber_bvecfree( vals );
}
if ( ber_scanf( ber, /*{*/ "}") == LBER_ERROR ) {
entry_free( e );
Debug( LDAP_DEBUG_ANY, "do_add: ber_scanf failed\n", 0, 0, 0 );
send_ldap_disconnect( conn, op,
LDAP_PROTOCOL_ERROR, "decoding error" );
return -1;
}
if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) {
entry_free( e );
Debug( LDAP_DEBUG_ANY, "do_add: get_ctrls failed\n", 0, 0, 0 );
return rc;
}
Statslog( LDAP_DEBUG_STATS, "conn=%d op=%d ADD dn=\"%s\"\n",
conn->c_connid, op->o_opid, dn, 0, 0 );
conn->c_connid, op->o_opid, e->e_ndn, 0, 0 );
/*
* We could be serving multiple database backends. Select the
* appropriate one, or send a referral to our "referral server"
* if we don't hold it.
*/
if ( (be = select_backend( dn )) == NULL ) {
be = select_backend( e->e_ndn );
if ( be == NULL ) {
entry_free( e );
send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
default_referral );
return;
send_ldap_result( conn, op, LDAP_REFERRAL, NULL,
NULL, default_referral );
return rc;
}
/*
@ -115,38 +138,46 @@ do_add( conn, op )
* 2) this backend is master for what it holds;
* 3) it's a replica and the dn supplied is the updatedn.
*/
if ( be->be_add != NULL ) {
if ( be->be_add ) {
/* do the update here */
if ( be->be_updatedn == NULL || strcasecmp( be->be_updatedn,
op->o_dn ) == 0 ) {
if ( (be->be_lastmod == ON || be->be_lastmod == 0 &&
global_lastmod == ON) && be->be_updatedn == NULL ) {
if ( be->be_update_ndn == NULL ||
strcmp( be->be_update_ndn, op->o_ndn ) == 0 )
{
if ( (be->be_lastmod == ON || (be->be_lastmod == UNDEFINED &&
global_lastmod == ON)) && be->be_update_ndn == NULL ) {
add_created_attrs( op, e );
}
if ( (*be->be_add)( be, conn, op, e ) == 0 ) {
replog( be, LDAP_REQ_ADD, e->e_dn, e, 0 );
be_entry_release_w( be, e );
}
} else {
entry_free( e );
send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
default_referral );
send_ldap_result( conn, op, rc = LDAP_REFERRAL, NULL,
NULL, default_referral );
}
} else {
Debug( LDAP_DEBUG_ARGS, " do_add: HHH\n", 0, 0, 0 );
entry_free( e );
send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
"Function not implemented" );
send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
NULL, "Function not implemented", NULL );
}
return rc;
}
static void
add_created_attrs( Operation *op, Entry *e )
{
char buf[20];
char buf[22];
struct berval bv;
struct berval *bvals[2];
Attribute **a, **next;
Attribute *tmp;
struct tm *ltm;
time_t currenttime;
Debug( LDAP_DEBUG_TRACE, "add_created_attrs\n", 0, 0, 0 );
@ -155,8 +186,7 @@ add_created_attrs( Operation *op, Entry *e )
/* remove any attempts by the user to add these attrs */
for ( a = &e->e_attrs; *a != NULL; a = next ) {
if ( strcasecmp( (*a)->a_type, "createtimestamp" ) == 0
|| strcasecmp( (*a)->a_type, "creatorsname" ) == 0 ) {
if ( oc_check_no_usermod_attr( (*a)->a_type ) ) {
tmp = *a;
*a = (*a)->a_next;
attr_free( tmp );
@ -167,7 +197,7 @@ add_created_attrs( Operation *op, Entry *e )
}
if ( op->o_dn == NULL || op->o_dn[0] == '\0' ) {
bv.bv_val = "NULLDN";
bv.bv_val = "<anonymous>";
bv.bv_len = strlen( bv.bv_val );
} else {
bv.bv_val = op->o_dn;
@ -175,10 +205,16 @@ add_created_attrs( Operation *op, Entry *e )
}
attr_merge( e, "creatorsname", bvals );
pthread_mutex_lock( &currenttime_mutex );
ltm = localtime( &currenttime );
strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm );
pthread_mutex_unlock( &currenttime_mutex );
currenttime = slap_get_time();
ldap_pvt_thread_mutex_lock( &gmtime_mutex );
#ifndef LDAP_LOCALTIME
ltm = gmtime( &currenttime );
strftime( buf, sizeof(buf), "%Y%m%d%H%M%SZ", ltm );
#else
ltm = localtime( &currenttime );
strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm );
#endif
ldap_pvt_thread_mutex_unlock( &gmtime_mutex );
bv.bv_val = buf;
bv.bv_len = strlen( bv.bv_val );

View file

@ -0,0 +1,547 @@
/* search.c - bdb2 backend search function */
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include <ac/socket.h>
#include <ac/time.h>
#include "slap.h"
#include "back-bdb2.h"
#include "proto-back-bdb2.h"
static ID_BLOCK *base_candidates(BackendDB *be, Connection *conn, Operation *op, char *base, Filter *filter, char **attrs, int attrsonly, char **matched, int *err);
static ID_BLOCK *onelevel_candidates(BackendDB *be, Connection *conn, Operation *op, char *base, Filter *filter, char **attrs, int attrsonly, char **matched, int *err);
static ID_BLOCK *subtree_candidates(BackendDB *be, Connection *conn, Operation *op, char *base, Filter *filter, char **attrs, int attrsonly, char **matched, Entry *e, int *err, int lookupbase);
#define GRABSIZE BUFSIZ
#define MAKE_SPACE( n ) { \
if ( rcur + (n) > rbuf + rmaxsize ) { \
int offset = rcur - rbuf; \
rbuf = ch_realloc( rbuf, rmaxsize + GRABSIZE ); \
rmaxsize += GRABSIZE; \
rcur = rbuf + offset; \
} \
}
static int
bdb2i_back_search_internal(
BackendDB *be,
Connection *conn,
Operation *op,
char *base,
int scope,
int deref,
int slimit,
int tlimit,
Filter *filter,
char *filterstr,
char **attrs,
int attrsonly
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
int err;
time_t stoptime;
ID_BLOCK *candidates;
ID id;
Entry *e;
Attribute *ref;
char *matched = NULL;
int rmaxsize, nrefs;
char *rbuf, *rcur;
int nentries = 0;
char *realBase;
Debug(LDAP_DEBUG_ARGS, "=> bdb2i_back_search\n", 0, 0, 0);
if ( tlimit == 0 && be_isroot( be, op->o_ndn ) ) {
tlimit = -1; /* allow root to set no limit */
} else {
tlimit = (tlimit > be->be_timelimit || tlimit < 1) ?
be->be_timelimit : tlimit;
stoptime = op->o_time + tlimit;
}
if ( slimit == 0 && be_isroot( be, op->o_ndn ) ) {
slimit = -1; /* allow root to set no limit */
} else {
slimit = (slimit > be->be_sizelimit || slimit < 1) ?
be->be_sizelimit : slimit;
}
/*
* check and apply aliasing where the dereferencing applies to
* the subordinates of the base
*/
switch ( deref ) {
case LDAP_DEREF_FINDING:
case LDAP_DEREF_ALWAYS:
realBase = bdb2i_derefDN ( be, conn, op, base );
break;
default:
realBase = ch_strdup(base);
}
(void) dn_normalize_case( realBase );
Debug( LDAP_DEBUG_TRACE, "using base \"%s\"\n",
realBase, 0, 0 );
switch ( scope ) {
case LDAP_SCOPE_BASE:
candidates = base_candidates( be, conn, op, realBase, filter,
attrs, attrsonly, &matched, &err );
break;
case LDAP_SCOPE_ONELEVEL:
candidates = onelevel_candidates( be, conn, op, realBase, filter,
attrs, attrsonly, &matched, &err );
break;
case LDAP_SCOPE_SUBTREE:
candidates = subtree_candidates( be, conn, op, realBase, filter,
attrs, attrsonly, &matched, NULL, &err, 1 );
break;
default:
send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, "",
"Bad scope" );
if( realBase != NULL) {
free( realBase );
}
return( -1 );
}
/* null candidates means we could not find the base object */
if ( candidates == NULL ) {
send_ldap_result( conn, op, err, matched, "" );
if ( matched != NULL ) {
free( matched );
}
if( realBase != NULL) {
free( realBase );
}
return( -1 );
}
if ( matched != NULL ) {
free( matched );
}
rmaxsize = 0;
nrefs = 0;
rbuf = rcur = NULL;
MAKE_SPACE( sizeof("Referral:") + 1 );
strcpy( rbuf, "Referral:" );
rcur = strchr( rbuf, '\0' );
for ( id = bdb2i_idl_firstid( candidates ); id != NOID;
id = bdb2i_idl_nextid( candidates, id ) ) {
/* check for abandon */
ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
if ( op->o_abandon ) {
ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
bdb2i_idl_free( candidates );
free( rbuf );
if( realBase != NULL) {
free( realBase );
}
return( 0 );
}
ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
/* check time limit */
if ( tlimit != -1 && slap_get_time() > stoptime ) {
send_search_result( conn, op,
LDAP_TIMELIMIT_EXCEEDED, NULL, nrefs > 0 ? rbuf :
NULL, nentries );
bdb2i_idl_free( candidates );
free( rbuf );
if( realBase != NULL) {
free( realBase );
}
return( 0 );
}
/* get the entry with reader lock */
if ( (e = bdb2i_id2entry_r( be, id )) == NULL ) {
Debug( LDAP_DEBUG_ARGS, "candidate %ld not found\n",
id, 0, 0 );
continue;
}
/*
* if it's a referral, add it to the list of referrals. only do
* this for subtree searches, and don't check the filter explicitly
* here since it's only a candidate anyway.
*/
if ( scope == LDAP_SCOPE_SUBTREE &&
e->e_ndn != NULL &&
strncmp( e->e_ndn, "REF=", 4 ) == 0 &&
(ref = attr_find( e->e_attrs, "ref" )) != NULL )
{
int i;
if ( ref->a_vals == NULL ) {
Debug( LDAP_DEBUG_ANY, "null ref in (%s)\n",
e->e_dn, 0, 0 );
} else {
if( op->o_protocol < LDAP_VERSION3 ) {
for ( i = 0; ref->a_vals[i] != NULL; i++ ) {
/* referral + newline + null */
MAKE_SPACE( ref->a_vals[i]->bv_len + 2 );
*rcur++ = '\n';
strncpy( rcur, ref->a_vals[i]->bv_val,
ref->a_vals[i]->bv_len );
rcur = rcur + ref->a_vals[i]->bv_len;
*rcur = '\0';
nrefs++;
}
} else {
send_search_reference( conn, op, ref->a_vals );
}
}
/* otherwise it's an entry - see if it matches the filter */
} else {
/* if it matches the filter and scope, send it */
if ( test_filter( be, conn, op, e, filter ) == 0 ) {
int scopeok;
char *dn;
/* check scope */
scopeok = 1;
if ( scope == LDAP_SCOPE_ONELEVEL ) {
if ( (dn = dn_parent( be, e->e_dn )) != NULL ) {
(void) dn_normalize_case( dn );
scopeok = (dn == realBase)
? 1
: (strcmp( dn, realBase ) ? 0 : 1 );
free( dn );
} else {
scopeok = (realBase == NULL || *realBase == '\0');
}
} else if ( scope == LDAP_SCOPE_SUBTREE ) {
dn = ch_strdup( e->e_ndn );
scopeok = dn_issuffix( dn, realBase );
free( dn );
}
if ( scopeok ) {
/* check size limit */
if ( --slimit == -1 ) {
bdb2i_cache_return_entry_r( &li->li_cache, e );
send_search_result( conn, op,
LDAP_SIZELIMIT_EXCEEDED, NULL,
nrefs > 0 ? rbuf : NULL, nentries );
bdb2i_idl_free( candidates );
free( rbuf );
if( realBase != NULL) {
free( realBase );
}
return( 0 );
}
/*
* check and apply aliasing where the dereferencing applies to
* the subordinates of the base
*/
switch ( deref ) {
case LDAP_DEREF_SEARCHING:
case LDAP_DEREF_ALWAYS:
{
Entry *newe = bdb2i_derefAlias_r( be, conn, op, e );
if ( newe == NULL ) { /* problem with the alias */
bdb2i_cache_return_entry_r( &li->li_cache, e );
e = NULL;
}
else if ( newe != e ) { /* reassign e */
bdb2i_cache_return_entry_r( &li->li_cache, e );
e = newe;
}
}
break;
}
if (e) {
switch ( send_search_entry( be, conn, op, e,
attrs, attrsonly, 0 ) ) {
case 0: /* entry sent ok */
nentries++;
break;
case 1: /* entry not sent */
break;
case -1: /* connection closed */
bdb2i_cache_return_entry_r( &li->li_cache, e );
bdb2i_idl_free( candidates );
free( rbuf );
if( realBase != NULL) {
free( realBase );
}
return( 0 );
}
}
}
}
}
if( e != NULL ) {
/* free reader lock */
bdb2i_cache_return_entry_r( &li->li_cache, e );
}
ldap_pvt_thread_yield();
}
bdb2i_idl_free( candidates );
if ( nrefs > 0 ) {
send_search_result( conn, op, LDAP_REFERRALS, NULL,
rbuf, nentries );
} else {
send_search_result( conn, op, LDAP_SUCCESS, NULL, NULL,
nentries );
}
free( rbuf );
if( realBase != NULL) {
free( realBase );
}
return( 0 );
}
int
bdb2_back_search(
BackendDB *be,
Connection *conn,
Operation *op,
char *base,
int scope,
int deref,
int slimit,
int tlimit,
Filter *filter,
char *filterstr,
char **attrs,
int attrsonly
)
{
DB_LOCK lock;
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
struct timeval time1;
int ret;
bdb2i_start_timing( be->bd_info, &time1 );
if ( bdb2i_enter_backend_r( &lock ) != 0 ) {
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
return( -1 );
}
ret = bdb2i_back_search_internal( be, conn, op, base, scope, deref,
slimit, tlimit, filter, filterstr, attrs, attrsonly );
(void) bdb2i_leave_backend_r( lock );
bdb2i_stop_timing( be->bd_info, time1, "SRCH", conn, op );
return( ret );
}
static ID_BLOCK *
base_candidates(
BackendDB *be,
Connection *conn,
Operation *op,
char *base,
Filter *filter,
char **attrs,
int attrsonly,
char **matched,
int *err
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
ID_BLOCK *idl;
Entry *e;
Debug(LDAP_DEBUG_TRACE, "base_candidates: base: \"%s\"\n", base, 0, 0);
*err = LDAP_SUCCESS;
/* get entry with reader lock */
if ( (e = bdb2i_dn2entry_r( be, base, matched )) == NULL ) {
*err = LDAP_NO_SUCH_OBJECT;
return( NULL );
}
/* check for deleted */
idl = bdb2i_idl_alloc( 1 );
bdb2i_idl_insert( &idl, e->e_id, 1 );
/* free reader lock */
bdb2i_cache_return_entry_r( &li->li_cache, e );
return( idl );
}
static ID_BLOCK *
onelevel_candidates(
BackendDB *be,
Connection *conn,
Operation *op,
char *base,
Filter *filter,
char **attrs,
int attrsonly,
char **matched,
int *err
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
Entry *e = NULL;
Filter *f;
char buf[20];
ID_BLOCK *candidates;
Debug(LDAP_DEBUG_TRACE, "onelevel_candidates: base: \"%s\"\n", base, 0, 0);
*err = LDAP_SUCCESS;
/* get the base object with reader lock */
if ( base != NULL && *base != '\0' &&
(e = bdb2i_dn2entry_r( be, base, matched )) == NULL )
{
*err = LDAP_NO_SUCH_OBJECT;
return( NULL );
}
/*
* modify the filter to be something like this:
*
* parent=baseobject & originalfilter
*/
f = (Filter *) ch_malloc( sizeof(Filter) );
f->f_next = NULL;
f->f_choice = LDAP_FILTER_AND;
f->f_and = (Filter *) ch_malloc( sizeof(Filter) );
f->f_and->f_choice = LDAP_FILTER_EQUALITY;
f->f_and->f_ava.ava_type = ch_strdup( "id2children" );
sprintf( buf, "%ld", e != NULL ? e->e_id : 0 );
f->f_and->f_ava.ava_value.bv_val = ch_strdup( buf );
f->f_and->f_ava.ava_value.bv_len = strlen( buf );
f->f_and->f_next = filter;
/* from here, it's just like subtree_candidates */
candidates = subtree_candidates( be, conn, op, base, f, attrs,
attrsonly, matched, e, err, 0 );
/* free up just the filter stuff we allocated above */
f->f_and->f_next = NULL;
filter_free( f );
/* free entry and reader lock */
if( e != NULL ) {
bdb2i_cache_return_entry_r( &li->li_cache, e );
}
return( candidates );
}
static ID_BLOCK *
subtree_candidates(
BackendDB *be,
Connection *conn,
Operation *op,
char *base,
Filter *filter,
char **attrs,
int attrsonly,
char **matched,
Entry *e,
int *err,
int lookupbase
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
Filter *f, **filterarg_ptr;
ID_BLOCK *candidates;
Debug(LDAP_DEBUG_TRACE, "subtree_candidates: base: \"%s\" %s\n",
base ? base : "NULL", lookupbase ? "lookupbase" : "", 0);
/*
* get the base object - unless we already have it (from one-level).
* also, unless this is a one-level search or a subtree search
* starting at the very top of our subtree, we need to modify the
* filter to be something like this:
*
* dn=*baseobjectdn & (originalfilter | ref=*)
*
* the "objectclass=referral" part is used to select referrals to return
*/
*err = LDAP_SUCCESS;
f = NULL;
if ( lookupbase ) {
e = NULL;
if ( base != NULL && *base != '\0' &&
(e = bdb2i_dn2entry_r( be, base, matched )) == NULL )
{
*err = LDAP_NO_SUCH_OBJECT;
return( NULL );
}
if (e) {
bdb2i_cache_return_entry_r( &li->li_cache, e );
}
f = (Filter *) ch_malloc( sizeof(Filter) );
f->f_next = NULL;
f->f_choice = LDAP_FILTER_OR;
f->f_or = (Filter *) ch_malloc( sizeof(Filter) );
f->f_or->f_choice = LDAP_FILTER_EQUALITY;
f->f_or->f_avtype = ch_strdup( "objectclass" );
/* Patch to use normalized uppercase */
f->f_or->f_avvalue.bv_val = ch_strdup( "REFERRAL" );
f->f_or->f_avvalue.bv_len = strlen( "REFERRAL" );
filterarg_ptr = &f->f_or->f_next;
*filterarg_ptr = filter;
filter = f;
if ( ! be_issuffix( be, base ) ) {
f = (Filter *) ch_malloc( sizeof(Filter) );
f->f_next = NULL;
f->f_choice = LDAP_FILTER_AND;
f->f_and = (Filter *) ch_malloc( sizeof(Filter) );
f->f_and->f_choice = LDAP_FILTER_SUBSTRINGS;
f->f_and->f_sub_type = ch_strdup( "dn" );
f->f_and->f_sub_initial = NULL;
f->f_and->f_sub_any = NULL;
f->f_and->f_sub_final = ch_strdup( base );
value_normalize( f->f_and->f_sub_final, SYNTAX_CIS );
f->f_and->f_next = filter;
filter = f;
}
}
candidates = bdb2i_filter_candidates( be, filter );
/* free up just the parts we allocated above */
if ( f != NULL ) {
*filterarg_ptr = NULL;
filter_free( f );
}
return( candidates );
}

View file

@ -0,0 +1,172 @@
/* search.c - ldap backend search function */
/*
* Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
*
* Permission is granted to anyone to use this software for any purpose
* on any computer system, and to alter it and redistribute it, subject
* to the following restrictions:
*
* 1. The author is not responsible for the consequences of use of this
* software, no matter how awful, even if they arise from flaws in it.
*
* 2. The origin of this software must not be misrepresented, either by
* explicit claim or by omission. Since few users ever read sources,
* credits should appear in the documentation.
*
* 3. Altered versions must be plainly marked as such, and must not be
* misrepresented as being the original software. Since few users
* ever read sources, credits should appear in the documentation.
*
* 4. This notice may not be removed or altered.
*/
#include "portable.h"
#include <stdio.h>
#include <ac/socket.h>
#include <ac/string.h>
#include <ac/time.h>
#include "slap.h"
#include "back-ldap.h"
int
ldap_back_search(
Backend *be,
Connection *conn,
Operation *op,
char *base,
int scope,
int deref,
int size,
int time,
Filter *filter,
char *filterstr,
char **attrs,
int attrsonly
)
{
struct ldapinfo *li = (struct ldapinfo *) be->be_private;
struct ldapconn *lc;
struct timeval tv;
LDAPMessage *res, *e;
int i, rc, msgid, sres = LDAP_SUCCESS;
char *match = NULL, *err = NULL;
lc = ldap_back_getconn(li, conn, op);
if (!lc)
return( -1 );
if (deref != -1)
ldap_set_option( lc->ld, LDAP_OPT_DEREF, (void *)&deref);
if (time != -1)
ldap_set_option( lc->ld, LDAP_OPT_TIMELIMIT, (void *)&time);
if (size != -1)
ldap_set_option( lc->ld, LDAP_OPT_SIZELIMIT, (void *)&size);
if (!lc->bound) {
ldap_back_dobind(lc, op);
if (!lc->bound)
return( -1 );
}
if ((msgid = ldap_search(lc->ld, base, scope, filterstr, attrs,
attrsonly)) == -1)
fail: return( ldap_back_op_result(lc, op) );
/* We pull apart the ber result, stuff it into a slapd entry, and
* let send_search_entry stuff it back into ber format. Slow & ugly,
* but this is necessary for version matching, and for ACL processing.
*/
for (i=0, rc=0; rc != -1;
rc = ldap_result(lc->ld, LDAP_RES_ANY, 0, &tv, &res)) {
int ab;
/* check for abandon */
ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
ab = op->o_abandon;
ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
if (ab) {
ldap_abandon(lc->ld, msgid);
} else if (rc == 0) {
tv.tv_sec = 0;
tv.tv_usec = 100000;
ldap_pvt_thread_yield();
continue;
} else if (rc == LDAP_RES_SEARCH_ENTRY) {
e = ldap_first_entry(lc->ld,res);
ldap_send_entry(be, op, lc, e, attrs, attrsonly);
i++;
} else {
sres = ldap_result2error(lc->ld, res, 1);
ldap_get_option(lc->ld, LDAP_OPT_ERROR_STRING, &err);
ldap_get_option(lc->ld, LDAP_OPT_MATCHED_DN, &match);
rc = 0;
}
ldap_msgfree(res);
if (ab)
return (0);
else if (rc == 0)
break;
}
if (rc == -1)
goto fail;
send_search_result( conn, op, sres, match, err, i );
if (match)
free(match);
if (err)
free(err);
return( 0 );
}
ldap_send_entry(
Backend *be,
Operation *op,
struct ldapconn *lc,
LDAPMessage *e,
char **attrs,
int attrsonly
)
{
char *a;
Entry ent;
BerElement *ber = NULL;
Attribute *attr;
struct berval *dummy = NULL;
ent.e_dn = ldap_get_dn(lc->ld, e);
ent.e_ndn = dn_normalize_case( ch_strdup( ent.e_dn));
ent.e_id = 0;
ent.e_attrs = 0;
ent.e_private = 0;
attr = (Attribute *)4;
attr = (Attribute *)((long)&ent.e_attrs - ((long)&attr->a_next-4));
for (a = ldap_first_attribute(lc->ld, e, &ber); a;
a = ldap_next_attribute(lc->ld, e, ber)) {
attr->a_next = (Attribute *)ch_malloc( sizeof(Attribute) );
attr=attr->a_next;
attr->a_next = 0;
attr->a_type = ch_strdup(a);
attr->a_syntax = attr_syntax(a);
attr->a_vals = ldap_get_values_len(lc->ld, e, a);
if (!attr->a_vals)
attr->a_vals = &dummy;
}
send_search_entry( be, lc->conn, op, &ent, attrs, attrsonly, 0 );
for (;ent.e_attrs;) {
attr=ent.e_attrs;
ent.e_attrs = attr->a_next;
free(attr->a_type);
if (attr->a_vals != &dummy)
ber_bvecfree(attr->a_vals);
free(attr);
}
if (ber)
ber_free(ber,0);
}

View file

@ -1,16 +1,15 @@
/* add.c - ldap ldbm back-end add routine */
#include "portable.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <ac/socket.h>
#include <ac/string.h>
#include "slap.h"
#include "back-ldbm.h"
extern int global_schemacheck;
extern char *dn_parent();
extern char *dn_normalize();
extern Entry *dn2entry();
#include "proto-back-ldbm.h"
int
ldbm_back_add(
@ -21,49 +20,33 @@ ldbm_back_add(
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
char *matched;
char *dn = NULL, *pdn = NULL;
Entry *p;
char *pdn;
Entry *p = NULL;
int rootlock = 0;
int rc;
dn = dn_normalize( strdup( e->e_dn ) );
matched = NULL;
if ( (p = dn2entry( be, dn, &matched )) != NULL ) {
cache_return_entry( &li->li_cache, p );
Debug(LDAP_DEBUG_ARGS, "==> ldbm_back_add: %s\n", e->e_dn, 0, 0);
/* nobody else can add until we lock our parent */
ldap_pvt_thread_mutex_lock(&li->li_add_mutex);
if ( ( dn2id( be, e->e_ndn ) ) != NOID ) {
ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
entry_free( e );
free( dn );
send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, "", "" );
send_ldap_result( conn, op, LDAP_ALREADY_EXISTS,
NULL, NULL, NULL );
return( -1 );
}
if ( matched != NULL ) {
free( matched );
}
/* XXX race condition here til we cache_add_entry_lock below XXX */
if ( global_schemacheck && oc_schema_check( e ) != 0 ) {
Debug( LDAP_DEBUG_TRACE, "entry failed schema check\n", 0, 0,
0 );
entry_free( e );
free( dn );
send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION, "",
"" );
return( -1 );
}
ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
/*
* Try to add the entry to the cache, assign it a new dnid
* and mark it locked. This should only fail if the entry
* already exists.
*/
Debug( LDAP_DEBUG_TRACE, "entry failed schema check\n",
0, 0, 0 );
e->e_id = next_id( be );
if ( cache_add_entry_lock( &li->li_cache, e, ENTRY_STATE_CREATING )
!= 0 ) {
Debug( LDAP_DEBUG_ANY, "cache_add_entry_lock failed\n", 0, 0,
0 );
next_id_return( be, e->e_id );
entry_free( e );
free( dn );
send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, "", "" );
send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION,
NULL, NULL, NULL );
return( -1 );
}
@ -73,42 +56,122 @@ ldbm_back_add(
* add the entry.
*/
if ( (pdn = dn_parent( be, dn )) != NULL ) {
/* no parent */
matched = NULL;
if ( (p = dn2entry( be, pdn, &matched )) == NULL ) {
pdn = dn_parent( be, e->e_ndn );
if( pdn != NULL && *pdn != '\0' && !be_issuffix(be, "") ) {
char *matched = NULL;
assert( *pdn != '\0' );
/* get parent with writer lock */
if ( (p = dn2entry_w( be, pdn, &matched )) == NULL ) {
ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
Debug( LDAP_DEBUG_TRACE, "parent does not exist\n", 0,
0, 0 );
send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT,
matched, "" );
matched, NULL, NULL );
if ( matched != NULL ) {
free( matched );
}
Debug( LDAP_DEBUG_TRACE, "parent does not exist\n", 0,
0, 0 );
goto error_return;
entry_free( e );
free( pdn );
return -1;
}
/* don't need the add lock anymore */
ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
free(pdn);
if ( matched != NULL ) {
free( matched );
}
if ( ! access_allowed( be, conn, op, p, "children", NULL,
op->o_dn, ACL_WRITE ) ) {
if ( ! access_allowed( be, conn, op, p,
"children", NULL, ACL_WRITE ) )
{
Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
0, 0 );
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
"", "" );
goto error_return;
NULL, NULL, NULL );
/* free parent and writer lock */
cache_return_entry_w( &li->li_cache, p );
entry_free( e );
return -1;
}
} else {
if ( ! be_isroot( be, op->o_dn ) ) {
Debug( LDAP_DEBUG_TRACE, "no parent & not root\n", 0,
0, 0 );
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
"", "" );
goto error_return;
if(pdn != NULL) {
assert( *pdn == '\0' );
free(pdn);
}
p = NULL;
/* no parent, must be adding entry to root */
if ( ! be_isroot( be, op->o_ndn ) ) {
ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
Debug( LDAP_DEBUG_TRACE, "%s add denied\n",
pdn == NULL ? "suffix" : "entry at root",
0, 0 );
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
NULL, NULL, NULL );
entry_free( e );
return -1;
}
/*
* no parent, acquire the root write lock
* and release the add lock.
*/
ldap_pvt_thread_mutex_lock(&li->li_root_mutex);
rootlock = 1;
ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
}
e->e_id = next_id( be );
/*
* Try to add the entry to the cache, assign it a new dnid.
*/
rc = cache_add_entry_rw(&li->li_cache, e, CACHE_WRITE_LOCK);
if ( rc != 0 ) {
if( p != NULL) {
/* free parent and writer lock */
cache_return_entry_w( &li->li_cache, p );
}
if ( rootlock ) {
/* release root lock */
ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
}
Debug( LDAP_DEBUG_ANY, "cache_add_entry_lock failed\n", 0, 0,
0 );
/* return the id */
next_id_return( be, e->e_id );
/* free the entry */
entry_free( e );
if(rc > 0) {
send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, NULL, NULL, NULL );
} else {
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL, NULL );
}
return( -1 );
}
rc = -1;
/*
* add it to the id2children index for the parent
*/
@ -116,9 +179,9 @@ ldbm_back_add(
if ( id2children_add( be, p, e ) != 0 ) {
Debug( LDAP_DEBUG_TRACE, "id2children_add failed\n", 0,
0, 0 );
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "",
"" );
goto error_return;
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL, NULL );
goto return_results;
}
/*
@ -130,44 +193,48 @@ ldbm_back_add(
if ( index_add_entry( be, e ) != 0 ) {
Debug( LDAP_DEBUG_TRACE, "index_add_entry failed\n", 0,
0, 0 );
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
goto error_return;
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL, NULL );
goto return_results;
}
/* dn2id index */
if ( dn2id_add( be, dn, e->e_id ) != 0 ) {
if ( dn2id_add( be, e->e_ndn, e->e_id ) != 0 ) {
Debug( LDAP_DEBUG_TRACE, "dn2id_add failed\n", 0,
0, 0 );
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
goto error_return;
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL, NULL );
goto return_results;
}
/* id2entry index */
if ( id2entry_add( be, e ) != 0 ) {
Debug( LDAP_DEBUG_TRACE, "id2entry_add failed\n", 0,
0, 0 );
(void) dn2id_delete( be, dn );
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
goto error_return;
(void) dn2id_delete( be, e->e_ndn );
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL, NULL );
goto return_results;
}
send_ldap_result( conn, op, LDAP_SUCCESS, "", "" );
if ( dn != NULL )
free( dn );
if ( pdn != NULL )
free( pdn );
cache_set_state( &li->li_cache, e, 0 );
cache_return_entry( &li->li_cache, e );
return( 0 );
send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL );
rc = 0;
error_return:;
if ( dn != NULL )
free( dn );
if ( pdn != NULL )
free( pdn );
next_id_return( be, e->e_id );
cache_delete_entry( &li->li_cache, e );
cache_return_entry( &li->li_cache, e );
return_results:;
if (p != NULL) {
/* free parent and writer lock */
cache_return_entry_w( &li->li_cache, p );
}
return( -1 );
if ( rootlock ) {
/* release root lock */
ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
}
if ( rc ) {
/* free entry and writer lock */
cache_return_entry_w( &li->li_cache, e );
}
return( rc );
}

View file

@ -0,0 +1,321 @@
/*
* Copyright (c) 1998 Will Ballantyne, ITSD, Government of BC
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to ITSD, Government of BC. The name of ITSD
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
*/
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "slap.h"
#include "back-ldbm.h"
#include "proto-back-ldbm.h"
/*
* given an alias object, dereference it to its end point.
* Entry returned has reader lock or is NULL. Starting entry is not released.
*/
Entry *derefAlias_r ( Backend *be,
Connection *conn,
Operation *op,
Entry *e)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private; /* to free cache entries */
Attribute *a;
int depth;
char *matched;
Entry *origDN = e;
if (!e) return NULL; /* be sure we have a starting entry */
Debug( LDAP_DEBUG_TRACE, "<= checking for alias for dn %s\n", e->e_dn, 0, 0 );
/*
* try to deref fully, up to a maximum depth. If the max depth exceeded
* then send an error
*/
for ( depth = 0;
( ( a = attr_find( e->e_attrs, "aliasedobjectname" ) ) != NULL) &&
( depth < be->be_maxDerefDepth );
++depth)
{
/*
* make sure there is a defined aliasedobjectname.
* can only have one value so just use first value (0) in the attr list.
*/
if (a->a_vals[0] && a->a_vals[0]->bv_val) {
char *newDN, *oldDN;
Debug( LDAP_DEBUG_TRACE, "<= %s is an alias for %s\n",
e->e_dn, a->a_vals[0]->bv_val, 0 );
newDN = ch_strdup (a->a_vals[0]->bv_val);
oldDN = ch_strdup (e->e_ndn);
/*
* release past lock if not original
*/
if ( (depth > 0) && e ) {
cache_return_entry_r(&li->li_cache, e);
}
/* make sure new and old DN are not same to avoid loops */
dn_normalize_case (newDN);
if ( strcmp (newDN, oldDN) == 0 ) {
Debug( LDAP_DEBUG_TRACE,
"<= %s alias is same as current %s\n",
oldDN, newDN, 0 );
send_ldap_result( conn, op, LDAP_ALIAS_DEREF_PROBLEM,
NULL, "circular alias", NULL );
free (newDN);
free (oldDN);
break;
}
/* make sure new and original are not same to avoid deadlocks */
if ( strcmp (newDN, origDN->e_ndn) == 0 ) {
Debug( LDAP_DEBUG_TRACE,
"<= %s alias is same as original %s\n",
oldDN, origDN->e_ndn, 0 );
send_ldap_result( conn, op, LDAP_ALIAS_DEREF_PROBLEM,
NULL, "circular alias", NULL );
free (newDN);
free (oldDN);
break;
}
/*
* ok, so what happens if there is an alias in the DN of a dereferenced
* alias object?
*/
if ( (e = dn2entry_r( be, newDN, &matched )) == NULL ) {
/* could not deref return error */
Debug( LDAP_DEBUG_TRACE,
"<= %s is a dangling alias to %s\n",
oldDN, newDN, 0 );
send_ldap_result( conn, op, LDAP_ALIAS_DEREF_PROBLEM,
NULL, "dangling alias", NULL );
if (matched != NULL) free(matched);
free (newDN);
free (oldDN);
break;
}
free (newDN);
free (oldDN);
}
else {
/*
* there was an aliasedobjectname defined but no data.
* this can't happen, right?
*/
Debug( LDAP_DEBUG_TRACE,
"<= %s has no data in aliasedobjectname attribute\n",
(e && e->e_dn) ? e->e_dn : "(null)", 0, 0 );
send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM,
NULL, "alias missing aliasedObjectName", NULL );
break;
}
}
/*
* warn if we pulled out due to exceeding the maximum deref depth
*/
if ( depth >= be->be_maxDerefDepth ) {
Debug( LDAP_DEBUG_TRACE,
"<= deref(\"%s\") exceeded maximum deref depth (%d) at \"%s\"\n",
origDN->e_dn ? origDN->e_dn : "(null)",
be->be_maxDerefDepth,
(e && e->e_ndn) ? e->e_ndn : "(null)");
send_ldap_result( conn, op, LDAP_ALIAS_DEREF_PROBLEM,
NULL, "maximum alias dereference depth exceeded", NULL );
}
return e;
}
/*
* given a DN fully deref it and return the real DN or original DN if it fails
* This involves finding the last matched part then reconstructing forward
* e.g.
* ou=MyOU,o=MyAliasedOrg,c=MyCountry where o=MyAliasedOrg is an alias for o=MyOrg
* loop starts with newDN = ou=MyOU,o=MyAliasedOrg,c=MyCountry
* dn2entry_r on newDN gives null entry and o=MyAliasedOrg,c=MyCountry matched
* dn2entry_r on matched gives o=MyAliasedOrg,c=MyCountry entry
* remainder is ou=MyOU
* dereferencing o=MyAliasedOrg,c=MyCountry yields entry o=MyOrg,c=MyCountry
* release lock on o=MyAliasedOrg,c=MyCountry entry
* reconstructed dn is ou=MyOU,o=MyOrg,c=MyCountry
* release lock on o=MyOrg,c=MyCountry entry
*/
char *derefDN ( Backend *be,
Connection *conn,
Operation *op,
char *dn
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
char *matched = 0;
char *newDN = NULL;
int depth, i;
Entry *eMatched;
Entry *eDeref;
Entry *eNew;
if (!dn) return NULL;
Debug( LDAP_DEBUG_TRACE,
"<= dereferencing dn: \"%s\"\n",
dn, 0, 0 );
newDN = ch_strdup ( dn );
/* while we don't have a matched dn, deref the DN */
for ( depth = 0;
( (eMatched = dn2entry_r( be, newDN, &matched )) == NULL) &&
(depth < be->be_maxDerefDepth);
++depth ) {
if ((matched != NULL) && *matched) {
char *submatch;
/*
* make sure there actually is an entry for the matched part
*/
if ( (eMatched = dn2entry_r( be, matched, &submatch )) != NULL) {
char *remainder; /* part before the aliased part */
int rlen = strlen(newDN) - strlen(matched);
Debug( LDAP_DEBUG_TRACE, "<= matched %s\n", matched, 0, 0 );
remainder = ch_malloc (rlen + 1);
strncpy ( remainder, newDN, rlen );
remainder[rlen] = '\0';
Debug( LDAP_DEBUG_TRACE, "<= remainder %s\n", remainder, 0, 0 );
if ((eNew = derefAlias_r( be, conn, op, eMatched )) == NULL) {
free (matched);
matched = NULL;
free (newDN);
newDN = NULL;
free (remainder);
remainder = NULL;
cache_return_entry_r(&li->li_cache, eMatched);
eMatched = NULL;
break; /* no associated entry, dont deref */
}
else {
Debug( LDAP_DEBUG_TRACE, "<= l&g we have %s vs %s \n", matched, eNew->e_dn, 0 );
i = strcasecmp (matched, eNew->e_dn);
/* free reader lock */
cache_return_entry_r(&li->li_cache, eNew);
free (matched);
matched = NULL;
if (! i) {
/* newDN same as old so not an alias, no need to go further */
free (newDN);
newDN = NULL;
free (remainder);
cache_return_entry_r(&li->li_cache, eMatched);
eMatched = NULL;
break;
}
/*
* we have dereferenced the aliased part so put
* the new dn together
*/
free (newDN);
newDN = ch_malloc (strlen(eMatched->e_dn) + rlen + 1);
strcpy (newDN, remainder);
strcat (newDN, eMatched->e_dn);
Debug( LDAP_DEBUG_TRACE, "<= expanded to %s\n", newDN, 0, 0 );
free (remainder);
}
/* free reader lock */
cache_return_entry_r(&li->li_cache, eMatched);
}
else {
if(submatch != NULL) free(submatch);
break; /* there was no entry for the matched part */
}
}
else {
break; /* there was no matched part */
}
}
/* release lock if a match terminated the loop, there should be no
* outstanding locks at this point
*/
if(eMatched != NULL) {
/* free reader lock */
cache_return_entry_r(&li->li_cache, eMatched);
}
/*
* the final part of the DN might be an alias so try to dereference it.
* e.g. if we had started with dn = o=MyAliasedOrg,c=MyCountry the dn would match
* and the above loop complete but we would still be left with an aliased DN.
*/
if (newDN != NULL) {
if ( (eNew = dn2entry_r( be, newDN, &matched )) != NULL) {
if ((eDeref = derefAlias_r( be, conn, op, eNew )) != NULL) {
free (newDN);
newDN = ch_strdup (eDeref->e_dn);
/* free reader lock */
cache_return_entry_r(&li->li_cache, eDeref);
}
/* free reader lock */
cache_return_entry_r(&li->li_cache, eNew);
}
}
if (matched != NULL) free(matched);
/*
* warn if we exceeded the max depth as the resulting DN may not be dereferenced
*/
if (depth >= be->be_maxDerefDepth) {
if (newDN) {
Debug( LDAP_DEBUG_TRACE,
"<= max deref depth exceeded in derefDN for \"%s\", result \"%s\"\n",
dn, newDN, 0 );
free (newDN);
newDN = NULL;
}
else {
Debug( LDAP_DEBUG_TRACE,
"<= max deref depth exceeded in derefDN for \"%s\", result NULL\n",
dn, 0, 0 );
}
send_ldap_result( conn, op, LDAP_ALIAS_DEREF_PROBLEM,
NULL, "maximum alias dereference depth exceeded for base", NULL );
}
if (newDN == NULL) {
newDN = ch_strdup ( dn );
}
Debug( LDAP_DEBUG_TRACE, "<= returning deref DN of \"%s\"\n", newDN, 0, 0 );
return newDN;
}

View file

@ -1,22 +1,63 @@
/* bind.c - ldbm backend bind and unbind routines */
#include "portable.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <ac/krb.h>
#include <ac/socket.h>
#include <ac/string.h>
#include <ac/unistd.h>
#include "slap.h"
#include "back-ldbm.h"
#ifdef KERBEROS
#include "krb.h"
#endif
#include "proto-back-ldbm.h"
extern Entry *dn2entry();
extern Attribute *attr_find();
#include <lutil.h>
#ifdef KERBEROS
#ifdef HAVE_KERBEROS
extern int krbv4_ldap_auth();
#endif
static int
crypted_value_find(
struct berval **vals,
struct berval *v,
int syntax,
int normalize,
struct berval *cred
)
{
int i;
for ( i = 0; vals[i] != NULL; i++ ) {
if ( syntax != SYNTAX_BIN ) {
int result;
#ifdef SLAPD_CRYPT
ldap_pvt_thread_mutex_lock( &crypt_mutex );
#endif
result = lutil_passwd(
(char*) cred->bv_val,
(char*) vals[i]->bv_val,
NULL );
#ifdef SLAPD_CRYPT
ldap_pvt_thread_mutex_unlock( &crypt_mutex );
#endif
return result;
} else {
if ( value_cmp( vals[i], v, syntax, normalize ) == 0 ) {
return( 0 );
}
}
}
return( 1 );
}
int
ldbm_back_bind(
Backend *be,
@ -24,127 +65,209 @@ ldbm_back_bind(
Operation *op,
char *dn,
int method,
struct berval *cred
char *mech,
struct berval *cred,
char** edn
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
Entry *e;
Attribute *a;
int rc;
char *matched = NULL;
#ifdef KERBEROS
char *matched;
#ifdef HAVE_KERBEROS
char krbname[MAX_K_NAME_SZ + 1];
AUTH_DAT ad;
#endif
if ( (e = dn2entry( be, dn, &matched )) == NULL ) {
Debug(LDAP_DEBUG_ARGS, "==> ldbm_back_bind: dn: %s\n", dn, 0, 0);
*edn = NULL;
/* get entry with reader lock */
if ( (e = dn2entry_r( be, dn, &matched )) == NULL ) {
/* allow noauth binds */
if ( method == LDAP_AUTH_SIMPLE && cred->bv_len == 0 ) {
/*
* bind successful, but return 1 so we don't
* authorize based on noauth credentials
*/
send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
rc = 1;
} else if ( be_isroot_pw( be, dn, cred ) ) {
/* front end will send result */
rc = 0;
rc = 1;
if ( method == LDAP_AUTH_SIMPLE ) {
if( cred->bv_len == 0 ) {
/* SUCCESS */
send_ldap_result( conn, op, LDAP_SUCCESS,
NULL, NULL, NULL );
} else if ( be_isroot_pw( be, dn, cred ) ) {
*edn = ch_strdup( be_root_dn( be ) );
rc = 0; /* front end will send result */
} else {
send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT,
matched, NULL, NULL );
}
} else if ( method == LDAP_AUTH_SASL ) {
if( mech != NULL && strcasecmp(mech,"DIGEST-MD5") == 0 ) {
/* insert DIGEST calls here */
send_ldap_result( conn, op, LDAP_AUTH_METHOD_NOT_SUPPORTED,
NULL, NULL, NULL );
} else {
send_ldap_result( conn, op, LDAP_AUTH_METHOD_NOT_SUPPORTED,
NULL, NULL, NULL );
}
} else {
send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT,
matched, NULL );
rc = 1;
matched, NULL, NULL );
}
if ( matched != NULL ) {
free( matched );
}
return( rc );
}
*edn = ch_strdup( e->e_dn );
/* check for deleted */
if ( ! access_allowed( be, conn, op, e,
"entry", NULL, ACL_AUTH ) )
{
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
NULL, NULL, NULL );
rc = 1;
goto return_results;
}
switch ( method ) {
case LDAP_AUTH_SIMPLE:
if ( cred->bv_len == 0 ) {
send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
return( 1 );
} else if ( be_isroot_pw( be, dn, cred ) ) {
send_ldap_result( conn, op, LDAP_SUCCESS,
NULL, NULL, NULL );
/* stop front end from sending result */
rc = 1;
goto return_results;
}
/* check for root dn/passwd */
if ( be_isroot_pw( be, dn, cred ) ) {
/* front end will send result */
return( 0 );
if(*edn != NULL) free( *edn );
*edn = ch_strdup( be_root_dn( be ) );
rc = 0;
goto return_results;
}
if ( ! access_allowed( be, conn, op, e,
"userpassword", NULL, ACL_AUTH ) )
{
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
NULL, NULL, NULL );
rc = 1;
goto return_results;
}
if ( (a = attr_find( e->e_attrs, "userpassword" )) == NULL ) {
if ( be_isroot_pw( be, dn, cred ) ) {
/* front end will send result */
return( 0 );
}
send_ldap_result( conn, op, LDAP_INAPPROPRIATE_AUTH,
NULL, NULL );
cache_return_entry( &li->li_cache, e );
return( 1 );
NULL, NULL, NULL );
/* stop front end from sending result */
rc = 1;
goto return_results;
}
if ( value_find( a->a_vals, cred, a->a_syntax, 0 ) != 0 ) {
if ( be_isroot_pw( be, dn, cred ) ) {
/* front end will send result */
return( 0 );
}
if ( crypted_value_find( a->a_vals, cred, a->a_syntax, 0, cred ) != 0 )
{
send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS,
NULL, NULL );
cache_return_entry( &li->li_cache, e );
return( 1 );
NULL, NULL, NULL );
/* stop front end from sending result */
rc = 1;
goto return_results;
}
rc = 0;
break;
#ifdef KERBEROS
#ifdef HAVE_KERBEROS
case LDAP_AUTH_KRBV41:
if ( ! access_allowed( be, conn, op, e,
"krbname", NULL, ACL_AUTH ) )
{
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, NULL, NULL, NULL );
rc = 1;
goto return_results;
}
if ( krbv4_ldap_auth( be, cred, &ad ) != LDAP_SUCCESS ) {
send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS,
NULL, NULL );
cache_return_entry( &li->li_cache, e );
return( 1 );
rc = 1;
goto return_results;
}
if ( ! access_allowed( be, conn, op, e,
"krbname", NULL, ACL_AUTH ) )
{
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, "", "" );
rc = 1;
goto return_results;
}
sprintf( krbname, "%s%s%s@%s", ad.pname, *ad.pinst ? "."
: "", ad.pinst, ad.prealm );
if ( (a = attr_find( e->e_attrs, "krbname" )) == NULL ) {
/*
* no krbName values present: check against DN
*/
if ( strcasecmp( dn, krbname ) == 0 ) {
rc = 0;
break;
}
send_ldap_result( conn, op, LDAP_INAPPROPRIATE_AUTH,
NULL, NULL );
cache_return_entry( &li->li_cache, e );
return( 1 );
rc = 1;
goto return_results;
} else { /* look for krbName match */
struct berval krbval;
krbval.bv_val = krbname;
krbval.bv_len = strlen( krbname );
if ( value_find( a->a_vals, &krbval, a->a_syntax, 3 )
!= 0 ) {
if ( value_find( a->a_vals, &krbval, a->a_syntax, 3 ) != 0 ) {
send_ldap_result( conn, op,
LDAP_INVALID_CREDENTIALS, NULL, NULL );
cache_return_entry( &li->li_cache, e );
return( 1 );
rc = 1;
goto return_results;
}
}
rc = 0;
break;
case LDAP_AUTH_KRBV42:
send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
cache_return_entry( &li->li_cache, e );
return( 1 );
/* stop front end from sending result */
rc = 1;
goto return_results;
#endif
case LDAP_AUTH_SASL:
/* insert SASL code here */
default:
send_ldap_result( conn, op, LDAP_STRONG_AUTH_NOT_SUPPORTED,
NULL, "auth method not supported" );
cache_return_entry( &li->li_cache, e );
return( 1 );
NULL, "auth method not supported", NULL );
rc = 1;
goto return_results;
}
cache_return_entry( &li->li_cache, e );
return_results:;
/* free entry and reader lock */
cache_return_entry_r( &li->li_cache, e );
/* success: front end will send result */
return( 0 );
/* front end with send result on success (rc==0) */
return( rc );
}

View file

@ -1,14 +1,15 @@
/* compare.c - ldbm backend compare routine */
#include "portable.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <ac/socket.h>
#include <ac/string.h>
#include "slap.h"
#include "back-ldbm.h"
extern Entry *dn2entry();
extern Attribute *attr_find();
#include "proto-back-ldbm.h"
int
ldbm_back_compare(
@ -23,33 +24,44 @@ ldbm_back_compare(
char *matched;
Entry *e;
Attribute *a;
int i;
int rc;
if ( (e = dn2entry( be, dn, &matched )) == NULL ) {
send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, "" );
/* get entry with reader lock */
if ( (e = dn2entry_r( be, dn, &matched )) == NULL ) {
send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT,
matched, NULL, NULL );
if(matched == NULL) free(matched);
return( 1 );
}
if ( ! access_allowed( be, conn, op, e, ava->ava_type, &ava->ava_value,
op->o_dn, ACL_COMPARE ) ) {
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, "", "" );
cache_return_entry( &li->li_cache, e );
return( 1 );
/* check for deleted */
if ( ! access_allowed( be, conn, op, e,
ava->ava_type, &ava->ava_value, ACL_COMPARE ) )
{
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
NULL, NULL, NULL );
rc = 1;
goto return_results;
}
if ( (a = attr_find( e->e_attrs, ava->ava_type )) == NULL ) {
send_ldap_result( conn, op, LDAP_NO_SUCH_ATTRIBUTE, "", "" );
cache_return_entry( &li->li_cache, e );
return( 1 );
send_ldap_result( conn, op, LDAP_NO_SUCH_ATTRIBUTE,
NULL, NULL, NULL );
rc = 1;
goto return_results;
}
if ( value_find( a->a_vals, &ava->ava_value, a->a_syntax, 1 ) == 0 ) {
send_ldap_result( conn, op, LDAP_COMPARE_TRUE, "", "" );
cache_return_entry( &li->li_cache, e );
return( 0 );
}
if ( value_find( a->a_vals, &ava->ava_value, a->a_syntax, 1 ) == 0 )
send_ldap_result( conn, op, LDAP_COMPARE_TRUE,
NULL, NULL, NULL );
else
send_ldap_result( conn, op, LDAP_COMPARE_FALSE,
NULL, NULL, NULL );
send_ldap_result( conn, op, LDAP_COMPARE_FALSE, "", "" );
cache_return_entry( &li->li_cache, e );
return( 0 );
rc = 0;
return_results:;
cache_return_entry_r( &li->li_cache, e );
return( rc );
}

View file

@ -1,14 +1,15 @@
/* delete.c - ldbm backend delete routine */
#include "portable.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "slap.h"
#include "back-ldbm.h"
extern Entry *dn2entry();
extern Attribute *attr_find();
#include "proto-back-ldbm.h"
int
ldbm_back_delete(
@ -19,49 +20,137 @@ ldbm_back_delete(
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
char *matched = NULL;
Entry *e;
char *matched = NULL;
char *pdn = NULL;
Entry *e, *p = NULL;
int rootlock = 0;
int rc = -1;
if ( (e = dn2entry( be, dn, &matched )) == NULL ) {
send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, "" );
Debug(LDAP_DEBUG_ARGS, "==> ldbm_back_delete: %s\n", dn, 0, 0);
/* get entry with writer lock */
if ( (e = dn2entry_w( be, dn, &matched )) == NULL ) {
Debug(LDAP_DEBUG_ARGS, "<=- ldbm_back_delete: no such object %s\n",
dn, 0, 0);
send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT,
matched, NULL, NULL );
if ( matched != NULL ) {
free( matched );
}
return( -1 );
}
/* check for deleted */
if ( has_children( be, e ) ) {
send_ldap_result( conn, op, LDAP_NOT_ALLOWED_ON_NONLEAF, "",
"" );
cache_return_entry( &li->li_cache, e );
return( -1 );
Debug(LDAP_DEBUG_ARGS, "<=- ldbm_back_delete: non leaf %s\n",
dn, 0, 0);
send_ldap_result( conn, op, LDAP_NOT_ALLOWED_ON_NONLEAF,
NULL, NULL, NULL );
goto return_results;
}
if ( ! access_allowed( be, conn, op, e, "entry", NULL, op->o_dn,
ACL_WRITE ) ) {
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, "", "" );
cache_return_entry( &li->li_cache, e );
return( -1 );
#ifdef SLAPD_CHILD_MODIFICATION_WITH_ENTRY_ACL
if ( ! access_allowed( be, conn, op, e,
"entry", NULL, ACL_WRITE ) )
{
Debug(LDAP_DEBUG_ARGS,
"<=- ldbm_back_delete: insufficient access %s\n",
dn, 0, 0);
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
NULL, NULL, NULL );
goto return_results;
}
#endif
/* delete from parent's id2children entry */
if( (pdn = dn_parent( be, e->e_ndn )) != NULL ) {
if( (p = dn2entry_w( be, pdn, &matched )) == NULL) {
Debug( LDAP_DEBUG_TRACE,
"<=- ldbm_back_delete: parent does not exist\n",
0, 0, 0);
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
NULL, NULL, NULL );
goto return_results;
}
/* check parent for "children" acl */
if ( ! access_allowed( be, conn, op, p,
"children", NULL, ACL_WRITE ) )
{
Debug( LDAP_DEBUG_TRACE,
"<=- ldbm_back_delete: no access to parent\n", 0,
0, 0 );
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
NULL, NULL, NULL );
goto return_results;
}
} else {
/* no parent, must be root to delete */
if( ! be_isroot( be, op->o_ndn ) ) {
Debug( LDAP_DEBUG_TRACE,
"<=- ldbm_back_delete: no parent & not root\n",
0, 0, 0);
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
NULL, NULL, NULL );
goto return_results;
}
ldap_pvt_thread_mutex_lock(&li->li_root_mutex);
rootlock = 1;
}
/* XXX delete from parent's id2children entry XXX */
if ( id2children_remove( be, p, e ) != 0 ) {
Debug(LDAP_DEBUG_ARGS,
"<=- ldbm_back_delete: operations error %s\n",
dn, 0, 0);
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
NULL, NULL, NULL );
goto return_results;
}
/* delete from dn2id mapping */
if ( dn2id_delete( be, e->e_dn ) != 0 ) {
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
cache_return_entry( &li->li_cache, e );
return( -1 );
if ( dn2id_delete( be, e->e_ndn ) != 0 ) {
Debug(LDAP_DEBUG_ARGS,
"<=- ldbm_back_delete: operations error %s\n",
dn, 0, 0);
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
NULL, NULL, NULL );
goto return_results;
}
/* delete from disk and cache */
if ( id2entry_delete( be, e ) != 0 ) {
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
cache_return_entry( &li->li_cache, e );
return( -1 );
Debug(LDAP_DEBUG_ARGS,
"<=- ldbm_back_delete: operations error %s\n",
dn, 0, 0);
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
NULL, NULL, NULL );
goto return_results;
}
cache_return_entry( &li->li_cache, e );
send_ldap_result( conn, op, LDAP_SUCCESS, "", "" );
send_ldap_result( conn, op, LDAP_SUCCESS,
NULL, NULL, NULL );
rc = 0;
return( 0 );
return_results:;
if ( pdn != NULL ) free(pdn);
if( p != NULL ) {
/* free parent and writer lock */
cache_return_entry_w( &li->li_cache, p );
}
if ( rootlock ) {
/* release root lock */
ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
}
/* free entry and writer lock */
cache_return_entry_w( &li->li_cache, e );
if ( matched != NULL ) free(matched);
return rc;
}

View file

@ -1,19 +1,218 @@
/* modify.c - ldbm backend modify routine */
#include "portable.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <ac/string.h>
#include <ac/socket.h>
#include <ac/time.h>
#include "slap.h"
#include "back-ldbm.h"
#include "proto-back-ldbm.h"
extern int global_schemacheck;
extern Entry *dn2entry();
extern Attribute *attr_find();
static void add_lastmods(Operation *op, LDAPModList **ml);
static void
add_lastmods( Operation *op, LDAPModList **modlist )
{
char buf[22];
struct berval bv;
struct berval *bvals[2];
LDAPModList **m;
LDAPModList *tmp;
struct tm *ltm;
time_t currenttime;
Debug( LDAP_DEBUG_TRACE, "add_lastmods\n", 0, 0, 0 );
bvals[0] = &bv;
bvals[1] = NULL;
/* remove any attempts by the user to modify these attrs */
for ( m = modlist; *m != NULL; m = &(*m)->ml_next ) {
if ( oc_check_no_usermod_attr( (*m)->ml_type ) ) {
Debug( LDAP_DEBUG_TRACE,
"add_lastmods: found no user mod attr: %s\n",
(*m)->ml_type, 0, 0 );
tmp = *m;
*m = (*m)->ml_next;
free( tmp->ml_type );
if ( tmp->ml_bvalues != NULL ) {
ber_bvecfree( tmp->ml_bvalues );
}
free( tmp );
if (!*m)
break;
}
}
if ( op->o_dn == NULL || op->o_dn[0] == '\0' ) {
bv.bv_val = "NULLDN";
bv.bv_len = strlen( bv.bv_val );
} else {
bv.bv_val = op->o_dn;
bv.bv_len = strlen( bv.bv_val );
}
tmp = (LDAPModList *) ch_calloc( 1, sizeof(LDAPModList) );
tmp->ml_type = ch_strdup( "modifiersname" );
tmp->ml_op = LDAP_MOD_REPLACE;
tmp->ml_bvalues = (struct berval **) ch_calloc(2, sizeof(struct berval *));
tmp->ml_bvalues[0] = ber_bvdup( &bv );
tmp->ml_next = *modlist;
*modlist = tmp;
currenttime = slap_get_time();
ldap_pvt_thread_mutex_lock( &gmtime_mutex );
#ifndef LDAP_LOCALTIME
ltm = gmtime( &currenttime );
strftime( buf, sizeof(buf), "%Y%m%d%H%M%SZ", ltm );
#else
ltm = localtime( &currenttime );
strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm );
#endif
ldap_pvt_thread_mutex_unlock( &gmtime_mutex );
bv.bv_val = buf;
bv.bv_len = strlen( bv.bv_val );
tmp = (LDAPModList *) ch_calloc( 1, sizeof(LDAPModList) );
tmp->ml_type = ch_strdup( "modifytimestamp" );
tmp->ml_op = LDAP_MOD_REPLACE;
tmp->ml_bvalues = (struct berval **) ch_calloc(2, sizeof(struct berval *));
tmp->ml_bvalues[0] = ber_bvdup( &bv );
tmp->ml_next = *modlist;
*modlist = tmp;
}
/* We need this function because of LDAP modrdn. If we do not
* add this there would be a bunch of code replication here
* and there and of course the likelihood of bugs increases.
* Juan C. Gomez (gomez@engr.sgi.com) 05/18/99
*/
int ldbm_modify_internal(
Backend *be,
Connection *conn,
Operation *op,
char *dn,
LDAPModList *modlist,
Entry *e
)
{
int err;
LDAPMod *mod;
LDAPModList *ml;
Attribute *a;
if ( ((be->be_lastmod == ON)
|| ((be->be_lastmod == UNDEFINED)&&(global_lastmod == ON)))
&& (be->be_update_ndn == NULL)) {
/* XXX: It may be wrong, it changes mod time even if
* mod fails!
*/
add_lastmods( op, &modlist );
}
if ( (err = acl_check_modlist( be, conn, op, e, modlist ))
!= LDAP_SUCCESS ) {
send_ldap_result( conn, op, err, NULL, NULL, NULL );
return -1;
}
for ( ml = modlist; ml != NULL; ml = ml->ml_next ) {
mod = &ml->ml_mod;
switch ( mod->mod_op & ~LDAP_MOD_BVALUES ) {
case LDAP_MOD_ADD:
err = add_values( e, mod, op->o_ndn );
break;
case LDAP_MOD_DELETE:
err = delete_values( e, mod, op->o_ndn );
break;
case LDAP_MOD_REPLACE:
/* Need to remove all values from indexes before they
* are lost.
*/
if( e->e_attrs
&& ((a = attr_find( e->e_attrs, mod->mod_type ))
!= NULL) ) {
(void) index_change_values( be,
mod->mod_type,
a->a_vals,
e->e_id,
__INDEX_DELETE_OP);
}
err = replace_values( e, mod, op->o_ndn );
break;
case LDAP_MOD_SOFTADD:
/* Avoid problems in index_add_mods()
* We need to add index if necessary.
*/
mod->mod_op = LDAP_MOD_ADD;
if ( (err = add_values( e, mod, op->o_ndn ))
== LDAP_TYPE_OR_VALUE_EXISTS ) {
err = LDAP_SUCCESS;
mod->mod_op = LDAP_MOD_SOFTADD;
}
break;
}
if ( err != LDAP_SUCCESS ) {
/* unlock entry, delete from cache */
send_ldap_result( conn, op, err, NULL, NULL, NULL );
return -1;
}
}
/* check that the entry still obeys the schema */
if ( global_schemacheck && oc_schema_check( e ) != 0 ) {
Debug( LDAP_DEBUG_ANY, "entry failed schema check\n", 0, 0, 0 );
send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION,
NULL, NULL, NULL );
return -1;
}
/* check for abandon */
ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
if ( op->o_abandon ) {
ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
return -1;
}
ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
/* modify indexes */
if ( index_add_mods( be, modlist, e->e_id ) != 0 ) {
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
NULL, NULL, NULL );
return -1;
}
/* check for abandon */
ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
if ( op->o_abandon ) {
ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
return -1;
}
ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
return 0;
}/* int ldbm_modify_internal() */
static int add_values();
static int delete_values();
static int replace_values();
int
ldbm_back_modify(
@ -21,101 +220,48 @@ ldbm_back_modify(
Connection *conn,
Operation *op,
char *dn,
LDAPMod *mods
LDAPModList *modlist
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
char *matched = NULL;
char *matched;
Entry *e;
int i, err, modtype;
LDAPMod *mod;
if ( (e = dn2entry( be, dn, &matched )) == NULL ) {
send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched,
NULL );
Debug(LDAP_DEBUG_ARGS, "ldbm_back_modify:\n", 0, 0, 0);
/* acquire and lock entry */
if ( (e = dn2entry_w( be, dn, &matched )) == NULL ) {
send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT,
matched, NULL, NULL );
if ( matched != NULL ) {
free( matched );
}
return( -1 );
}
/* lock entry */
if ( (err = acl_check_mods( be, conn, op, e, mods )) != LDAP_SUCCESS ) {
send_ldap_result( conn, op, err, NULL, NULL );
cache_return_entry( &li->li_cache, e );
return( -1 );
/* Modify the entry */
if ( ldbm_modify_internal( be, conn, op, dn, modlist, e ) != 0 ) {
goto error_return;
}
for ( mod = mods; mod != NULL; mod = mod->mod_next ) {
switch ( mod->mod_op & ~LDAP_MOD_BVALUES ) {
case LDAP_MOD_ADD:
err = add_values( e, mod, op->o_dn );
break;
case LDAP_MOD_DELETE:
err = delete_values( e, mod, op->o_dn );
break;
case LDAP_MOD_REPLACE:
err = replace_values( e, mod, op->o_dn );
break;
}
if ( err != LDAP_SUCCESS ) {
/* unlock entry, delete from cache */
send_ldap_result( conn, op, err, NULL, NULL );
cache_return_entry( &li->li_cache, e );
return( -1 );
}
}
/* check for abandon */
pthread_mutex_lock( &op->o_abandonmutex );
if ( op->o_abandon ) {
pthread_mutex_unlock( &op->o_abandonmutex );
cache_return_entry( &li->li_cache, e );
return( -1 );
}
pthread_mutex_unlock( &op->o_abandonmutex );
/* check that the entry still obeys the schema */
if ( global_schemacheck && oc_schema_check( e ) != 0 ) {
send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION, NULL,
NULL );
cache_return_entry( &li->li_cache, e );
return( -1 );
}
/* modify indexes */
if ( index_add_mods( be, mods, e->e_id ) != 0 ) {
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
cache_return_entry( &li->li_cache, e );
return( -1 );
}
/* check for abandon */
pthread_mutex_lock( &op->o_abandonmutex );
if ( op->o_abandon ) {
pthread_mutex_unlock( &op->o_abandonmutex );
cache_return_entry( &li->li_cache, e );
return( -1 );
}
pthread_mutex_unlock( &op->o_abandonmutex );
/* change the entry itself */
if ( id2entry_add( be, e ) != 0 ) {
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
cache_return_entry( &li->li_cache, e );
return( -1 );
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
NULL, NULL, NULL );
goto error_return;
}
send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
cache_return_entry( &li->li_cache, e );
send_ldap_result( conn, op, LDAP_SUCCESS,
NULL, NULL, NULL );
cache_return_entry_w( &li->li_cache, e );
return( 0 );
error_return:;
cache_return_entry_w( &li->li_cache, e );
return( -1 );
}
static int
int
add_values(
Entry *e,
LDAPMod *mod,
@ -143,7 +289,7 @@ add_values(
return( LDAP_SUCCESS );
}
static int
int
delete_values(
Entry *e,
LDAPMod *mod,
@ -199,13 +345,18 @@ delete_values(
return( LDAP_SUCCESS );
}
static int
int
replace_values(
Entry *e,
LDAPMod *mod,
char *dn
)
{
/* XXX: BEFORE YOU GET RID OF PREVIOUS VALUES REMOVE FROM INDEX
* FILES
*/
(void) attr_delete( &e->e_attrs, mod->mod_type );
if ( attr_merge( e, mod->mod_type, mod->mod_bvalues ) != 0 ) {

View file

@ -1,14 +1,31 @@
/* modrdn.c - ldbm backend modrdn routine */
/*
* LDAP v3 newSuperior support. Add new rdn as an attribute.
* (Full support for v2 also used software/ideas contributed
* by Roy Hooper rhooper@cyberus.ca, thanks to him for his
* submission!.)
*
* Copyright 1999, Juan C. Gomez, All rights reserved.
* This software is not subject to any license of Silicon Graphics
* Inc. or Purdue University.
*
* Redistribution and use in source and binary forms are permitted
* without restriction or fee of any kind as long as this notice
* is preserved.
*
*/
#include "portable.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "slap.h"
#include "back-ldbm.h"
extern Entry *dn2entry();
extern char *dn_parent();
#include "proto-back-ldbm.h"
int
ldbm_back_modrdn(
@ -17,116 +34,422 @@ ldbm_back_modrdn(
Operation *op,
char *dn,
char *newrdn,
int deleteoldrdn
int deleteoldrdn,
char *newSuperior
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
char *matched;
char *pdn, *newdn, *p;
char sep[2];
Entry *e, *e2;
char *matched = NULL;
char *p_dn = NULL, *p_ndn = NULL;
char *new_dn = NULL, *new_ndn = NULL;
Entry *e, *p = NULL;
int rootlock = 0;
int rc = -1;
/* Added to support LDAP v2 correctly (deleteoldrdn thing) */
char *new_rdn_val = NULL; /* Val of new rdn */
char *new_rdn_type = NULL; /* Type of new rdn */
char *old_rdn; /* Old rdn's attr type & val */
char *old_rdn_type = NULL; /* Type of old rdn attr. */
char *old_rdn_val = NULL; /* Old rdn attribute value */
/* Added to support newSuperior */
Entry *np = NULL; /* newSuperior Entry */
char *np_dn = NULL; /* newSuperior dn */
char *np_ndn = NULL; /* newSuperior ndn */
char *new_parent_dn = NULL; /* np_dn, p_dn, or NULL */
/* Used to interface with ldbm_modify_internal() */
struct berval add_bv; /* Stores new rdn att */
struct berval *add_bvals[2]; /* Stores new rdn att */
struct berval del_bv; /* Stores old rdn att */
struct berval *del_bvals[2]; /* Stores old rdn att */
LDAPModList mod[2]; /* Used to delete old rdn */
matched = NULL;
if ( (e = dn2entry( be, dn, &matched )) == NULL ) {
send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, "" );
Debug( LDAP_DEBUG_TRACE, "==>ldbm_back_modrdn(newSuperior=%s)\n",
(newSuperior ? newSuperior : "NULL"),
0, 0 );
/* get entry with writer lock */
if ( (e = dn2entry_w( be, dn, &matched )) == NULL ) {
send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT,
matched, NULL, NULL );
if ( matched != NULL ) {
free( matched );
}
return( -1 );
}
if ( (pdn = dn_parent( be, dn )) != NULL ) {
/* parent + rdn + separator(s) + null */
newdn = (char *) ch_malloc( strlen( pdn ) + strlen( newrdn )
+ 3 );
if ( dn_type( dn ) == DN_X500 ) {
strcpy( newdn, newrdn );
strcat( newdn, ", " );
strcat( newdn, pdn );
} else {
strcpy( newdn, newrdn );
p = strchr( newrdn, '\0' );
p--;
if ( *p != '.' && *p != '@' ) {
if ( (p = strpbrk( dn, ".@" )) != NULL ) {
sep[0] = *p;
sep[1] = '\0';
strcat( newdn, sep );
}
}
strcat( newdn, pdn );
}
} else {
newdn = strdup( newrdn );
#ifdef SLAPD_CHILD_MODIFICATION_WITH_ENTRY_ACL
/* check parent for "children" acl */
if ( ! access_allowed( be, conn, op, e,
"entry", NULL, ACL_WRITE ) )
{
Debug( LDAP_DEBUG_TRACE, "no access to entry\n", 0,
0, 0 );
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
"", "" );
goto return_results;
}
(void) dn_normalize( newdn );
#endif
if ( (p_ndn = dn_parent( be, e->e_ndn )) != NULL ) {
/* Make sure parent entry exist and we can write its
* children.
*/
if( (p = dn2entry_w( be, p_ndn, &matched )) == NULL) {
Debug( LDAP_DEBUG_TRACE, "parent does not exist\n",
0, 0, 0);
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
NULL, NULL, NULL );
goto return_results;
}
/* check parent for "children" acl */
if ( ! access_allowed( be, conn, op, p,
"children", NULL, ACL_WRITE ) )
{
Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
0, 0 );
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
NULL, NULL, NULL );
goto return_results;
}
Debug( LDAP_DEBUG_TRACE,
"ldbm_back_modrdn: wr to children of entry %s OK\n",
p_ndn, 0, 0 );
p_dn = dn_parent( be, e->e_dn );
Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: parent dn=%s\n",
p_dn, 0, 0 );
} else {
/* no parent, modrdn entry directly under root */
if( ! be_isroot( be, op->o_ndn ) ) {
Debug( LDAP_DEBUG_TRACE, "no parent & not root\n",
0, 0, 0);
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
NULL, NULL, NULL );
goto return_results;
}
ldap_pvt_thread_mutex_lock(&li->li_root_mutex);
rootlock = 1;
Debug( LDAP_DEBUG_TRACE,
"ldbm_back_modrdn: no parent, locked root\n",
0, 0, 0 );
}/* if ( (p_ndn = dn_parent( be, e->e_ndn )) != NULL ) else */
new_parent_dn = p_dn; /* New Parent unless newSuperior given */
if ( (np_dn = newSuperior) != NULL) {
Debug( LDAP_DEBUG_TRACE,
"ldbm_back_modrdn: new parent requested...\n",
0, 0, 0 );
np_ndn = dn_normalize_case( ch_strdup( np_dn ) );
/* newSuperior == oldParent?, if so ==> ERROR */
/* newSuperior == entry being moved?, if so ==> ERROR */
/* Get Entry with dn=newSuperior. Does newSuperior exist? */
if( (np = dn2entry_w( be, np_ndn, &matched )) == NULL) {
Debug( LDAP_DEBUG_TRACE,
"ldbm_back_modrdn: newSup(ndn=%s) not here!\n",
np_ndn, 0, 0);
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
NULL, NULL, NULL );
goto return_results;
}
Debug( LDAP_DEBUG_TRACE,
"ldbm_back_modrdn: wr to new parent OK np=%p, id=%d\n",
np, np->e_id, 0 );
/* check newSuperior for "children" acl */
if ( !access_allowed( be, conn, op, np, "children", NULL,
ACL_WRITE ) )
{
Debug( LDAP_DEBUG_TRACE,
"ldbm_back_modrdn: no wr to newSup children\n",
0, 0, 0 );
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
NULL, NULL, NULL );
goto return_results;
}
Debug( LDAP_DEBUG_TRACE,
"ldbm_back_modrdn: wr to new parent's children OK\n",
0, 0 , 0 );
new_parent_dn = np_dn;
matched = NULL;
if ( (e2 = dn2entry( be, newdn, &matched )) != NULL ) {
free( newdn );
free( pdn );
send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, NULL, NULL );
cache_return_entry( &li->li_cache, e2 );
cache_return_entry( &li->li_cache, e );
return( -1 );
}
if ( matched != NULL ) {
free( matched );
/* Build target dn and make sure target entry doesn't exist already. */
build_new_dn( &new_dn, e->e_dn, new_parent_dn, newrdn );
new_ndn = dn_normalize_case( ch_strdup(new_dn) );
Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: new ndn=%s\n",
new_ndn, 0, 0 );
if (dn2id ( be, new_ndn ) != NOID) {
send_ldap_result( conn, op, LDAP_ALREADY_EXISTS,
NULL, NULL, NULL );
goto return_results;
}
Debug( LDAP_DEBUG_TRACE,
"ldbm_back_modrdn: new ndn=%s does not exist\n",
new_ndn, 0, 0 );
/* check for abandon */
pthread_mutex_lock( &op->o_abandonmutex );
ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
if ( op->o_abandon ) {
pthread_mutex_unlock( &op->o_abandonmutex );
free( newdn );
free( pdn );
cache_return_entry( &li->li_cache, e2 );
cache_return_entry( &li->li_cache, e );
return( -1 );
}
pthread_mutex_unlock( &op->o_abandonmutex );
/* add new one */
if ( dn2id_add( be, newdn, e->e_id ) != 0 ) {
free( newdn );
free( pdn );
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
cache_return_entry( &li->li_cache, e );
return( -1 );
ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
goto return_results;
}
ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
/* delete old one */
if ( dn2id_delete( be, dn ) != 0 ) {
free( newdn );
free( pdn );
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
cache_return_entry( &li->li_cache, e );
return( -1 );
if ( dn2id_delete( be, e->e_ndn ) != 0 ) {
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
NULL, NULL, NULL );
goto return_results;
}
(void) cache_delete_entry( &li->li_cache, e );
free( e->e_dn );
e->e_dn = newdn;
free( e->e_ndn );
e->e_dn = new_dn;
e->e_ndn = new_ndn;
/* XXX
* At some point here we need to update the attribute values in
* the entry itself that were effected by this RDN change
* (respecting the value of the deleteoldrdn parameter).
*
* Since the code to do this has not yet been written, treat this
* omission as a (documented) bug.
/* add new one */
if ( dn2id_add( be, e->e_ndn, e->e_id ) != 0 ) {
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
NULL, NULL, NULL );
goto return_results;
}
/* Get attribute type and attribute value of our new rdn, we will
* need to add that to our new entry
*/
if ( (new_rdn_type = rdn_attr_type( newrdn )) == NULL ) {
Debug( LDAP_DEBUG_TRACE,
"ldbm_back_modrdn: can't figure out type of newrdn\n",
0, 0, 0 );
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
NULL, NULL, NULL );
goto return_results;
}
if ( (new_rdn_val = rdn_attr_value( newrdn )) == NULL ) {
Debug( LDAP_DEBUG_TRACE,
"ldbm_back_modrdn: can't figure out val of newrdn\n",
0, 0, 0 );
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
NULL, NULL, NULL );
goto return_results;
}
Debug( LDAP_DEBUG_TRACE,
"ldbm_back_modrdn: new_rdn_val=\"%s\", new_rdn_type=\"%s\"\n",
new_rdn_val, new_rdn_type, 0 );
/* Retrieve the old rdn from the entry's dn */
if ( (old_rdn = dn_rdn( be, dn )) == NULL ) {
Debug( LDAP_DEBUG_TRACE,
"ldbm_back_modrdn: can't figure out old_rdn from dn\n",
0, 0, 0 );
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
NULL, NULL, NULL );
goto return_results;
}
if ( (old_rdn_type = rdn_attr_type( old_rdn )) == NULL ) {
Debug( LDAP_DEBUG_TRACE,
"ldbm_back_modrdn: can't figure out the old_rdn type\n",
0, 0, 0 );
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
NULL, NULL, NULL );
goto return_results;
}
if ( strcasecmp( old_rdn_type, new_rdn_type ) != 0 ) {
/* Not a big deal but we may say something */
Debug( LDAP_DEBUG_TRACE,
"ldbm_back_modrdn: old_rdn_type=%s, new_rdn_type=%s!\n",
old_rdn_type, new_rdn_type, 0 );
}
if ( dn_type( old_rdn ) == DN_X500 ) {
Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: DN_X500\n",
0, 0, 0 );
/* Add new attribute value to the entry.
*/
add_bvals[0] = &add_bv; /* Array of bervals */
add_bvals[1] = NULL;
add_bv.bv_val = new_rdn_val;
add_bv.bv_len = strlen(new_rdn_val);
mod[0].ml_type = new_rdn_type;
mod[0].ml_bvalues = add_bvals;
mod[0].ml_op = LDAP_MOD_SOFTADD;
mod[0].ml_next = NULL;
/* Remove old rdn value if required */
if (deleteoldrdn) {
/* Get value of old rdn */
if ((old_rdn_val = rdn_attr_value( old_rdn ))
== NULL) {
Debug( LDAP_DEBUG_TRACE,
"ldbm_back_modrdn: can't figure out old_rdn_val from old_rdn\n",
0, 0, 0 );
send_ldap_result( conn, op,
LDAP_OPERATIONS_ERROR,
NULL, NULL, NULL );
goto return_results;
}
del_bvals[0] = &del_bv; /* Array of bervals */
del_bvals[1] = NULL;
/* Remove old value of rdn as an attribute. */
del_bv.bv_val = old_rdn_val;
del_bv.bv_len = strlen(old_rdn_val);
/* No need to normalize old_rdn_type, delete_values()
* does that for us
*/
mod[0].ml_next = &mod[1];
mod[1].ml_type = old_rdn_type;
mod[1].ml_bvalues = del_bvals;
mod[1].ml_op = LDAP_MOD_DELETE;
mod[1].ml_next = NULL;
Debug( LDAP_DEBUG_TRACE,
"ldbm_back_modrdn: removing old_rdn_val=%s\n",
old_rdn_val, 0, 0 );
}/* if (deleteoldrdn) */
} else {
Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: DNS DN\n",
0, 0, 0 );
/* XXXV3: not sure of what to do here */
Debug( LDAP_DEBUG_TRACE,
"ldbm_back_modrdn: not fully implemented...\n",
0, 0, 0 );
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
NULL, NULL, NULL );
goto return_results;
}
/* modify memory copy of entry */
if ( ldbm_modify_internal( be, conn, op, dn, &mod[0], e )
!= 0 ) {
goto return_results;
}
(void) cache_update_entry( &li->li_cache, e );
/* NOTE: after this you must not free new_dn or new_ndn!
* They are used by cache.
*/
/* id2entry index */
if ( id2entry_add( be, e ) != 0 ) {
entry_free( e );
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
return( -1 );
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
NULL, NULL, NULL );
goto return_results_after;
}
free( pdn );
cache_return_entry( &li->li_cache, e );
send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
return( 0 );
send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL );
rc = 0;
goto return_results_after;
return_results:
if( new_dn != NULL ) free( new_dn );
if( new_ndn != NULL ) free( new_ndn );
return_results_after:
/* NOTE:
* new_dn and new_ndn are not deallocated because they are used by
* the cache entry.
*/
if( p_dn != NULL ) free( p_dn );
if( p_ndn != NULL ) free( p_ndn );
if( matched != NULL ) free( matched );
/* LDAP v2 supporting correct attribute handling. */
if( new_rdn_type != NULL ) free(new_rdn_type);
if( new_rdn_val != NULL ) free(new_rdn_val);
if( old_rdn != NULL ) free(old_rdn);
if( old_rdn_type != NULL ) free(old_rdn_type);
if( old_rdn_val != NULL ) free(old_rdn_val);
/* LDAP v3 Support */
if ( np_dn != NULL ) free( np_dn );
if ( np_ndn != NULL ) free( np_ndn );
if( p != NULL ) {
/* free parent and writer lock */
cache_return_entry_w( &li->li_cache, p );
}
if ( rootlock ) {
/* release root writer lock */
ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
}
/* free entry and writer lock */
cache_return_entry_w( &li->li_cache, e );
return( rc );
}

View file

@ -1,38 +1,19 @@
/* search.c - ldbm backend search function */
#include "portable.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "slap.h"
#include "back-ldbm.h"
#include "proto-back-ldbm.h"
extern time_t currenttime;
extern pthread_mutex_t currenttime_mutex;
extern ID dn2id();
extern IDList *idl_alloc();
extern Entry *id2entry();
extern Entry *dn2entry();
extern Attribute *attr_find();
extern IDList *filter_candidates();
extern char *ch_realloc();
extern char *dn_parent();
static IDList *base_candidates();
static IDList *onelevel_candidates();
static IDList *subtree_candidates();
#define GRABSIZE BUFSIZ
#define MAKE_SPACE( n ) { \
if ( rcur + n > rbuf + rmaxsize ) { \
int offset = rcur - rbuf; \
rbuf = ch_realloc( rbuf, rmaxsize + GRABSIZE ); \
rmaxsize += GRABSIZE; \
rcur = rbuf + offset; \
} \
}
static ID_BLOCK *base_candidates(Backend *be, Connection *conn, Operation *op, char *base, Filter *filter, char **attrs, int attrsonly, char **matched, int *err);
static ID_BLOCK *onelevel_candidates(Backend *be, Connection *conn, Operation *op, char *base, Filter *filter, char **attrs, int attrsonly, char **matched, int *err);
static ID_BLOCK *subtree_candidates(Backend *be, Connection *conn, Operation *op, char *base, Filter *filter, char **attrs, int attrsonly, char **matched, Entry *e, int *err, int lookupbase);
int
ldbm_back_search(
@ -53,125 +34,141 @@ ldbm_back_search(
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
int err;
time_t stoptime;
IDList *candidates;
ID_BLOCK *candidates;
ID id;
Entry *e;
Attribute *ref;
struct berval **refs;
char *matched = NULL;
int rmaxsize, nrefs;
char *rbuf, *rcur, *r;
int nentries = 0;
char *realBase;
if ( tlimit == 0 && be_isroot( be, op->o_dn ) ) {
Debug(LDAP_DEBUG_ARGS, "=> ldbm_back_search\n", 0, 0, 0);
if ( tlimit == 0 && be_isroot( be, op->o_ndn ) ) {
tlimit = -1; /* allow root to set no limit */
} else {
tlimit = (tlimit > be->be_timelimit || tlimit < 1) ?
be->be_timelimit : tlimit;
stoptime = op->o_time + tlimit;
}
if ( slimit == 0 && be_isroot( be, op->o_dn ) ) {
if ( slimit == 0 && be_isroot( be, op->o_ndn ) ) {
slimit = -1; /* allow root to set no limit */
} else {
slimit = (slimit > be->be_sizelimit || slimit < 1) ?
be->be_sizelimit : slimit;
}
/*
* check and apply aliasing where the dereferencing applies to
* the subordinates of the base
*/
switch ( deref ) {
case LDAP_DEREF_FINDING:
case LDAP_DEREF_ALWAYS:
realBase = derefDN ( be, conn, op, base );
break;
default:
realBase = ch_strdup(base);
}
(void) dn_normalize_case( realBase );
Debug( LDAP_DEBUG_TRACE, "using base \"%s\"\n",
realBase, 0, 0 );
switch ( scope ) {
case LDAP_SCOPE_BASE:
candidates = base_candidates( be, conn, op, base, filter,
candidates = base_candidates( be, conn, op, realBase, filter,
attrs, attrsonly, &matched, &err );
break;
case LDAP_SCOPE_ONELEVEL:
candidates = onelevel_candidates( be, conn, op, base, filter,
candidates = onelevel_candidates( be, conn, op, realBase, filter,
attrs, attrsonly, &matched, &err );
break;
case LDAP_SCOPE_SUBTREE:
candidates = subtree_candidates( be, conn, op, base, filter,
candidates = subtree_candidates( be, conn, op, realBase, filter,
attrs, attrsonly, &matched, NULL, &err, 1 );
break;
default:
send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, "",
"Bad scope" );
send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR,
"", "Bad search scope", NULL );
if( realBase != NULL) {
free( realBase );
}
return( -1 );
}
/* null candidates means we could not find the base object */
if ( candidates == NULL ) {
send_ldap_result( conn, op, err, matched, "" );
send_ldap_result( conn, op, err,
matched, NULL, NULL );
if ( matched != NULL ) {
free( matched );
}
if( realBase != NULL) {
free( realBase );
}
return( -1 );
}
rmaxsize = 0;
nrefs = 0;
rbuf = rcur = NULL;
MAKE_SPACE( sizeof("Referral:") + 1 );
strcpy( rbuf, "Referral:" );
rcur = strchr( rbuf, '\0' );
if ( matched != NULL ) {
free( matched );
}
refs = NULL;
for ( id = idl_firstid( candidates ); id != NOID;
id = idl_nextid( candidates, id ) ) {
/* check for abandon */
pthread_mutex_lock( &op->o_abandonmutex );
ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
if ( op->o_abandon ) {
pthread_mutex_unlock( &op->o_abandonmutex );
ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
idl_free( candidates );
free( rbuf );
ber_bvecfree( refs );
if( realBase != NULL) {
free( realBase );
}
return( 0 );
}
pthread_mutex_unlock( &op->o_abandonmutex );
ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
/* check time limit */
pthread_mutex_lock( &currenttime_mutex );
time( &currenttime );
if ( tlimit != -1 && currenttime > stoptime ) {
pthread_mutex_unlock( &currenttime_mutex );
send_ldap_search_result( conn, op,
LDAP_TIMELIMIT_EXCEEDED, NULL, nrefs > 0 ? rbuf :
NULL, nentries );
if ( tlimit != -1 && slap_get_time() > stoptime ) {
send_search_result( conn, op, LDAP_TIMELIMIT_EXCEEDED,
NULL, NULL, refs, nentries );
idl_free( candidates );
free( rbuf );
ber_bvecfree( refs );
if( realBase != NULL) {
free( realBase );
}
return( 0 );
}
pthread_mutex_unlock( &currenttime_mutex );
/* get the entry */
if ( (e = id2entry( be, id )) == NULL ) {
Debug( LDAP_DEBUG_ARGS, "candidate %d not found\n", id,
0, 0 );
/* get the entry with reader lock */
if ( (e = id2entry_r( be, id )) == NULL ) {
Debug( LDAP_DEBUG_ARGS, "candidate %ld not found\n",
id, 0, 0 );
continue;
}
/*
* if it's a referral, add it to the list of referrals. only do
* this for subtree searches, and don't check the filter explicitly
* here since it's only a candidate anyway.
* this for subtree searches, and don't check the filter
* explicitly here since it's only a candidate anyway.
*/
if ( e->e_dn != NULL && strncasecmp( e->e_dn, "ref=", 4 )
== 0 && (ref = attr_find( e->e_attrs, "ref" )) != NULL &&
scope == LDAP_SCOPE_SUBTREE )
if ( scope == LDAP_SCOPE_SUBTREE &&
e->e_ndn != NULL &&
strncmp( e->e_ndn, "REF=", 4 ) == 0 &&
(ref = attr_find( e->e_attrs, "ref" )) != NULL )
{
int i, len;
if ( ref->a_vals == NULL ) {
Debug( LDAP_DEBUG_ANY, "null ref in (%s)\n", 0,
0, 0 );
} else {
for ( i = 0; ref->a_vals[i] != NULL; i++ ) {
/* referral + newline + null */
MAKE_SPACE( ref->a_vals[i]->bv_len + 2 );
*rcur++ = '\n';
strncpy( rcur, ref->a_vals[i]->bv_val,
ref->a_vals[i]->bv_len );
rcur = rcur + ref->a_vals[i]->bv_len;
*rcur = '\0';
nrefs++;
}
}
send_search_reference( be, conn, op,
e, ref->a_vals, &refs );
/* otherwise it's an entry - see if it matches the filter */
} else {
@ -184,66 +181,102 @@ ldbm_back_search(
scopeok = 1;
if ( scope == LDAP_SCOPE_ONELEVEL ) {
if ( (dn = dn_parent( be, e->e_dn )) != NULL ) {
(void) dn_normalize( dn );
scopeok = (dn == base) ? 1 : (! strcasecmp( dn, base ));
(void) dn_normalize_case( dn );
scopeok = (dn == realBase)
? 1
: (strcmp( dn, realBase ) ? 0 : 1 );
free( dn );
} else {
scopeok = (base == NULL || *base == '\0');
scopeok = (realBase == NULL || *realBase == '\0');
}
free( dn );
} else if ( scope == LDAP_SCOPE_SUBTREE ) {
dn = strdup( e->e_dn );
(void) dn_normalize( dn );
scopeok = dn_issuffix( dn, base );
dn = ch_strdup( e->e_ndn );
scopeok = dn_issuffix( dn, realBase );
free( dn );
}
if ( scopeok ) {
/* check size limit */
if ( --slimit == -1 ) {
cache_return_entry( &li->li_cache, e );
send_ldap_search_result( conn, op,
LDAP_SIZELIMIT_EXCEEDED, NULL,
nrefs > 0 ? rbuf : NULL, nentries );
cache_return_entry_r( &li->li_cache, e );
send_search_result( conn, op,
LDAP_SIZELIMIT_EXCEEDED, NULL, NULL,
refs, nentries );
idl_free( candidates );
free( rbuf );
ber_bvecfree( refs );
if( realBase != NULL) {
free( realBase );
}
return( 0 );
}
switch ( send_search_entry( be, conn, op, e,
attrs, attrsonly ) ) {
case 0: /* entry sent ok */
nentries++;
/*
* check and apply aliasing where the dereferencing applies to
* the subordinates of the base
*/
switch ( deref ) {
case LDAP_DEREF_SEARCHING:
case LDAP_DEREF_ALWAYS:
{
Entry *newe = derefAlias_r( be, conn, op, e );
if ( newe == NULL ) { /* problem with the alias */
cache_return_entry_r( &li->li_cache, e );
e = NULL;
}
else if ( newe != e ) { /* reassign e */
cache_return_entry_r( &li->li_cache, e );
e = newe;
}
}
break;
case 1: /* entry not sent */
break;
case -1: /* connection closed */
cache_return_entry( &li->li_cache, e );
idl_free( candidates );
free( rbuf );
return( 0 );
}
if (e) {
switch ( send_search_entry( be, conn, op, e,
attrs, attrsonly, 0 ) ) {
case 0: /* entry sent ok */
nentries++;
break;
case 1: /* entry not sent */
break;
case -1: /* connection closed */
cache_return_entry_r( &li->li_cache, e );
idl_free( candidates );
ber_bvecfree( refs );
if( realBase != NULL) {
free( realBase );
}
return( 0 );
}
}
}
}
}
cache_return_entry( &li->li_cache, e );
if( e != NULL ) {
/* free reader lock */
cache_return_entry_r( &li->li_cache, e );
}
pthread_yield();
ldap_pvt_thread_yield();
}
idl_free( candidates );
if ( nrefs > 0 ) {
send_ldap_search_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
rbuf, nentries );
} else {
send_ldap_search_result( conn, op, LDAP_SUCCESS, NULL, NULL,
nentries );
send_search_result( conn, op,
refs == NULL ? LDAP_SUCCESS : LDAP_REFERRAL,
NULL, NULL, refs, nentries );
ber_bvecfree( refs );
if( realBase != NULL) {
free( realBase );
}
free( rbuf );
return( 0 );
}
static IDList *
static ID_BLOCK *
base_candidates(
Backend *be,
Connection *conn,
@ -257,26 +290,32 @@ base_candidates(
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
int rc;
ID id;
IDList *idl;
ID_BLOCK *idl;
Entry *e;
Debug(LDAP_DEBUG_TRACE, "base_candidates: base: \"%s\"\n", base, 0, 0);
*err = LDAP_SUCCESS;
if ( (e = dn2entry( be, base, matched )) == NULL ) {
/* get entry with reader lock */
if ( (e = dn2entry_r( be, base, matched )) == NULL ) {
*err = LDAP_NO_SUCH_OBJECT;
return( NULL );
}
/* check for deleted */
idl = idl_alloc( 1 );
idl_insert( &idl, e->e_id, 1 );
cache_return_entry( &li->li_cache, e );
/* free reader lock */
cache_return_entry_r( &li->li_cache, e );
return( idl );
}
static IDList *
static ID_BLOCK *
onelevel_candidates(
Backend *be,
Connection *conn,
@ -290,16 +329,19 @@ onelevel_candidates(
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
Entry *e;
Entry *e = NULL;
Filter *f;
char buf[20];
IDList *candidates;
ID_BLOCK *candidates;
Debug(LDAP_DEBUG_TRACE, "onelevel_candidates: base: \"%s\"\n", base, 0, 0);
*err = LDAP_SUCCESS;
e = NULL;
/* get the base object */
if ( base != NULL && *base != '\0' && (e = dn2entry( be, base,
matched )) == NULL ) {
/* get the base object with reader lock */
if ( base != NULL && *base != '\0' &&
(e = dn2entry_r( be, base, matched )) == NULL )
{
*err = LDAP_NO_SUCH_OBJECT;
return( NULL );
}
@ -315,9 +357,9 @@ onelevel_candidates(
f->f_choice = LDAP_FILTER_AND;
f->f_and = (Filter *) ch_malloc( sizeof(Filter) );
f->f_and->f_choice = LDAP_FILTER_EQUALITY;
f->f_and->f_ava.ava_type = strdup( "id2children" );
sprintf( buf, "%d", e != NULL ? e->e_id : 0 );
f->f_and->f_ava.ava_value.bv_val = strdup( buf );
f->f_and->f_ava.ava_type = ch_strdup( "id2children" );
sprintf( buf, "%ld", e != NULL ? e->e_id : 0 );
f->f_and->f_ava.ava_value.bv_val = ch_strdup( buf );
f->f_and->f_ava.ava_value.bv_len = strlen( buf );
f->f_and->f_next = filter;
@ -329,10 +371,14 @@ onelevel_candidates(
f->f_and->f_next = NULL;
filter_free( f );
/* free entry and reader lock */
if( e != NULL ) {
cache_return_entry_r( &li->li_cache, e );
}
return( candidates );
}
static IDList *
static ID_BLOCK *
subtree_candidates(
Backend *be,
Connection *conn,
@ -348,8 +394,11 @@ subtree_candidates(
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
Filter *f;
IDList *candidates;
Filter *f, **filterarg_ptr;
ID_BLOCK *candidates;
Debug(LDAP_DEBUG_TRACE, "subtree_candidates: base: \"%s\" %s\n",
base ? base : "NULL", lookupbase ? "lookupbase" : "", 0);
/*
* get the base object - unless we already have it (from one-level).
@ -365,21 +414,30 @@ subtree_candidates(
*err = LDAP_SUCCESS;
f = NULL;
if ( lookupbase ) {
if ( base != NULL && *base != '\0' && (e = dn2entry( be, base,
matched )) == NULL ) {
e = NULL;
if ( base != NULL && *base != '\0' &&
(e = dn2entry_r( be, base, matched )) == NULL )
{
*err = LDAP_NO_SUCH_OBJECT;
return( NULL );
}
if (e) {
cache_return_entry_r( &li->li_cache, e );
}
f = (Filter *) ch_malloc( sizeof(Filter) );
f->f_next = NULL;
f->f_choice = LDAP_FILTER_OR;
f->f_or = (Filter *) ch_malloc( sizeof(Filter) );
f->f_or->f_choice = LDAP_FILTER_EQUALITY;
f->f_or->f_avtype = strdup( "objectclass" );
f->f_or->f_avvalue.bv_val = strdup( "referral" );
f->f_or->f_avvalue.bv_len = strlen( "referral" );
f->f_or->f_next = filter;
f->f_or->f_avtype = ch_strdup( "objectclass" );
/* Patch to use normalized uppercase */
f->f_or->f_avvalue.bv_val = ch_strdup( "REFERRAL" );
f->f_or->f_avvalue.bv_len = strlen( "REFERRAL" );
filterarg_ptr = &f->f_or->f_next;
*filterarg_ptr = filter;
filter = f;
if ( ! be_issuffix( be, base ) ) {
@ -388,10 +446,10 @@ subtree_candidates(
f->f_choice = LDAP_FILTER_AND;
f->f_and = (Filter *) ch_malloc( sizeof(Filter) );
f->f_and->f_choice = LDAP_FILTER_SUBSTRINGS;
f->f_and->f_sub_type = strdup( "dn" );
f->f_and->f_sub_type = ch_strdup( "dn" );
f->f_and->f_sub_initial = NULL;
f->f_and->f_sub_any = NULL;
f->f_and->f_sub_final = strdup( base );
f->f_and->f_sub_final = ch_strdup( base );
value_normalize( f->f_and->f_sub_final, SYNTAX_CIS );
f->f_and->f_next = filter;
filter = f;
@ -402,13 +460,9 @@ subtree_candidates(
/* free up just the parts we allocated above */
if ( f != NULL ) {
f->f_and->f_next = NULL;
*filterarg_ptr = NULL;
filter_free( f );
}
if ( e != NULL ) {
cache_return_entry( &li->li_cache, e );
}
return( candidates );
}

View file

@ -12,30 +12,72 @@
* is provided ``as is'' without express or implied warranty.
*/
#include "portable.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "slap.h"
extern Backend *select_backend();
char *supportedSASLMechanisms[] = {
"X-DIGEST-MD5",
NULL
};
extern char *default_referral;
void
int
do_bind(
Connection *conn,
Operation *op
)
{
BerElement *ber = op->o_ber;
int version, method, len, rc;
char *dn;
ber_int_t version;
ber_tag_t method;
char *mech;
char *cdn, *ndn;
ber_tag_t tag;
int rc = LDAP_SUCCESS;
struct berval cred;
Backend *be;
Debug( LDAP_DEBUG_TRACE, "do_bind\n", 0, 0, 0 );
cdn = NULL;
ndn = NULL;
mech = NULL;
cred.bv_val = NULL;
ldap_pvt_thread_mutex_lock( &conn->c_mutex );
/* Force to connection to "anonymous" until bind succeeds.
* This may need to be relocated or done on a case by case basis
* to handle certain SASL mechanisms.
*/
if ( conn->c_cdn != NULL ) {
free( conn->c_cdn );
conn->c_cdn = NULL;
}
if ( conn->c_dn != NULL ) {
free( conn->c_dn );
conn->c_dn = NULL;
}
ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
if ( op->o_dn != NULL ) {
free( op->o_dn );
op->o_dn = ch_strdup( "" );
}
if ( op->o_ndn != NULL ) {
free( op->o_ndn );
op->o_ndn = ch_strdup( "" );
}
/*
* Parse the bind request. It looks like this:
*
@ -45,90 +87,163 @@ do_bind(
* authentication CHOICE {
* simple [0] OCTET STRING -- passwd
* krbv42ldap [1] OCTET STRING
* krbv42dsa [1] OCTET STRING
* krbv42dsa [2] OCTET STRING
* SASL [3] SaslCredentials
* }
* }
*
* SaslCredentials ::= SEQUENCE {
* mechanism LDAPString,
* credentials OCTET STRING OPTIONAL
* }
*/
#ifdef COMPAT30
/*
* in version 3.0 there is an extra SEQUENCE tag after the
* BindRequest SEQUENCE tag.
*/
tag = ber_scanf( ber, "{iat" /*}*/, &version, &cdn, &method );
{
BerElement tber;
unsigned long tlen, ttag;
if ( tag == LBER_ERROR ) {
Debug( LDAP_DEBUG_ANY, "bind: ber_scanf failed\n", 0, 0, 0 );
send_ldap_disconnect( conn, op,
LDAP_PROTOCOL_ERROR, "decoding error" );
rc = -1;
goto cleanup;
}
op->o_protocol = version;
if( method != LDAP_AUTH_SASL ) {
tag = ber_scanf( ber, /*{*/ "o}", &cred );
tber = *op->o_ber;
ttag = ber_skip_tag( &tber, &tlen );
if ( ber_peek_tag( &tber, &tlen ) == LBER_SEQUENCE ) {
Debug( LDAP_DEBUG_ANY, "version 3.0 detected\n", 0, 0, 0 );
conn->c_version = 30;
rc = ber_scanf(ber, "{{iato}}", &version, &dn, &method, &cred);
} else {
rc = ber_scanf( ber, "{iato}", &version, &dn, &method, &cred );
}
}
#else
rc = ber_scanf( ber, "{iato}", &version, &dn, &method, &cred );
#endif
if ( rc == LBER_ERROR ) {
Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
"decoding error" );
return;
}
#ifdef COMPAT30
if ( conn->c_version == 30 ) {
switch ( method ) {
case LDAP_AUTH_SIMPLE_30:
method = LDAP_AUTH_SIMPLE;
break;
#ifdef KERBEROS
case LDAP_AUTH_KRBV41_30:
method = LDAP_AUTH_KRBV41;
break;
case LDAP_AUTH_KRBV42_30:
method = LDAP_AUTH_KRBV42;
break;
#endif
tag = ber_scanf( ber, "{a" /*}*/, &mech );
if ( tag != LBER_ERROR ) {
ber_len_t len;
tag = ber_peek_tag( ber, &len );
if ( tag == LDAP_TAG_LDAPCRED ) {
tag = ber_scanf( ber, "o", &cred );
}
if ( tag != LBER_ERROR ) {
tag = ber_scanf( ber, /*{{*/ "}}" );
}
}
}
#endif /* compat30 */
dn_normalize( dn );
if ( tag == LBER_ERROR ) {
send_ldap_disconnect( conn, op,
LDAP_PROTOCOL_ERROR,
"decoding error" );
rc = -1;
goto cleanup;
}
if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_ANY, "do_bind: get_ctrls failed\n", 0, 0, 0 );
goto cleanup;
}
if( method == LDAP_AUTH_SASL ) {
Debug( LDAP_DEBUG_TRACE, "do_sasl_bind: dn (%s) mech %s\n",
cdn, mech, NULL );
} else {
Debug( LDAP_DEBUG_TRACE, "do_bind: version %d dn (%s) method %d\n",
version, cdn, method );
}
ndn = dn_normalize_case( ch_strdup( cdn ) );
Statslog( LDAP_DEBUG_STATS, "conn=%d op=%d BIND dn=\"%s\" method=%d\n",
conn->c_connid, op->o_opid, dn, method, 0 );
if ( version != LDAP_VERSION2 ) {
if ( dn != NULL ) {
free( dn );
}
if ( cred.bv_val != NULL ) {
free( cred.bv_val );
}
conn->c_connid, op->o_opid, ndn, method, 0 );
if ( version < LDAP_VERSION_MIN || version > LDAP_VERSION_MAX ) {
Debug( LDAP_DEBUG_ANY, "unknown version %d\n", version, 0, 0 );
send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
"version not supported" );
return;
send_ldap_result( conn, op, rc = LDAP_PROTOCOL_ERROR,
NULL, "version not supported", NULL );
goto cleanup;
}
Debug( LDAP_DEBUG_TRACE, "do_bind: version %d dn (%s) method %d\n",
version, dn, method );
if ( method == LDAP_AUTH_SASL ) {
if ( version < LDAP_VERSION3 ) {
Debug( LDAP_DEBUG_ANY, "do_bind: sasl with LDAPv%d\n",
version, 0, 0 );
send_ldap_disconnect( conn, op,
LDAP_PROTOCOL_ERROR, "sasl bind requires LDAPv3" );
rc = -1;
goto cleanup;
}
if( mech == NULL || *mech == '\0' ) {
Debug( LDAP_DEBUG_ANY,
"do_bind: no sasl mechanism provided\n",
version, 0, 0 );
send_ldap_result( conn, op, rc = LDAP_AUTH_METHOD_NOT_SUPPORTED,
NULL, "no sasl mechanism provided", NULL );
goto cleanup;
}
if( !charray_inlist( supportedSASLMechanisms, mech ) ) {
Debug( LDAP_DEBUG_ANY,
"do_bind: sasl mechanism \"%s\" not supported.\n",
mech, 0, 0 );
send_ldap_result( conn, op, rc = LDAP_AUTH_METHOD_NOT_SUPPORTED,
NULL, "sasl mechanism not supported", NULL );
goto cleanup;
}
ldap_pvt_thread_mutex_lock( &conn->c_mutex );
if ( conn->c_authmech != NULL ) {
assert( conn->c_bind_in_progress );
if((strcmp(conn->c_authmech, mech) != 0)) {
/* mechanism changed, cancel in progress bind */
conn->c_bind_in_progress = 0;
if( conn->c_authstate != NULL ) {
free(conn->c_authstate);
conn->c_authstate = NULL;
}
free(conn->c_authmech);
conn->c_authmech = NULL;
}
#ifdef LDAP_DEBUG
} else {
assert( !conn->c_bind_in_progress );
assert( conn->c_authmech == NULL );
assert( conn->c_authstate == NULL );
#endif
}
} else {
ldap_pvt_thread_mutex_lock( &conn->c_mutex );
if ( conn->c_authmech != NULL ) {
assert( conn->c_bind_in_progress );
/* cancel in progress bind */
conn->c_bind_in_progress = 0;
if( conn->c_authstate != NULL ) {
free(conn->c_authstate);
conn->c_authstate = NULL;
}
free(conn->c_authmech);
conn->c_authmech = NULL;
}
}
conn->c_protocol = version;
ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
/* accept null binds */
if ( dn == NULL || *dn == '\0' ) {
if ( dn != NULL ) {
free( dn );
}
if ( cred.bv_val != NULL ) {
free( cred.bv_val );
}
send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
return;
if ( ndn == NULL || *ndn == '\0' ) {
/*
* we already forced connection to "anonymous", we just
* need to send success
*/
send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL );
goto cleanup;
}
/*
@ -137,39 +252,73 @@ do_bind(
* if we don't hold it.
*/
if ( (be = select_backend( dn )) == NULL ) {
free( dn );
if ( cred.bv_val != NULL ) {
free( cred.bv_val );
}
if ( (be = select_backend( ndn )) == NULL ) {
if ( cred.bv_len == 0 ) {
send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
send_ldap_result( conn, op, LDAP_SUCCESS,
NULL, NULL, NULL );
} else if ( default_referral ) {
send_ldap_result( conn, op, rc = LDAP_REFERRAL,
NULL, NULL, default_referral );
} else {
send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
default_referral );
send_ldap_result( conn, op, rc = LDAP_INVALID_CREDENTIALS,
NULL, NULL, NULL );
}
return;
goto cleanup;
}
if ( be->be_bind != NULL ) {
if ( (*be->be_bind)( be, conn, op, dn, method, &cred ) == 0 ) {
pthread_mutex_lock( &conn->c_dnmutex );
if ( conn->c_dn != NULL ) {
free( conn->c_dn );
if ( be->be_bind ) {
/* alias suffix */
char *edn;
ndn = suffixAlias( ndn, op, be );
if ( (*be->be_bind)( be, conn, op, ndn, method, mech, &cred, &edn ) == 0 ) {
ldap_pvt_thread_mutex_lock( &conn->c_mutex );
conn->c_cdn = cdn;
cdn = NULL;
if(edn != NULL) {
conn->c_dn = edn;
} else {
conn->c_dn = ndn;
ndn = NULL;
}
conn->c_dn = strdup( dn );
pthread_mutex_unlock( &conn->c_dnmutex );
Debug( LDAP_DEBUG_TRACE, "do_bind: bound \"%s\" to \"%s\"\n",
conn->c_cdn, conn->c_dn, method );
ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
/* send this here to avoid a race condition */
send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
send_ldap_result( conn, op, LDAP_SUCCESS,
NULL, NULL, NULL );
} else if (edn != NULL) {
free( edn );
}
} else {
send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
"Function not implemented" );
send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
NULL, "Function not implemented", NULL );
}
free( dn );
cleanup:
if( cdn != NULL ) {
free( cdn );
}
if( ndn != NULL ) {
free( ndn );
}
if ( mech != NULL ) {
free( mech );
}
if ( cred.bv_val != NULL ) {
free( cred.bv_val );
}
return rc;
}

View file

@ -1,9 +1,12 @@
/* charray.c - routines for dealing with char * arrays */
#include "portable.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "slap.h"
void
@ -26,7 +29,7 @@ charray_add(
(n + 2) * sizeof(char *) );
}
(*a)[n++] = s;
(*a)[n++] = ch_strdup(s);
(*a)[n] = NULL;
}
@ -48,7 +51,7 @@ charray_merge(
*a = (char **) ch_realloc( (char *) *a, (n + nn + 1) * sizeof(char *) );
for ( i = 0; i < nn; i++ ) {
(*a)[n + i] = s[i];
(*a)[n + i] = ch_strdup(s[i]);
}
(*a)[n + nn] = NULL;
}
@ -99,20 +102,53 @@ charray_dup( char **a )
new = (char **) ch_malloc( (i + 1) * sizeof(char *) );
for ( i = 0; a[i] != NULL; i++ ) {
new[i] = strdup( a[i] );
new[i] = ch_strdup( a[i] );
}
new[i] = NULL;
return( new );
}
char *
charray2str( char **a )
{
char *s;
int i;
size_t cur, len = 0;
if( a == NULL ) return NULL;
for( i=0 ; a[i] != NULL ; i++ ) {
len += strlen( a[i] );
}
if( len == 0 ) return NULL;
s = ch_malloc( len + 1 );
cur = 0;
for( i=0 ; a[i] != NULL ; i++ ) {
len = strlen( a[i] );
strncpy( &s[cur], a[i], len );
cur += len;
}
s[len] = '\0';
return s;
}
char **
str2charray( char *str, char *brkstr )
{
char **res;
char *s;
char *lasts;
int i;
/* protect the input string from strtok */
str = ch_strdup( str );
i = 1;
for ( s = str; *s; s++ ) {
if ( strchr( brkstr, *s ) != NULL ) {
@ -122,11 +158,16 @@ str2charray( char *str, char *brkstr )
res = (char **) ch_malloc( (i + 1) * sizeof(char *) );
i = 0;
for ( s = strtok( str, brkstr ); s != NULL; s = strtok( NULL,
brkstr ) ) {
res[i++] = strdup( s );
for ( s = ldap_pvt_strtok( str, brkstr, &lasts );
s != NULL;
s = ldap_pvt_strtok( NULL, brkstr, &lasts ) )
{
res[i++] = ch_strdup( s );
}
res[i] = NULL;
free( str );
return( res );
}

View file

@ -10,28 +10,35 @@
* is provided ``as is'' without express or implied warranty.
*/
#include "portable.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <ac/socket.h>
#include "slap.h"
extern Backend *select_backend();
extern char *default_referral;
void
int
do_compare(
Connection *conn,
Operation *op
)
{
char *dn;
char *ndn;
Ava ava;
int rc;
Backend *be;
int rc = LDAP_SUCCESS;
Debug( LDAP_DEBUG_TRACE, "do_compare\n", 0, 0, 0 );
if( op->o_bind_in_progress ) {
Debug( LDAP_DEBUG_ANY, "do_compare: SASL bind in progress.\n",
0, 0, 0 );
send_ldap_result( conn, op, LDAP_SASL_BIND_IN_PROGRESS,
NULL, "SASL bind in progress", NULL );
return LDAP_SASL_BIND_IN_PROGRESS;
}
/*
* Parse the compare request. It looks like this:
*
@ -44,42 +51,57 @@ do_compare(
* }
*/
if ( ber_scanf( op->o_ber, "{a{ao}}", &dn, &ava.ava_type,
if ( ber_scanf( op->o_ber, "{a{ao}}", &ndn, &ava.ava_type,
&ava.ava_value ) == LBER_ERROR ) {
Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL, "" );
return;
send_ldap_disconnect( conn, op,
LDAP_PROTOCOL_ERROR, "decoding error" );
return -1;
}
if( ( rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) {
free( ndn );
ava_free( &ava, 0 );
Debug( LDAP_DEBUG_ANY, "do_compare: get_ctrls failed\n", 0, 0, 0 );
return rc;
}
value_normalize( ava.ava_value.bv_val, attr_syntax( ava.ava_type ) );
dn_normalize( dn );
Debug( LDAP_DEBUG_ARGS, "do_compare: dn (%s) attr (%s) value (%s)\n",
dn, ava.ava_type, ava.ava_value.bv_val );
ndn, ava.ava_type, ava.ava_value.bv_val );
ndn = dn_normalize_case( ndn );
Statslog( LDAP_DEBUG_STATS, "conn=%d op=%d CMP dn=\"%s\" attr=\"%s\"\n",
conn->c_connid, op->o_opid, dn, ava.ava_type, 0 );
conn->c_connid, op->o_opid, ndn, ava.ava_type, 0 );
/*
* We could be serving multiple database backends. Select the
* appropriate one, or send a referral to our "referral server"
* if we don't hold it.
*/
if ( (be = select_backend( dn )) == NULL ) {
free( dn );
if ( (be = select_backend( ndn )) == NULL ) {
free( ndn );
ava_free( &ava, 0 );
send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
default_referral );
return;
send_ldap_result( conn, op, rc = LDAP_REFERRAL,
NULL, NULL, default_referral );
return 1;
}
if ( be->be_compare != NULL ) {
(*be->be_compare)( be, conn, op, dn, &ava );
/* alias suffix if approp */
ndn = suffixAlias( ndn, op, be );
if ( be->be_compare ) {
(*be->be_compare)( be, conn, op, ndn, &ava );
} else {
send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
"Function not implemented" );
send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
NULL, "Function not implemented", NULL );
}
free( dn );
free( ndn );
ava_free( &ava, 0 );
return rc;
}

View file

@ -1,19 +1,21 @@
/* config.c - configuration file handling routines */
#include "portable.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
#include <ac/string.h>
#include <ac/ctype.h>
#include <ac/socket.h>
#include "ldap_defaults.h"
#include "slap.h"
#include "ldapconfig.h"
#define MAXARGS 100
extern Backend *new_backend();
extern char *default_referral;
extern int ldap_syslog;
extern int global_schemacheck;
/*
* defaults for various global variables
*/
@ -23,36 +25,57 @@ struct acl *global_acl = NULL;
int global_default_access = ACL_READ;
char *replogfile;
int global_lastmod;
int global_idletimeout = 0;
char *global_realm = NULL;
char *ldap_srvtab = "";
static char *fp_getline();
static void fp_getline_init();
static void fp_parse_line();
char *slapd_pid_file = NULL;
char *slapd_args_file = NULL;
static char *strtok_quote();
static char *fp_getline(FILE *fp, int *lineno);
static void fp_getline_init(int *lineno);
static int fp_parse_line(char *line, int *argcp, char **argv);
void
read_config( char *fname, Backend **bep, FILE *pfp )
static char *strtok_quote(char *line, char *sep);
int
read_config( char *fname )
{
FILE *fp;
char *line, *savefname, *dn;
char *line, *savefname, *saveline;
int cargc, savelineno;
char *cargv[MAXARGS];
int lineno, i;
Backend *be;
if ( (fp = pfp) == NULL && (fp = fopen( fname, "r" )) == NULL ) {
struct berval *vals[2];
struct berval val;
static BackendInfo *bi = NULL;
static BackendDB *be = NULL;
vals[0] = &val;
vals[1] = NULL;
if ( (fp = fopen( fname, "r" )) == NULL ) {
ldap_syslog = 1;
Debug( LDAP_DEBUG_ANY,
"could not open config file \"%s\" - absolute path?\n",
fname, 0, 0 );
perror( fname );
exit( 1 );
return 1;
}
Debug( LDAP_DEBUG_CONFIG, "reading config file %s\n", fname, 0, 0 );
be = *bep;
if ( schema_init( ) != 0 ) {
Debug( LDAP_DEBUG_ANY,
"error initializing the schema\n",
0, 0, 0 );
return( 1 );
}
fp_getline_init( &lineno );
while ( (line = fp_getline( fp, &lineno )) != NULL ) {
/* skip comments and blank lines */
if ( line[0] == '#' || line[0] == '\0' ) {
@ -61,7 +84,12 @@ read_config( char *fname, Backend **bep, FILE *pfp )
Debug( LDAP_DEBUG_CONFIG, "line %d (%s)\n", lineno, line, 0 );
fp_parse_line( line, &cargc, cargv );
/* fp_parse_line is destructive, we save a copy */
saveline = ch_strdup( line );
if ( fp_parse_line( line, &cargc, cargv ) != 0 ) {
return( 1 );
}
if ( cargc < 1 ) {
Debug( LDAP_DEBUG_ANY,
@ -70,24 +98,87 @@ read_config( char *fname, Backend **bep, FILE *pfp )
continue;
}
if ( strcasecmp( cargv[0], "backend" ) == 0 ) {
if ( cargc < 2 ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: missing type in \"backend <type>\" line\n",
fname, lineno, 0 );
return( 1 );
}
if( be != NULL ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: backend line must appear before any database definition\n",
fname, lineno, 0 );
return( 1 );
}
bi = backend_info( cargv[1] );
/* start of a new database definition */
if ( strcasecmp( cargv[0], "database" ) == 0 ) {
} else if ( strcasecmp( cargv[0], "database" ) == 0 ) {
if ( cargc < 2 ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: missing type in \"database <type>\" line\n",
fname, lineno, 0 );
exit( 1 );
return( 1 );
}
*bep = new_backend( cargv[1] );
be = *bep;
bi = NULL;
be = backend_db_init( cargv[1] );
/* set size limit */
/* assign a default depth limit for alias deref */
be->be_maxDerefDepth = SLAPD_DEFAULT_MAXDEREFDEPTH;
/* get pid file name */
} else if ( strcasecmp( cargv[0], "pidfile" ) == 0 ) {
if ( cargc < 2 ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: missing file name in \"pidfile <file>\" line\n",
fname, lineno, 0 );
return( 1 );
}
slapd_pid_file = ch_strdup( cargv[1] );
/* get args file name */
} else if ( strcasecmp( cargv[0], "argsfile" ) == 0 ) {
if ( cargc < 2 ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: missing file name in \"argsfile <file>\" line\n",
fname, lineno, 0 );
return( 1 );
}
slapd_args_file = ch_strdup( cargv[1] );
/* set DIGEST realm */
} else if ( strcasecmp( cargv[0], "digest-realm" ) == 0 ) {
if ( cargc < 2 ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: missing realm in \"digest-realm <realm>\" line\n",
fname, lineno, 0 );
return( 1 );
}
if ( be != NULL ) {
be->be_realm = ch_strdup( cargv[1] );
} else if ( global_realm != NULL ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: already set global realm!\n",
fname, lineno, 0 );
return 1;
} else {
global_realm = ch_strdup( cargv[1] );
}
/* set time limit */
} else if ( strcasecmp( cargv[0], "sizelimit" ) == 0 ) {
if ( cargc < 2 ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: missing limit in \"sizelimit <limit>\" line\n",
fname, lineno, 0 );
exit( 1 );
return( 1 );
}
if ( be == NULL ) {
defsize = atoi( cargv[1] );
@ -101,7 +192,7 @@ read_config( char *fname, Backend **bep, FILE *pfp )
Debug( LDAP_DEBUG_ANY,
"%s: line %d: missing limit in \"timelimit <limit>\" line\n",
fname, lineno, 0 );
exit( 1 );
return( 1 );
}
if ( be == NULL ) {
deftime = atoi( cargv[1] );
@ -115,7 +206,7 @@ read_config( char *fname, Backend **bep, FILE *pfp )
Debug( LDAP_DEBUG_ANY,
"%s: line %d: missing dn in \"suffix <dn>\" line\n",
fname, lineno, 0 );
exit( 1 );
return( 1 );
} else if ( cargc > 2 ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: extra cruft after <dn> in \"suffix %s\" line (ignored)\n",
@ -126,27 +217,92 @@ read_config( char *fname, Backend **bep, FILE *pfp )
"%s: line %d: suffix line must appear inside a database definition (ignored)\n",
fname, lineno, 0 );
} else {
dn = strdup( cargv[1] );
char *dn = ch_strdup( cargv[1] );
(void) dn_normalize( dn );
charray_add( &be->be_suffix, dn );
(void) dn_upcase( dn );
charray_add( &be->be_nsuffix, dn );
free( dn );
}
/* set database suffixAlias */
} else if ( strcasecmp( cargv[0], "suffixAlias" ) == 0 ) {
if ( cargc < 2 ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: missing alias and aliased_dn in \"suffixAlias <alias> <aliased_dn>\" line\n",
fname, lineno, 0 );
return( 1 );
} else if ( cargc < 3 ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: missing aliased_dn in \"suffixAlias <alias> <aliased_dn>\" line\n",
fname, lineno, 0 );
return( 1 );
} else if ( cargc > 3 ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: extra cruft in suffixAlias line (ignored)\n",
fname, lineno, 0 );
}
if ( be == NULL ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: suffixAlias line must appear inside a database definition (ignored)\n",
fname, lineno, 0 );
} else {
char *alias, *aliased_dn;
alias = ch_strdup( cargv[1] );
(void) dn_normalize( alias );
aliased_dn = ch_strdup( cargv[2] );
(void) dn_normalize( aliased_dn );
if ( strcasecmp( alias, aliased_dn) == 0 ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: suffixAlias %s is not different from aliased dn (ignored)\n",
fname, lineno, alias );
} else {
(void) dn_normalize_case( alias );
(void) dn_normalize_case( aliased_dn );
charray_add( &be->be_suffixAlias, alias );
charray_add( &be->be_suffixAlias, aliased_dn );
}
free(alias);
free(aliased_dn);
}
/* set max deref depth */
} else if ( strcasecmp( cargv[0], "maxDerefDepth" ) == 0 ) {
if ( cargc < 2 ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: missing depth in \"maxDerefDepth <depth>\" line\n",
fname, lineno, 0 );
return( 1 );
}
if ( be == NULL ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: depth line must appear inside a database definition (ignored)\n",
fname, lineno, 0 );
} else {
be->be_maxDerefDepth = atoi (cargv[1]);
}
/* set magic "root" dn for this database */
} else if ( strcasecmp( cargv[0], "rootdn" ) == 0 ) {
if ( cargc < 2 ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: missing dn in \"rootdn <dn>\" line\n",
fname, lineno, 0 );
exit( 1 );
return( 1 );
}
if ( be == NULL ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: rootdn line must appear inside a database definition (ignored)\n",
fname, lineno, 0 );
} else {
dn = strdup( cargv[1] );
(void) dn_normalize( dn );
be->be_rootdn = dn;
be->be_root_dn = ch_strdup( cargv[1] );
be->be_root_ndn = dn_normalize_case( ch_strdup( cargv[1] ) );
}
/* set super-secret magic database password */
@ -155,14 +311,14 @@ read_config( char *fname, Backend **bep, FILE *pfp )
Debug( LDAP_DEBUG_ANY,
"%s: line %d: missing passwd in \"rootpw <passwd>\" line\n",
fname, lineno, 0 );
exit( 1 );
return( 1 );
}
if ( be == NULL ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: rootpw line must appear inside a database definition (ignored)\n",
fname, lineno, 0 );
} else {
be->be_rootpw = strdup( cargv[1] );
be->be_root_pw = ch_strdup( cargv[1] );
}
/* make this database read-only */
@ -171,7 +327,7 @@ read_config( char *fname, Backend **bep, FILE *pfp )
Debug( LDAP_DEBUG_ANY,
"%s: line %d: missing on|off in \"readonly <on|off>\" line\n",
fname, lineno, 0 );
exit( 1 );
return( 1 );
}
if ( be == NULL ) {
Debug( LDAP_DEBUG_ANY,
@ -191,21 +347,62 @@ read_config( char *fname, Backend **bep, FILE *pfp )
Debug( LDAP_DEBUG_ANY,
"%s: line %d: missing URL in \"referral <URL>\" line\n",
fname, lineno, 0 );
exit( 1 );
return( 1 );
}
default_referral = (char *) malloc( strlen( cargv[1] )
+ sizeof("Referral:\n") + 1 );
strcpy( default_referral, "Referral:\n" );
strcat( default_referral, cargv[1] );
vals[0]->bv_val = cargv[1];
vals[0]->bv_len = strlen( vals[0]->bv_val );
value_add( &default_referral, vals );
/* specify locale */
} else if ( strcasecmp( cargv[0], "locale" ) == 0 ) {
#ifdef HAVE_LOCALE_H
char *locale;
if ( cargc < 2 ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: missing locale in \"locale <name | on | off>\" line\n",
fname, lineno, 0 );
return( 1 );
}
locale = (strcasecmp( cargv[1], "on" ) == 0 ? ""
: strcasecmp( cargv[1], "off" ) == 0 ? "C"
: ch_strdup( cargv[1] ) );
if ( setlocale( LC_CTYPE, locale ) == 0 ) {
Debug( LDAP_DEBUG_ANY,
(*locale
? "%s: line %d: bad locale \"%s\"\n"
: "%s: line %d: bad locale\n"),
fname, lineno, locale );
return( 1 );
}
#else
Debug( LDAP_DEBUG_ANY,
"%s: line %d: \"locale\" unsupported\n",
fname, lineno, 0 );
return( 1 );
#endif
/* specify an objectclass */
} else if ( strcasecmp( cargv[0], "objectclass" ) == 0 ) {
parse_oc( be, fname, lineno, cargc, cargv );
if ( *cargv[1] == '(' ) {
char * p;
p = strchr(saveline,'(');
parse_oc( fname, lineno, p );
} else {
parse_oc_old( be, fname, lineno, cargc, cargv );
}
/* specify an attribute */
} else if ( strcasecmp( cargv[0], "attribute" ) == 0 ) {
attr_syntax_config( fname, lineno, cargc - 1,
&cargv[1] );
if ( *cargv[1] == '(' ) {
char * p;
p = strchr(saveline,'(');
parse_at( fname, lineno, p );
} else {
attr_syntax_config( fname, lineno, cargc - 1,
&cargv[1] );
}
/* turn on/off schema checking */
} else if ( strcasecmp( cargv[0], "schemacheck" ) == 0 ) {
@ -213,12 +410,12 @@ read_config( char *fname, Backend **bep, FILE *pfp )
Debug( LDAP_DEBUG_ANY,
"%s: line %d: missing on|off in \"schemacheck <on|off>\" line\n",
fname, lineno, 0 );
exit( 1 );
return( 1 );
}
if ( strcasecmp( cargv[1], "on" ) == 0 ) {
global_schemacheck = 1;
} else {
if ( strcasecmp( cargv[1], "off" ) == 0 ) {
global_schemacheck = 0;
} else {
global_schemacheck = 1;
}
/* specify access control info */
@ -231,23 +428,26 @@ read_config( char *fname, Backend **bep, FILE *pfp )
Debug( LDAP_DEBUG_ANY,
"%s: line %d: missing limit in \"defaultaccess <access>\" line\n",
fname, lineno, 0 );
exit( 1 );
return( 1 );
}
if ( be == NULL ) {
if ( (global_default_access =
str2access( cargv[1] )) == -1 ) {
if ( ACL_IS_INVALID(ACL_SET(global_default_access,
str2access(cargv[1]))) )
{
Debug( LDAP_DEBUG_ANY,
"%s: line %d: bad access \"%s\" expecting [self]{none|compare|read|write}\n",
fname, lineno, cargv[1] );
exit( 1 );
return( 1 );
}
} else {
if ( (be->be_dfltaccess =
str2access( cargv[1] )) == -1 ) {
if ( ACL_IS_INVALID(ACL_SET(be->be_dfltaccess,
str2access(cargv[1]))) )
{
Debug( LDAP_DEBUG_ANY,
"%s: line %d: bad access \"%s\" expecting [self]{none|compare|read|write}\n",
"%s: line %d: bad access \"%s\", "
"expecting [self]{none|compare|search|read|write}\n",
fname, lineno, cargv[1] );
exit( 1 );
return( 1 );
}
}
@ -257,7 +457,7 @@ read_config( char *fname, Backend **bep, FILE *pfp )
Debug( LDAP_DEBUG_ANY,
"%s: line %d: missing level in \"loglevel <level>\" line\n",
fname, lineno, 0 );
exit( 1 );
return( 1 );
}
ldap_syslog = atoi( cargv[1] );
@ -267,7 +467,7 @@ read_config( char *fname, Backend **bep, FILE *pfp )
Debug( LDAP_DEBUG_ANY,
"%s: line %d: missing host in \"replica <host[:port]>\" line\n",
fname, lineno, 0 );
exit( 1 );
return( 1 );
}
if ( be == NULL ) {
Debug( LDAP_DEBUG_ANY,
@ -278,7 +478,7 @@ read_config( char *fname, Backend **bep, FILE *pfp )
if ( strncasecmp( cargv[i], "host=", 5 )
== 0 ) {
charray_add( &be->be_replica,
strdup( cargv[i] + 5 ) );
cargv[i] + 5 );
break;
}
}
@ -295,15 +495,15 @@ read_config( char *fname, Backend **bep, FILE *pfp )
Debug( LDAP_DEBUG_ANY,
"%s: line %d: missing dn in \"updatedn <dn>\" line\n",
fname, lineno, 0 );
exit( 1 );
return( 1 );
}
if ( be == NULL ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: updatedn line must appear inside a database definition (ignored)\n",
fname, lineno, 0 );
} else {
be->be_updatedn = strdup( cargv[1] );
(void) dn_normalize( be->be_updatedn );
be->be_update_ndn = ch_strdup( cargv[1] );
(void) dn_normalize_case( be->be_update_ndn );
}
/* replication log file to which changes are appended */
@ -312,12 +512,12 @@ read_config( char *fname, Backend **bep, FILE *pfp )
Debug( LDAP_DEBUG_ANY,
"%s: line %d: missing dn in \"replogfile <filename>\" line\n",
fname, lineno, 0 );
exit( 1 );
return( 1 );
}
if ( be ) {
be->be_replogfile = strdup( cargv[1] );
be->be_replogfile = ch_strdup( cargv[1] );
} else {
replogfile = strdup( cargv[1] );
replogfile = ch_strdup( cargv[1] );
}
/* maintain lastmodified{by,time} attributes */
@ -326,7 +526,7 @@ read_config( char *fname, Backend **bep, FILE *pfp )
Debug( LDAP_DEBUG_ANY,
"%s: line %d: missing on|off in \"lastmod <on|off>\" line\n",
fname, lineno, 0 );
exit( 1 );
return( 1 );
}
if ( strcasecmp( cargv[1], "on" ) == 0 ) {
if ( be )
@ -340,18 +540,42 @@ read_config( char *fname, Backend **bep, FILE *pfp )
global_lastmod = OFF;
}
/* set idle timeout value */
} else if ( strcasecmp( cargv[0], "idletimeout" ) == 0 ) {
int i;
if ( cargc < 2 ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: missing timeout value in \"idletimeout <seconds>\" line\n",
fname, lineno, 0 );
return( 1 );
}
i = atoi( cargv[1] );
if( i < 0 ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: timeout value (%d) invalid \"idletimeout <seconds>\" line\n",
fname, lineno, i );
return( 1 );
}
global_idletimeout = i;
/* include another config file */
} else if ( strcasecmp( cargv[0], "include" ) == 0 ) {
if ( cargc < 2 ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: missing filename in \"include <filename>\" line\n",
fname, lineno, 0 );
exit( 1 );
return( 1 );
}
savefname = strdup( cargv[1] );
savefname = ch_strdup( cargv[1] );
savelineno = lineno;
read_config( savefname, bep, NULL );
be = *bep;
if ( read_config( savefname ) != 0 ) {
return( 1 );
}
free( savefname );
lineno = savelineno - 1;
@ -361,30 +585,66 @@ read_config( char *fname, Backend **bep, FILE *pfp )
Debug( LDAP_DEBUG_ANY,
"%s: line %d: missing filename in \"srvtab <filename>\" line\n",
fname, lineno, 0 );
exit( 1 );
return( 1 );
}
ldap_srvtab = strdup( cargv[1] );
ldap_srvtab = ch_strdup( cargv[1] );
/* pass anything else to the current backend config routine */
#ifdef SLAPD_MODULES
} else if (strcasecmp( cargv[0], "loadmodule") == 0 ) {
if ( cargc < 2 ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: missing filename in \"loadmodule <filename>\" line\n",
fname, lineno, 0 );
exit( 1 );
}
if (!load_module(cargv[1], cargc - 2, (cargc > 2) ? cargv + 2 : NULL)) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: failed to load or initialize module %s\n",
fname, lineno, cargv[1]);
exit( 1 );
}
#endif /*SLAPD_MODULES*/
/* pass anything else to the current backend info/db config routine */
} else {
if ( be == NULL ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: unknown directive \"%s\" outside database definition (ignored)\n",
fname, lineno, cargv[0] );
} else if ( be->be_config == NULL ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: unknown directive \"%s\" inside database definition (ignored)\n",
fname, lineno, cargv[0] );
if ( bi != NULL ) {
if ( bi->bi_config == 0 ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: unknown directive \"%s\" inside backend info definition (ignored)\n",
fname, lineno, cargv[0] );
} else {
if ( (*bi->bi_config)( bi, fname, lineno, cargc, cargv )
!= 0 )
{
return( 1 );
}
}
} else if ( be != NULL ) {
if ( be->be_config == 0 ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: unknown directive \"%s\" inside backend database definition (ignored)\n",
fname, lineno, cargv[0] );
} else {
if ( (*be->be_config)( be, fname, lineno, cargc, cargv )
!= 0 )
{
return( 1 );
}
}
} else {
(*be->be_config)( be, fname, lineno, cargc,
cargv );
Debug( LDAP_DEBUG_ANY,
"%s: line %d: unknown directive \"%s\" outside backend info and database definitions (ignored)\n",
fname, lineno, cargv[0] );
}
}
free( saveline );
}
fclose( fp );
return( 0 );
}
static void
static int
fp_parse_line(
char *line,
int *argcp,
@ -399,11 +659,12 @@ fp_parse_line(
if ( *argcp == MAXARGS ) {
Debug( LDAP_DEBUG_ANY, "Too many tokens (max %d)\n",
MAXARGS, 0, 0 );
exit( 1 );
return( 1 );
}
argv[(*argcp)++] = token;
}
argv[*argcp] = NULL;
return 0;
}
static char *
@ -434,11 +695,14 @@ strtok_quote( char *line, char *sep )
} else {
inquote = 1;
}
strcpy( next, next + 1 );
SAFEMEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
break;
case '\\':
strcpy( next, next + 1 );
if ( next[1] )
SAFEMEMCPY( next,
next + 1, strlen( next + 1 ) + 1 );
next++; /* dont parse the escaped character */
break;
default:
@ -490,7 +754,7 @@ fp_getline( FILE *fp, int *lineno )
if ( (p = strchr( buf, '\n' )) != NULL ) {
*p = '\0';
}
if ( ! isspace( buf[0] ) ) {
if ( ! isspace( (unsigned char) buf[0] ) ) {
return( line );
}

View file

@ -10,19 +10,18 @@
* is provided ``as is'' without express or implied warranty.
*/
#include "portable.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "ldap_defaults.h"
#include "slap.h"
#include "ldapconfig.h"
#if defined( SLAPD_CONFIG_DN )
extern int nbackends;
extern Backend *backends;
extern char *default_referral;
/*
* no mutex protection in here - take our chances!
*/
@ -40,8 +39,11 @@ config_info( Connection *conn, Operation *op )
vals[1] = NULL;
e = (Entry *) ch_calloc( 1, sizeof(Entry) );
e->e_attrs = NULL;
e->e_dn = strdup( SLAPD_CONFIG_DN );
e->e_dn = ch_strdup( SLAPD_CONFIG_DN );
e->e_ndn = dn_normalize_case( ch_strdup( SLAPD_CONFIG_DN ));
e->e_private = NULL;
for ( i = 0; i < nbackends; i++ ) {
strcpy( buf, backends[i].be_type );
@ -54,15 +56,8 @@ config_info( Connection *conn, Operation *op )
attr_merge( e, "database", vals );
}
if ( default_referral != NULL ) {
strcpy( buf, default_referral );
val.bv_val = buf;
val.bv_len = strlen( buf );
attr_merge( e, "database", vals );
}
send_search_entry( &backends[0], conn, op, e, NULL, 0 );
send_ldap_search_result( conn, op, LDAP_SUCCESS, NULL, NULL, 1 );
send_search_entry( &backends[0], conn, op, e, NULL, 0, 1 );
send_search_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL, 1 );
entry_free( e );
}

163
servers/slapd/controls.c Normal file
View file

@ -0,0 +1,163 @@
/*
* Copyright 1999 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted only
* as authorized by the OpenLDAP Public License. A copy of this
* license is available at http://www.OpenLDAP.org/license.html or
* in file LICENSE in the top-level directory of the distribution.
*/
#include "portable.h"
#include <stdio.h>
#include <ac/socket.h>
#include "slap.h"
#include "../../libraries/liblber/lber-int.h"
char *supportedControls[] = {
LDAP_CONTROL_MANAGEDSAIT,
NULL
};
int get_ctrls(
Connection *conn,
Operation *op,
int sendres )
{
int nctrls;
ber_tag_t tag;
ber_len_t len;
char *opaque;
BerElement *ber = op->o_ber;
LDAPControl ***ctrls = &op->o_ctrls;
int rc = LDAP_SUCCESS;
char *errmsg = NULL;
len = ber_pvt_ber_remaining(ber);
if( len == 0) {
/* no controls */
rc = LDAP_SUCCESS;
goto return_results;
}
if(( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) {
if( tag == LBER_ERROR ) {
rc = -1;
errmsg = "unexpected data in PDU";
}
goto return_results;
}
if( op->o_protocol < LDAP_VERSION3 ) {
rc = -1;
errmsg = "controls require LDAPv3";
goto return_results;
}
/* set through each element */
nctrls = 0;
*ctrls = ch_malloc( 1 * sizeof(LDAPControl *) );
#if 0
if( *ctrls == NULL ) {
rc = LDAP_NO_MEMORY;
errmsg = "no memory";
goto return_results;
}
#endif
ctrls[nctrls] = NULL;
for( tag = ber_first_element( ber, &len, &opaque );
tag != LBER_ERROR;
tag = ber_next_element( ber, &len, opaque ) )
{
LDAPControl *tctrl;
LDAPControl **tctrls;
tctrl = ch_calloc( 1, sizeof(LDAPControl) );
/* allocate pointer space for current controls (nctrls)
* + this control + extra NULL
*/
tctrls = (tctrl == NULL) ? NULL :
ch_realloc(*ctrls, (nctrls+2) * sizeof(LDAPControl *));
#if 0
if( tctrls == NULL ) {
/* one of the above allocation failed */
if( tctrl != NULL ) {
ch_free( tctrl );
}
ldap_controls_free(*ctrls);
*ctrls = NULL;
rc = LDAP_NO_MEMORY;
errmsg = "no memory";
goto return_results;
}
#endif
tctrls[nctrls++] = tctrl;
tctrls[nctrls] = NULL;
tag = ber_scanf( ber, "{a" /*}*/, &tctrl->ldctl_oid );
if( tag != LBER_ERROR ) {
tag = ber_peek_tag( ber, &len );
}
if( tag == LBER_BOOLEAN ) {
ber_int_t crit;
tag = ber_scanf( ber, "b", &crit );
tctrl->ldctl_iscritical = crit ? (char) 0 : (char) ~0;
}
if( tag != LBER_ERROR ) {
tag = ber_peek_tag( ber, &len );
}
if( tag == LBER_OCTETSTRING ) {
tag = ber_scanf( ber, "o", &tctrl->ldctl_value );
} else {
tctrl->ldctl_value.bv_val = NULL;
}
if( tag == LBER_ERROR ) {
*ctrls = NULL;
ldap_controls_free( tctrls );
rc = -1;
errmsg = "decoding controls error";
goto return_results;
}
if( tctrl->ldctl_iscritical &&
!charray_inlist( supportedControls, tctrl->ldctl_oid ) )
{
rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
errmsg = "critical extension is unavailable ";
goto return_results;
}
*ctrls = tctrls;
}
return_results:
if( sendres && rc != LDAP_SUCCESS ) {
if( rc == -1 ) {
send_ldap_disconnect( conn, op, rc, errmsg );
} else {
send_ldap_result( conn, op, rc, NULL, errmsg, NULL );
}
}
return rc;
}

View file

@ -10,80 +10,98 @@
* is provided ``as is'' without express or implied warranty.
*/
#include "portable.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "slap.h"
extern Backend *select_backend();
extern char *default_referral;
void
int
do_delete(
Connection *conn,
Operation *op
)
{
char *dn, *odn;
char *ndn;
Backend *be;
int rc;
Debug( LDAP_DEBUG_TRACE, "do_delete\n", 0, 0, 0 );
if( op->o_bind_in_progress ) {
Debug( LDAP_DEBUG_ANY, "do_delete: SASL bind in progress.\n",
0, 0, 0 );
send_ldap_result( conn, op, LDAP_SASL_BIND_IN_PROGRESS,
NULL, "SASL bind in progress", NULL );
return LDAP_SASL_BIND_IN_PROGRESS;
}
/*
* Parse the delete request. It looks like this:
*
* DelRequest := DistinguishedName
*/
if ( ber_scanf( op->o_ber, "a", &dn ) == LBER_ERROR ) {
if ( ber_scanf( op->o_ber, "a", &ndn ) == LBER_ERROR ) {
Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL, "" );
return;
send_ldap_disconnect( conn, op,
LDAP_PROTOCOL_ERROR, "decoding error" );
return -1;
}
odn = strdup( dn );
dn_normalize( dn );
Debug( LDAP_DEBUG_ARGS, "do_delete: dn (%s)\n", dn, 0, 0 );
if( ( rc = get_ctrls( conn, op, 1 ) ) != LDAP_SUCCESS ) {
free( ndn );
Debug( LDAP_DEBUG_ANY, "do_add: get_ctrls failed\n", 0, 0, 0 );
return rc;
}
Debug( LDAP_DEBUG_STATS, "DEL dn=\"%s\"\n", dn, 0, 0 );
Debug( LDAP_DEBUG_ARGS, "do_delete: dn (%s)\n", ndn, 0, 0 );
dn_normalize_case( ndn );
Debug( LDAP_DEBUG_STATS, "DEL dn=\"%s\"\n", ndn, 0, 0 );
/*
* We could be serving multiple database backends. Select the
* appropriate one, or send a referral to our "referral server"
* if we don't hold it.
*/
if ( (be = select_backend( dn )) == NULL ) {
free( dn );
free( odn );
send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
default_referral );
return;
if ( (be = select_backend( ndn )) == NULL ) {
free( ndn );
send_ldap_result( conn, op, rc = LDAP_REFERRAL,
NULL, NULL, default_referral );
return rc;
}
/* alias suffix if approp */
ndn = suffixAlias( ndn, op, be );
/*
* do the delete if 1 && (2 || 3)
* 1) there is a delete function implemented in this backend;
* 2) this backend is master for what it holds;
* 3) it's a replica and the dn supplied is the updatedn.
* 3) it's a replica and the dn supplied is the update_ndn.
*/
if ( be->be_delete != NULL ) {
if ( be->be_delete ) {
/* do the update here */
if ( be->be_updatedn == NULL || strcasecmp( be->be_updatedn,
op->o_dn ) == 0 ) {
if ( (*be->be_delete)( be, conn, op, dn ) == 0 ) {
replog( be, LDAP_REQ_DELETE, odn, NULL, 0 );
if ( be->be_update_ndn == NULL ||
strcmp( be->be_update_ndn, op->o_ndn ) == 0 )
{
if ( (*be->be_delete)( be, conn, op, ndn ) == 0 ) {
replog( be, LDAP_REQ_DELETE, ndn, NULL, 0 );
}
} else {
send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
default_referral );
send_ldap_result( conn, op, rc = LDAP_REFERRAL,
NULL, NULL, default_referral );
}
} else {
send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
"Function not implemented" );
send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
NULL, "Function not implemented", NULL );
}
free( dn );
free( odn );
free( ndn );
return rc;
}

112
servers/slapd/extended.c Normal file
View file

@ -0,0 +1,112 @@
/*
* Copyright 1999 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted only
* as authorized by the OpenLDAP Public License. A copy of this
* license is available at http://www.OpenLDAP.org/license.html or
* in file LICENSE in the top-level directory of the distribution.
*/
/*
* LDAPv3 Extended Operation Request
* ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
* requestName [0] LDAPOID,
* requestValue [1] OCTET STRING OPTIONAL
* }
*
* LDAPv3 Extended Operation Response
* ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
* COMPONENTS OF LDAPResult,
* responseName [10] LDAPOID OPTIONAL,
* response [11] OCTET STRING OPTIONAL
* }
*
*/
#include "portable.h"
#include <stdio.h>
#include <ac/socket.h>
#include "slap.h"
char *supportedExtensions[] = {
NULL
};
int
do_extended(
Connection *conn,
Operation *op
)
{
int rc = LDAP_SUCCESS;
char* reqoid ;
struct berval reqdata;
ber_tag_t tag;
ber_len_t len;
Debug( LDAP_DEBUG_TRACE, "do_extended\n", 0, 0, 0 );
reqoid = NULL;
reqdata.bv_val = NULL;
if( op->o_protocol < LDAP_VERSION3 ) {
Debug( LDAP_DEBUG_ANY, "do_extended: protocol version (%d) too low\n",
op->o_protocol, 0 ,0 );
send_ldap_disconnect( conn, op,
LDAP_PROTOCOL_ERROR, "requires LDAPv3" );
rc = -1;
goto done;
}
if ( ber_scanf( op->o_ber, "a", &reqoid ) == LBER_ERROR ) {
Debug( LDAP_DEBUG_ANY, "do_extended: ber_scanf failed\n", 0, 0 ,0 );
send_ldap_disconnect( conn, op,
LDAP_PROTOCOL_ERROR, "decoding error" );
rc = -1;
goto done;
}
if( !charray_inlist( supportedExtensions, reqoid ) ) {
Debug( LDAP_DEBUG_ANY, "do_extended: unsupported operation \"%s\"\n",
reqoid, 0 ,0 );
send_ldap_result( conn, op, rc = LDAP_PROTOCOL_ERROR,
NULL, "unsuppored extended operation", NULL );
goto done;
}
tag = ber_peek_tag( op->o_ber, &len );
if( ber_peek_tag( op->o_ber, &len ) == LDAP_TAG_EXOP_REQ_VALUE ) {
if( ber_scanf( op->o_ber, "o", &reqdata ) != LBER_ERROR ) {
Debug( LDAP_DEBUG_ANY, "do_extended: ber_scanf failed\n", 0, 0 ,0 );
send_ldap_disconnect( conn, op,
LDAP_PROTOCOL_ERROR, "decoding error" );
rc = -1;
goto done;
}
}
if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_ANY, "do_extended: get_ctrls failed\n", 0, 0 ,0 );
return rc;
}
Debug( LDAP_DEBUG_ARGS, "do_extended: oid \"%s\"\n", reqoid, 0 ,0 );
send_ldap_result( conn, op, rc = LDAP_PROTOCOL_ERROR,
NULL, "unsupported extended operation", NULL );
done:
if ( reqoid != NULL ) {
free( reqoid );
}
if ( reqdata.bv_val != NULL ) {
free( reqdata.bv_val );
}
return rc;
}

View file

@ -1,37 +1,173 @@
/* init.c - initialize various things */
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "portable.h"
#include <stdio.h>
#include <ac/socket.h>
#include <ac/string.h>
#include <ac/time.h>
#include "slap.h"
extern pthread_mutex_t active_threads_mutex;
extern pthread_mutex_t new_conn_mutex;
extern pthread_mutex_t currenttime_mutex;
extern pthread_mutex_t entry2str_mutex;
extern pthread_mutex_t replog_mutex;
extern pthread_mutex_t ops_mutex;
extern pthread_mutex_t num_sent_mutex;
#ifndef sunos5
extern pthread_mutex_t regex_mutex;
/*
* read-only global variables or variables only written by the listener
* thread (after they are initialized) - no need to protect them with a mutex.
*/
int slap_debug = 0;
#ifdef LDAP_DEBUG
int ldap_syslog = LDAP_DEBUG_STATS;
#else
int ldap_syslog;
#endif
init()
{
pthread_mutex_init( &active_threads_mutex, pthread_mutexattr_default );
pthread_mutex_init( &new_conn_mutex, pthread_mutexattr_default );
pthread_mutex_init( &currenttime_mutex, pthread_mutexattr_default );
pthread_mutex_init( &entry2str_mutex, pthread_mutexattr_default );
pthread_mutex_init( &replog_mutex, pthread_mutexattr_default );
pthread_mutex_init( &ops_mutex, pthread_mutexattr_default );
pthread_mutex_init( &num_sent_mutex, pthread_mutexattr_default );
#ifndef sunos5
pthread_mutex_init( &regex_mutex, pthread_mutexattr_default );
int ldap_syslog_level = LOG_DEBUG;
struct berval **default_referral = NULL;
int g_argc;
char **g_argv;
/*
* global variables that need mutex protection
*/
int active_threads;
ldap_pvt_thread_mutex_t active_threads_mutex;
ldap_pvt_thread_cond_t active_threads_cond;
ldap_pvt_thread_mutex_t gmtime_mutex;
#ifdef SLAPD_CRYPT
ldap_pvt_thread_mutex_t crypt_mutex;
#endif
int num_conns;
long num_ops_initiated;
long num_ops_completed;
ldap_pvt_thread_mutex_t num_ops_mutex;
long num_entries_sent;
long num_refs_sent;
long num_bytes_sent;
long num_pdu_sent;
ldap_pvt_thread_mutex_t num_sent_mutex;
/*
* these mutexes must be used when calling the entry2str()
* routine since it returns a pointer to static data.
*/
ldap_pvt_thread_mutex_t entry2str_mutex;
ldap_pvt_thread_mutex_t replog_mutex;
static char* slap_name;
int slapMode = SLAP_UNDEFINED_MODE;
static ldap_pvt_thread_mutex_t currenttime_mutex;
int
slap_init( int mode, char *name )
{
int rc;
if( slapMode != SLAP_UNDEFINED_MODE ) {
Debug( LDAP_DEBUG_ANY,
"%s init: init called twice (old=%d, new=%d)\n",
name, slapMode, mode );
return 1;
}
slapMode = mode;
switch ( slapMode ) {
case SLAP_SERVER_MODE:
case SLAP_TOOL_MODE:
#ifdef SLAPD_BDB2
case SLAP_TIMEDSERVER_MODE:
case SLAP_TOOLID_MODE:
#endif
Debug( LDAP_DEBUG_TRACE,
"%s init: initiated %s.\n",
name, mode == SLAP_TOOL_MODE ? "tool" : "server", 0 );
slap_name = name;
(void) ldap_pvt_thread_initialize();
ldap_pvt_thread_mutex_init( &active_threads_mutex );
ldap_pvt_thread_cond_init( &active_threads_cond );
ldap_pvt_thread_mutex_init( &currenttime_mutex );
ldap_pvt_thread_mutex_init( &entry2str_mutex );
ldap_pvt_thread_mutex_init( &replog_mutex );
ldap_pvt_thread_mutex_init( &num_ops_mutex );
ldap_pvt_thread_mutex_init( &num_sent_mutex );
ldap_pvt_thread_mutex_init( &gmtime_mutex );
#ifdef SLAPD_CRYPT
ldap_pvt_thread_mutex_init( &crypt_mutex );
#endif
rc = backend_init();
break;
default:
Debug( LDAP_DEBUG_ANY,
"%s init: undefined mode (%d).\n", name, mode, 0 );
rc = 1;
break;
}
return rc;
}
int slap_startup(int dbnum)
{
int rc;
Debug( LDAP_DEBUG_TRACE,
"%s startup: initiated.\n",
slap_name, 0, 0 );
rc = backend_startup(dbnum);
return rc;
}
int slap_shutdown(int dbnum)
{
int rc;
Debug( LDAP_DEBUG_TRACE,
"%s shutdown: initiated\n",
slap_name, 0, 0 );
/* let backends do whatever cleanup they need to do */
rc = backend_shutdown(dbnum);
return rc;
}
int slap_destroy(void)
{
int rc;
Debug( LDAP_DEBUG_TRACE,
"%s shutdown: freeing system resources.\n",
slap_name, 0, 0 );
rc = backend_destroy();
ldap_pvt_thread_destroy();
/* should destory the above mutex */
return rc;
}
/* should create a utils.c for these */
time_t slap_get_time(void)
{
time_t t;
ldap_pvt_thread_mutex_lock( &currenttime_mutex );
time( &t );
ldap_pvt_thread_mutex_unlock( &currenttime_mutex );
return t;
}

View file

@ -10,39 +10,46 @@
* is provided ``as is'' without express or implied warranty.
*/
#include "portable.h"
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <ac/socket.h>
#include <ac/string.h>
#include <ac/time.h>
#include "slap.h"
extern Backend *select_backend();
static void modlist_free(LDAPModList *ml);
extern char *default_referral;
extern time_t currenttime;
extern pthread_mutex_t currenttime_mutex;
extern int global_lastmod;
static void modlist_free();
static void add_lastmods();
void
int
do_modify(
Connection *conn,
Operation *op
)
{
char *dn, *odn;
char *ndn;
char *last;
unsigned long tag, len;
LDAPMod *mods, *tmp;
LDAPMod **modtail;
ber_tag_t tag;
ber_len_t len;
LDAPModList *modlist;
LDAPModList **modtail;
#ifdef LDAP_DEBUG
LDAPModList *tmp;
#endif
Backend *be;
int rc;
Debug( LDAP_DEBUG_TRACE, "do_modify\n", 0, 0, 0 );
if( op->o_bind_in_progress ) {
Debug( LDAP_DEBUG_ANY, "do_modify: SASL bind in progress.\n",
0, 0, 0 );
send_ldap_result( conn, op, LDAP_SASL_BIND_IN_PROGRESS, NULL,
"SASL bind in progress", NULL );
return LDAP_SASL_BIND_IN_PROGRESS;
}
/*
* Parse the modify request. It looks like this:
*
@ -62,198 +69,150 @@ do_modify(
* }
*/
if ( ber_scanf( op->o_ber, "{a", &dn ) == LBER_ERROR ) {
if ( ber_scanf( op->o_ber, "{a" /*}*/, &ndn ) == LBER_ERROR ) {
Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL, "" );
return;
send_ldap_disconnect( conn, op,
LDAP_PROTOCOL_ERROR, "decoding error" );
return -1;
}
odn = strdup( dn );
dn_normalize( dn );
Debug( LDAP_DEBUG_ARGS, "do_modify: dn (%s)\n", dn, 0, 0 );
Debug( LDAP_DEBUG_ARGS, "do_modify: dn (%s)\n", ndn, 0, 0 );
(void) dn_normalize_case( ndn );
/* collect modifications & save for later */
mods = NULL;
modtail = &mods;
modlist = NULL;
modtail = &modlist;
for ( tag = ber_first_element( op->o_ber, &len, &last );
tag != LBER_DEFAULT;
tag = ber_next_element( op->o_ber, &len, last ) )
{
(*modtail) = (LDAPMod *) ch_calloc( 1, sizeof(LDAPMod) );
ber_int_t mop;
if ( ber_scanf( op->o_ber, "{i{a[V]}}", &(*modtail)->mod_op,
&(*modtail)->mod_type, &(*modtail)->mod_bvalues )
(*modtail) = (LDAPModList *) ch_calloc( 1, sizeof(LDAPModList) );
if ( ber_scanf( op->o_ber, "{i{a[V]}}", &mop,
&(*modtail)->ml_type, &(*modtail)->ml_bvalues )
== LBER_ERROR )
{
send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
"decoding error" );
free( dn );
free( odn );
send_ldap_disconnect( conn, op,
LDAP_PROTOCOL_ERROR, "decoding modlist error" );
free( ndn );
free( *modtail );
modlist_free( mods );
return;
*modtail = NULL;
modlist_free( modlist );
return -1;
}
if ( (*modtail)->mod_op != LDAP_MOD_ADD &&
(*modtail)->mod_op != LDAP_MOD_DELETE &&
(*modtail)->mod_op != LDAP_MOD_REPLACE )
(*modtail)->ml_op = mop;
if ( (*modtail)->ml_op != LDAP_MOD_ADD &&
(*modtail)->ml_op != LDAP_MOD_DELETE &&
(*modtail)->ml_op != LDAP_MOD_REPLACE )
{
send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
"unrecognized modify operation" );
free( dn );
free( odn );
modlist_free( mods );
return;
send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR,
NULL, "unrecognized modify operation", NULL );
free( ndn );
modlist_free( modlist );
return LDAP_PROTOCOL_ERROR;
}
if ( (*modtail)->mod_bvalues == NULL && (*modtail)->mod_op
!= LDAP_MOD_DELETE ) {
send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
"no values given" );
free( dn );
free( odn );
modlist_free( mods );
return;
if ( (*modtail)->ml_bvalues == NULL
&& (*modtail)->ml_op != LDAP_MOD_DELETE )
{
send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR,
NULL, "unrecognized modify operation", NULL );
free( ndn );
modlist_free( modlist );
return LDAP_PROTOCOL_ERROR;
}
attr_normalize( (*modtail)->mod_type );
attr_normalize( (*modtail)->ml_type );
modtail = &(*modtail)->mod_next;
modtail = &(*modtail)->ml_next;
}
*modtail = NULL;
#ifdef LDAP_DEBUG
Debug( LDAP_DEBUG_ARGS, "modifications:\n", 0, 0, 0 );
for ( tmp = mods; tmp != NULL; tmp = tmp->mod_next ) {
Debug( LDAP_DEBUG_ARGS, "\t%s: %s\n", tmp->mod_op
== LDAP_MOD_ADD ? "add" : (tmp->mod_op == LDAP_MOD_DELETE ?
"delete" : "replace"), tmp->mod_type, 0 );
for ( tmp = modlist; tmp != NULL; tmp = tmp->ml_next ) {
Debug( LDAP_DEBUG_ARGS, "\t%s: %s\n",
tmp->ml_op == LDAP_MOD_ADD
? "add" : (tmp->ml_op == LDAP_MOD_DELETE
? "delete" : "replace"), tmp->ml_type, 0 );
}
#endif
if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) {
free( ndn );
modlist_free( modlist );
Debug( LDAP_DEBUG_ANY, "do_modify: get_ctrls failed\n", 0, 0, 0 );
return rc;
}
Statslog( LDAP_DEBUG_STATS, "conn=%d op=%d MOD dn=\"%s\"\n",
conn->c_connid, op->o_opid, dn, 0, 0 );
conn->c_connid, op->o_opid, ndn, 0, 0 );
/*
* We could be serving multiple database backends. Select the
* appropriate one, or send a referral to our "referral server"
* if we don't hold it.
*/
if ( (be = select_backend( dn )) == NULL ) {
free( dn );
free( odn );
modlist_free( mods );
send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
default_referral );
return;
if ( (be = select_backend( ndn )) == NULL ) {
free( ndn );
modlist_free( modlist );
send_ldap_result( conn, op, rc = LDAP_REFERRAL,
NULL, NULL, default_referral );
return rc;
}
/* alias suffix if approp */
ndn = suffixAlias ( ndn, op, be );
/*
* do the modify if 1 && (2 || 3)
* 1) there is a modify function implemented in this backend;
* 2) this backend is master for what it holds;
* 3) it's a replica and the dn supplied is the updatedn.
* 3) it's a replica and the dn supplied is the update_ndn.
*/
if ( be->be_modify != NULL ) {
if ( be->be_modify ) {
/* do the update here */
if ( be->be_updatedn == NULL || strcasecmp( be->be_updatedn,
op->o_dn ) == 0 ) {
if ( (be->be_lastmod == ON || be->be_lastmod == 0 &&
global_lastmod == ON) && be->be_updatedn == NULL ) {
add_lastmods( op, &mods );
}
if ( (*be->be_modify)( be, conn, op, odn, mods )
== 0 ) {
replog( be, LDAP_REQ_MODIFY, dn, mods, 0 );
if ( be->be_update_ndn == NULL ||
strcmp( be->be_update_ndn, op->o_ndn ) == 0 )
{
if ( (*be->be_modify)( be, conn, op, ndn, modlist ) == 0 ) {
replog( be, LDAP_REQ_MODIFY, ndn, modlist, 0 );
}
/* send a referral */
} else {
send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
default_referral );
send_ldap_result( conn, op, rc = LDAP_REFERRAL,
NULL, NULL, default_referral );
}
} else {
send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
"Function not implemented" );
send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
NULL, "Function not implemented", NULL );
}
free( dn );
free( odn );
modlist_free( mods );
free( ndn );
modlist_free( modlist );
return rc;
}
static void
modlist_free(
LDAPMod *mods
LDAPModList *ml
)
{
LDAPMod *next;
LDAPModList *next;
for ( ; mods != NULL; mods = next ) {
next = mods->mod_next;
free( mods->mod_type );
if ( mods->mod_bvalues != NULL )
ber_bvecfree( mods->mod_bvalues );
free( mods );
for ( ; ml != NULL; ml = next ) {
next = ml->ml_next;
free( ml->ml_type );
if ( ml->ml_bvalues != NULL )
ber_bvecfree( ml->ml_bvalues );
free( ml );
}
}
static void
add_lastmods( Operation *op, LDAPMod **mods )
{
char buf[20];
struct berval bv;
struct berval *bvals[2];
LDAPMod **m;
LDAPMod *tmp;
struct tm *ltm;
Debug( LDAP_DEBUG_TRACE, "add_lastmods\n", 0, 0, 0 );
bvals[0] = &bv;
bvals[1] = NULL;
/* remove any attempts by the user to modify these attrs */
for ( m = mods; *m != NULL; m = &(*m)->mod_next ) {
if ( strcasecmp( (*m)->mod_type, "modifytimestamp" ) == 0
|| strcasecmp( (*m)->mod_type, "modifiersname" ) == 0 ) {
tmp = *m;
*m = (*m)->mod_next;
free( tmp->mod_type );
if ( tmp->mod_bvalues != NULL ) {
ber_bvecfree( tmp->mod_bvalues );
}
free( tmp );
}
}
if ( op->o_dn == NULL || op->o_dn[0] == '\0' ) {
bv.bv_val = "NULLDN";
bv.bv_len = strlen( bv.bv_val );
} else {
bv.bv_val = op->o_dn;
bv.bv_len = strlen( bv.bv_val );
}
tmp = (LDAPMod *) ch_calloc( 1, sizeof(LDAPMod) );
tmp->mod_type = strdup( "modifiersname" );
tmp->mod_op = LDAP_MOD_REPLACE;
tmp->mod_bvalues = (struct berval **) ch_calloc( 1,
2 * sizeof(struct berval *) );
tmp->mod_bvalues[0] = ber_bvdup( &bv );
tmp->mod_next = *mods;
*mods = tmp;
pthread_mutex_lock( &currenttime_mutex );
ltm = localtime( &currenttime );
strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm );
pthread_mutex_unlock( &currenttime_mutex );
bv.bv_val = buf;
bv.bv_len = strlen( bv.bv_val );
tmp = (LDAPMod *) ch_calloc( 1, sizeof(LDAPMod) );
tmp->mod_type = strdup( "modifytimestamp" );
tmp->mod_op = LDAP_MOD_REPLACE;
tmp->mod_bvalues = (struct berval **) ch_calloc( 1,
2 * sizeof(struct berval *) );
tmp->mod_bvalues[0] = ber_bvdup( &bv );
tmp->mod_next = *mods;
*mods = tmp;
}

View file

@ -10,52 +10,167 @@
* is provided ``as is'' without express or implied warranty.
*/
/*
* LDAP v3 newSuperior support.
*
* Copyright 1999, Juan C. Gomez, All rights reserved.
* This software is not subject to any license of Silicon Graphics
* Inc. or Purdue University.
*
* Redistribution and use in source and binary forms are permitted
* without restriction or fee of any kind as long as this notice
* is preserved.
*
*/
#include "portable.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <ac/socket.h>
#include <ac/string.h>
#include "slap.h"
extern Backend *select_backend();
extern char *default_referral;
void
int
do_modrdn(
Connection *conn,
Operation *op
)
{
char *dn, *odn, *newrdn;
int deloldrdn;
char *ndn, *newrdn;
ber_int_t deloldrdn;
Backend *be;
/* Vars for LDAP v3 newSuperior support */
char *newSuperior = NULL;
char *nnewSuperior = NULL;
Backend *newSuperior_be = NULL;
ber_len_t length;
int rc;
Debug( LDAP_DEBUG_TRACE, "do_modrdn\n", 0, 0, 0 );
if( op->o_bind_in_progress ) {
Debug( LDAP_DEBUG_ANY, "do_modrdn: SASL bind in progress.\n",
0, 0, 0 );
send_ldap_result( conn, op, LDAP_SASL_BIND_IN_PROGRESS, NULL,
"SASL bind in progress", NULL );
return LDAP_SASL_BIND_IN_PROGRESS;
}
/*
* Parse the modrdn request. It looks like this:
*
* ModifyRDNRequest := SEQUENCE {
* entry DistinguishedName,
* newrdn RelativeDistinguishedName
* deleteoldrdn BOOLEAN,
* newSuperior [0] LDAPDN OPTIONAL (v3 Only!)
* }
*/
if ( ber_scanf( op->o_ber, "{aab}", &dn, &newrdn, &deloldrdn )
if ( ber_scanf( op->o_ber, "{aab", &ndn, &newrdn, &deloldrdn )
== LBER_ERROR ) {
Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL, "" );
return;
send_ldap_disconnect( conn, op,
LDAP_PROTOCOL_ERROR, "decoding error" );
return -1;
}
/* Check for newSuperior parameter, if present scan it */
if ( ber_peek_tag( op->o_ber, &length ) == LDAP_TAG_NEWSUPERIOR ) {
if ( op->o_protocol == 0 ) {
/*
* Promote to LDAPv3
*/
ldap_pvt_thread_mutex_lock( &conn->c_mutex );
conn->c_protocol = LDAP_VERSION3;
ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
op->o_protocol = LDAP_VERSION3;
} else if ( op->o_protocol < LDAP_VERSION3 ) {
/* Conection record indicates v2 but field
* newSuperior is present: report error.
*/
Debug( LDAP_DEBUG_ANY,
"modrdn(v2): invalid field newSuperior!\n",
0, 0, 0 );
send_ldap_disconnect( conn, op,
LDAP_PROTOCOL_ERROR, "newSuperior requires LDAPv3" );
return -1;
}
if ( ber_scanf( op->o_ber, "a", &newSuperior )
== LBER_ERROR ) {
Debug( LDAP_DEBUG_ANY, "ber_scanf(\"a\"}) failed\n",
0, 0, 0 );
send_ldap_disconnect( conn, op,
LDAP_PROTOCOL_ERROR, "decoding error" );
return -1;
}
}
odn = strdup( dn );
dn_normalize( dn );
Debug( LDAP_DEBUG_ARGS,
"do_modrdn: dn (%s) newrdn (%s) deloldrdn (%d)\n", dn, newrdn,
deloldrdn );
"do_modrdn: dn (%s) newrdn (%s) newsuperior (%s)\n",
ndn, newrdn,
newSuperior != NULL ? newSuperior : "" );
if ( ber_scanf( op->o_ber, /*{*/ "}") == LBER_ERROR ) {
free( ndn );
free( newrdn );
free( newSuperior );
Debug( LDAP_DEBUG_ANY, "do_modrdn: ber_scanf failed\n", 0, 0, 0 );
send_ldap_disconnect( conn, op,
LDAP_PROTOCOL_ERROR, "decoding error" );
return -1;
}
if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) {
free( ndn );
free( newrdn );
free( newSuperior );
Debug( LDAP_DEBUG_ANY, "do_modrdn: get_ctrls failed\n", 0, 0, 0 );
return rc;
}
if( newSuperior != NULL ) {
/* GET BACKEND FOR NEW SUPERIOR */
nnewSuperior = strdup( newSuperior );
dn_normalize_case( nnewSuperior );
if ( (newSuperior_be = select_backend( nnewSuperior ))
== NULL ) {
/* We do not have a backend for newSuperior so we send
* a referral.
* XXX: We may need to do something else here, not sure
* what though.
*/
Debug( LDAP_DEBUG_ARGS,
"do_modrdn: cant find backend for=(%s)\n",
newSuperior, 0, 0 );
free( ndn );
free( newrdn );
free( newSuperior );
free( nnewSuperior );
send_ldap_result( conn, op, LDAP_REFERRAL,
NULL, NULL, default_referral );
return 0;
}
}
dn_normalize_case( ndn );
Statslog( LDAP_DEBUG_STATS, "conn=%d op=%d MODRDN dn=\"%s\"\n",
conn->c_connid, op->o_opid, dn, 0, 0 );
conn->c_connid, op->o_opid, ndn, 0, 0 );
/*
* We could be serving multiple database backends. Select the
@ -63,40 +178,70 @@ do_modrdn(
* if we don't hold it.
*/
if ( (be = select_backend( dn )) == NULL ) {
free( dn );
free( odn );
free( newrdn );
send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
default_referral );
return;
if ( (be = select_backend( ndn )) == NULL ) {
free( ndn );
free( newrdn );
free( newSuperior );
free( nnewSuperior );
send_ldap_result( conn, op, rc = LDAP_REFERRAL,
NULL, NULL, default_referral );
return rc;
}
/* Make sure that the entry being changed and the newSuperior are in
* the same backend, otherwise we return an error.
*/
if ( (newSuperior_be != NULL) && ( be != newSuperior_be) ) {
Debug( LDAP_DEBUG_ANY, "dn=(%s), newSuperior=(%s)\n", ndn,
newSuperior, 0 );
free( ndn );
free( newrdn );
free( newSuperior );
free( nnewSuperior );
send_ldap_result( conn, op, rc = LDAP_AFFECTS_MULTIPLE_DSAS,
NULL, NULL, NULL );
return rc;
}
/* alias suffix if approp */
ndn = suffixAlias( ndn, op, be );
/*
* do the add if 1 && (2 || 3)
* 1) there is an add function implemented in this backend;
* 2) this backend is master for what it holds;
* 3) it's a replica and the dn supplied is the updatedn.
* 3) it's a replica and the dn supplied is the update_ndn.
*/
if ( be->be_modrdn != NULL ) {
if ( be->be_modrdn ) {
/* do the update here */
if ( be->be_updatedn == NULL || strcasecmp( be->be_updatedn,
op->o_dn ) == 0 ) {
if ( (*be->be_modrdn)( be, conn, op, dn, newrdn,
deloldrdn ) == 0 ) {
replog( be, LDAP_REQ_MODRDN, odn, newrdn,
if ( be->be_update_ndn == NULL ||
strcmp( be->be_update_ndn, op->o_ndn ) == 0 )
{
if ( (*be->be_modrdn)( be, conn, op, ndn, newrdn,
deloldrdn, newSuperior ) == 0 ) {
/* XXX: MAY NEED TO ADD newSuperior HERE */
replog( be, LDAP_REQ_MODRDN, ndn, newrdn,
deloldrdn );
}
} else {
send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
default_referral );
send_ldap_result( conn, op, rc = LDAP_REFERRAL,
NULL, NULL, default_referral );
}
} else {
send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
"Function not implemented" );
send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
NULL, "Function not implemented", NULL );
}
free( dn );
free( odn );
free( newrdn );
free( ndn );
free( newrdn );
free( newSuperior );
free( nnewSuperior );
return rc;
}

View file

@ -10,54 +10,46 @@
* is provided ``as is'' without express or implied warranty.
*/
#include "portable.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <ac/socket.h>
#include <ac/string.h>
#include <ac/time.h>
#include "ldap_defaults.h"
#include "slap.h"
#include "ldapconfig.h"
#if defined( SLAPD_MONITOR_DN )
extern int nbackends;
extern Backend *backends;
extern int active_threads;
extern int dtblsize;
extern Connection *c;
extern long ops_initiated;
extern long ops_completed;
extern long num_entries_sent;
extern long num_bytes_sent;
extern time_t currenttime;
extern time_t starttime;
extern int num_conns;
extern char Versionstr[];
/*
* no mutex protection in here - take our chances!
*/
void
monitor_info( Connection *conn, Operation *op )
{
Entry *e;
char buf[BUFSIZ], buf2[20];
char buf[BUFSIZ];
struct berval val;
struct berval *vals[2];
int i, nconns, nwritewaiters, nreadwaiters;
int nconns, nwritewaiters, nreadwaiters;
struct tm *ltm;
char *p, *tmpdn;
char *p;
char buf2[22];
char buf3[22];
Connection *c;
int connindex;
time_t currenttime;
vals[0] = &val;
vals[1] = NULL;
e = (Entry *) ch_calloc( 1, sizeof(Entry) );
/* initialize reader/writer lock */
e->e_attrs = NULL;
e->e_dn = strdup( SLAPD_MONITOR_DN );
e->e_dn = ch_strdup( SLAPD_MONITOR_DN );
e->e_ndn = dn_normalize_case( ch_strdup(SLAPD_MONITOR_DN) );
e->e_private = NULL;
val.bv_val = Versionstr;
val.bv_val = (char *) Versionstr;
if (( p = strchr( Versionstr, '\n' )) == NULL ) {
val.bv_len = strlen( Versionstr );
} else {
@ -65,7 +57,9 @@ monitor_info( Connection *conn, Operation *op )
}
attr_merge( e, "version", vals );
ldap_pvt_thread_mutex_lock( &active_threads_mutex );
sprintf( buf, "%d", active_threads );
ldap_pvt_thread_mutex_unlock( &active_threads_mutex );
val.bv_val = buf;
val.bv_len = strlen( buf );
attr_merge( e, "threads", vals );
@ -73,82 +67,165 @@ monitor_info( Connection *conn, Operation *op )
nconns = 0;
nwritewaiters = 0;
nreadwaiters = 0;
for ( i = 0; i < dtblsize; i++ ) {
if ( c[i].c_sb.sb_sd != -1 ) {
nconns++;
if ( c[i].c_writewaiter ) {
nwritewaiters++;
}
if ( c[i].c_gettingber ) {
nreadwaiters++;
}
ltm = localtime( &c[i].c_starttime );
strftime( buf2, sizeof(buf2), "%y%m%d%H%M%SZ", ltm );
pthread_mutex_lock( &c[i].c_dnmutex );
sprintf( buf, "%d : %s : %ld : %ld : %s : %s%s", i,
buf2, c[i].c_opsinitiated, c[i].c_opscompleted,
c[i].c_dn ? c[i].c_dn : "NULLDN",
c[i].c_gettingber ? "r" : "",
c[i].c_writewaiter ? "w" : "" );
pthread_mutex_unlock( &c[i].c_dnmutex );
val.bv_val = buf;
val.bv_len = strlen( buf );
attr_merge( e, "connection", vals );
/* loop through the connections */
for ( c = connection_first( &connindex );
c != NULL;
c = connection_next( c, &connindex ))
{
nconns++;
if ( c->c_writewaiter ) {
nwritewaiters++;
}
if ( c->c_currentber != NULL ) {
nreadwaiters++;
}
ldap_pvt_thread_mutex_lock( &gmtime_mutex );
#ifndef LDAP_LOCALTIME
ltm = gmtime( &c->c_starttime );
strftime( buf2, sizeof(buf2), "%Y%m%d%H%M%SZ", ltm );
ltm = gmtime( &c->c_activitytime );
strftime( buf3, sizeof(buf2), "%Y%m%d%H%M%SZ", ltm );
#else
ltm = localtime( &c->.c_starttime );
strftime( buf2, sizeof(buf2), "%y%m%d%H%M%SZ", ltm );
ltm = localtime( &c->c_activitytime );
strftime( buf3, sizeof(buf2), "%y%m%d%H%M%SZ", ltm );
#endif
ldap_pvt_thread_mutex_unlock( &gmtime_mutex );
sprintf( buf,
"%ld : %ld "
": %ld/%ld/%ld/%ld "
": %ld/%ld/%ld "
": %s%s%s%s%s%s "
": %s : %s : %s "
": %s : %s",
c->c_connid,
(long) c->c_protocol,
c->c_n_ops_received, c->c_n_ops_executing,
c->c_n_ops_pending, c->c_n_ops_completed,
/* add low-level counters here */
c->c_n_get, c->c_n_read, c->c_n_write,
c->c_currentber ? "r" : "",
c->c_writewaiter ? "w" : "",
c->c_ops != NULL ? "x" : "",
c->c_pending_ops != NULL ? "p" : "",
connection_state2str( c->c_conn_state ),
c->c_bind_in_progress ? "S" : "",
c->c_cdn ? c->c_cdn : "<anonymous>",
c->c_client_addr ? c->c_client_addr : "unknown",
c->c_client_name ? c->c_client_name : "unknown",
buf2,
buf3
);
val.bv_val = buf;
val.bv_len = strlen( buf );
attr_merge( e, "connection", vals );
}
connection_done(c);
sprintf( buf, "%d", nconns );
val.bv_val = buf;
val.bv_len = strlen( buf );
attr_merge( e, "currentconnections", vals );
attr_merge( e, "currentConnections", vals );
sprintf( buf, "%d", num_conns );
sprintf( buf, "%ld", connections_nextid() );
val.bv_val = buf;
val.bv_len = strlen( buf );
attr_merge( e, "totalconnections", vals );
attr_merge( e, "totalConnections", vals );
sprintf( buf, "%d", dtblsize );
sprintf( buf, "%ld", (long) dtblsize );
val.bv_val = buf;
val.bv_len = strlen( buf );
attr_merge( e, "dtablesize", vals );
attr_merge( e, "dTableSize", vals );
sprintf( buf, "%d", nwritewaiters );
val.bv_val = buf;
val.bv_len = strlen( buf );
attr_merge( e, "writewaiters", vals );
attr_merge( e, "writeWaiters", vals );
sprintf( buf, "%d", nreadwaiters );
val.bv_val = buf;
val.bv_len = strlen( buf );
attr_merge( e, "readwaiters", vals );
attr_merge( e, "readWaiters", vals );
sprintf( buf, "%ld", ops_initiated );
ldap_pvt_thread_mutex_lock(&num_ops_mutex);
sprintf( buf, "%ld", num_ops_initiated );
ldap_pvt_thread_mutex_unlock(&num_ops_mutex);
val.bv_val = buf;
val.bv_len = strlen( buf );
attr_merge( e, "opsinitiated", vals );
attr_merge( e, "opsInitiated", vals );
sprintf( buf, "%ld", ops_completed );
ldap_pvt_thread_mutex_lock(&num_ops_mutex);
sprintf( buf, "%ld", num_ops_completed );
ldap_pvt_thread_mutex_unlock(&num_ops_mutex);
val.bv_val = buf;
val.bv_len = strlen( buf );
attr_merge( e, "opscompleted", vals );
attr_merge( e, "opsCompleted", vals );
ldap_pvt_thread_mutex_lock(&num_sent_mutex);
sprintf( buf, "%ld", num_entries_sent );
ldap_pvt_thread_mutex_unlock(&num_sent_mutex);
val.bv_val = buf;
val.bv_len = strlen( buf );
attr_merge( e, "entriessent", vals );
attr_merge( e, "entriesSent", vals );
ldap_pvt_thread_mutex_lock(&num_sent_mutex);
sprintf( buf, "%ld", num_refs_sent );
ldap_pvt_thread_mutex_unlock(&num_sent_mutex);
val.bv_val = buf;
val.bv_len = strlen( buf );
attr_merge( e, "referencesSent", vals );
ldap_pvt_thread_mutex_lock(&num_sent_mutex);
sprintf( buf, "%ld", num_pdu_sent );
ldap_pvt_thread_mutex_unlock(&num_sent_mutex);
val.bv_val = buf;
val.bv_len = strlen( buf );
attr_merge( e, "pduSent", vals );
ldap_pvt_thread_mutex_lock(&num_sent_mutex);
sprintf( buf, "%ld", num_bytes_sent );
ldap_pvt_thread_mutex_unlock(&num_sent_mutex);
val.bv_val = buf;
val.bv_len = strlen( buf );
attr_merge( e, "bytessent", vals );
attr_merge( e, "bytesSent", vals );
ltm = localtime( &currenttime );
strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm );
currenttime = slap_get_time();
ldap_pvt_thread_mutex_lock( &gmtime_mutex );
#ifndef LDAP_LOCALTIME
ltm = gmtime( &currenttime );
strftime( buf, sizeof(buf), "%Y%m%d%H%M%SZ", ltm );
#else
ltm = localtime( &currenttime );
strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm );
#endif
val.bv_val = buf;
val.bv_len = strlen( buf );
attr_merge( e, "currenttime", vals );
ltm = localtime( &starttime );
strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm );
#ifndef LDAP_LOCALTIME
ltm = gmtime( &starttime );
strftime( buf, sizeof(buf), "%Y%m%d%H%M%SZ", ltm );
#else
ltm = localtime( &starttime );
strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm );
#endif
ldap_pvt_thread_mutex_unlock( &gmtime_mutex );
val.bv_val = buf;
val.bv_len = strlen( buf );
attr_merge( e, "starttime", vals );
@ -158,15 +235,15 @@ monitor_info( Connection *conn, Operation *op )
val.bv_len = strlen( buf );
attr_merge( e, "nbackends", vals );
#ifdef THREAD_SUNOS5_LWP
sprintf( buf, "%d", thr_getconcurrency() );
#ifdef HAVE_THREAD_CONCURRENCY
sprintf( buf, "%d", ldap_pvt_thread_get_concurrency() );
val.bv_val = buf;
val.bv_len = strlen( buf );
attr_merge( e, "concurrency", vals );
#endif
send_search_entry( &backends[0], conn, op, e, NULL, 0 );
send_ldap_search_result( conn, op, LDAP_SUCCESS, NULL, NULL, 1 );
send_search_entry( &backends[0], conn, op, e, NULL, 0, 1 );
send_search_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL, 1 );
entry_free( e );
}

View file

@ -1,202 +1,439 @@
#ifndef _PROTO_SLAP
#define _PROTO_SLAP
#include <ldap_cdefs.h>
LDAP_BEGIN_DECL
/*
* acl.c
*/
int access_allowed( Backend *be, Connection *conn, Operation *op, Entry *e,
char *attr, struct berval *val, char *dn, int access );
struct acl * acl_get_applicable( Backend *be, Operation *op, Entry *e,
char *attr );
int acl_access_allowed( struct acl *a, Backend *be, Connection *conn, Entry *e,
struct berval *val, Operation *op, int access );
int acl_check_mods( Backend *be, Connection *conn, Operation *op, Entry *e,
LDAPMod *mods );
int access_allowed LDAP_P(( Backend *be, Connection *conn,
Operation *op, Entry *e,
char *attr, struct berval *val, int access ));
struct acl * acl_get_applicable LDAP_P(( Backend *be,
Operation *op, Entry *e,
char *attr, int nmatches, regmatch_t *matches ));
int acl_access_allowed LDAP_P(( struct acl *a, Backend *be, Connection *conn, Entry *e,
struct berval *val, Operation *op, int access, char *edn,
regmatch_t *matches ));
int acl_check_modlist LDAP_P(( Backend *be,
Connection *conn,
Operation *op,
Entry *e,
LDAPModList *ml ));
/*
* aclparse.c
*/
void parse_acl( Backend *be, char *fname, int lineno, int argc, char **argv );
char * access2str( int access );
int str2access( char *str );
void parse_acl LDAP_P(( Backend *be, char *fname, int lineno, int argc, char **argv ));
char * access2str LDAP_P(( int access ));
int str2access LDAP_P(( char *str ));
/*
* attr.c
*/
void attr_free( Attribute *a );
char * attr_normalize( char *s );
int attr_merge_fast( Entry *e, char *type, struct berval **vals, int nvals,
int naddvals, int *maxvals, Attribute ***a );
int attr_merge( Entry *e, char *type, struct berval **vals );
Attribute * attr_find( Attribute *a, char *type );
int attr_delete( Attribute **attrs, char *type );
int attr_syntax( char *type );
void attr_syntax_config( char *fname, int lineno, int argc, char **argv );
void attr_free LDAP_P(( Attribute *a ));
char * attr_normalize LDAP_P(( char *s ));
int attr_merge_fast LDAP_P(( Entry *e, char *type, struct berval **vals, int nvals,
int naddvals, int *maxvals, Attribute ***a ));
int attr_merge LDAP_P(( Entry *e, char *type, struct berval **vals ));
Attribute * attr_find LDAP_P(( Attribute *a, char *type ));
int attr_delete LDAP_P(( Attribute **attrs, char *type ));
int attr_syntax LDAP_P(( char *type ));
void attr_syntax_config LDAP_P(( char *fname, int lineno, int argc, char **argv ));
AttributeType * at_find LDAP_P(( const char *name ));
int at_find_in_list LDAP_P(( AttributeType *sat, AttributeType **list ));
int at_append_to_list LDAP_P(( AttributeType *sat, AttributeType ***listp ));
int at_delete_from_list LDAP_P(( int pos, AttributeType ***listp ));
int at_fake_if_needed LDAP_P(( char *name ));
int at_schema_info LDAP_P(( Entry *e ));
int at_add LDAP_P(( LDAP_ATTRIBUTE_TYPE *at, const char **err ));
char * at_canonical_name LDAP_P(( char * a_type ));
/*
* ava.c
*/
int get_ava( BerElement *ber, Ava *ava );
void ava_free( Ava *ava, int freeit );
int get_ava LDAP_P(( BerElement *ber, Ava *ava ));
void ava_free LDAP_P(( Ava *ava, int freeit ));
/*
* backend.c
*/
Backend * new_backend( char *type );
Backend * select_backend( char * dn );
int be_issuffix( Backend *be, char *suffix );
int be_isroot( Backend *be, char *dn );
int be_isroot_pw( Backend *be, char *dn, struct berval *cred );
void be_close();
int backend_init LDAP_P((void));
int backend_add LDAP_P((BackendInfo *aBackendInfo));
int backend_startup LDAP_P((int dbnum));
int backend_shutdown LDAP_P((int dbnum));
int backend_destroy LDAP_P((void));
BackendInfo * backend_info LDAP_P(( char *type ));
BackendDB * backend_db_init LDAP_P(( char *type ));
BackendDB * select_backend LDAP_P(( char * dn ));
int be_issuffix LDAP_P(( Backend *be, char *suffix ));
int be_isroot LDAP_P(( Backend *be, char *ndn ));
int be_isroot_pw LDAP_P(( Backend *be, char *ndn, struct berval *cred ));
char* be_root_dn LDAP_P(( Backend *be ));
int be_entry_release_rw LDAP_P(( Backend *be, Entry *e, int rw ));
#define be_entry_release_r( be, e ) be_entry_release_rw( be, e, 0 )
#define be_entry_release_w( be, e ) be_entry_release_rw( be, e, 1 )
extern int backend_unbind LDAP_P((Connection *conn, Operation *op));
extern int backend_connection_init LDAP_P((Connection *conn));
extern int backend_connection_destroy LDAP_P((Connection *conn));
extern int backend_group LDAP_P((Backend *be,
Entry *target,
char *gr_ndn, char *op_ndn,
char *objectclassValue, char *groupattrName));
/*
* ch_malloc.c
*/
char * ch_malloc( unsigned long size );
char * ch_realloc( char *block, unsigned long size );
char * ch_calloc( unsigned long nelem, unsigned long size );
void * ch_malloc LDAP_P(( ber_len_t size ));
void * ch_realloc LDAP_P(( void *block, ber_len_t size ));
void * ch_calloc LDAP_P(( ber_len_t nelem, ber_len_t size ));
char * ch_strdup LDAP_P(( const char *string ));
void ch_free LDAP_P(( void * ));
#define free ch_free
/*
* charray.c
*/
void charray_add( char ***a, char *s );
void charray_merge( char ***a, char **s );
void charray_free( char **array );
int charray_inlist( char **a, char *s );
char ** charray_dup( char **a );
char ** str2charray( char *str, char *brkstr );
void charray_add LDAP_P(( char ***a, char *s ));
void charray_merge LDAP_P(( char ***a, char **s ));
void charray_free LDAP_P(( char **array ));
int charray_inlist LDAP_P(( char **a, char *s ));
char ** charray_dup LDAP_P(( char **a ));
char ** str2charray LDAP_P(( char *str, char *brkstr ));
char * charray2str LDAP_P(( char **a ));
/*
* controls.c
*/
int get_ctrls LDAP_P((
Connection *co,
Operation *op,
int senderrors ));
/*
* config.c
*/
void read_config( char *fname, Backend **bep, FILE *pfp );
int read_config LDAP_P(( char *fname ));
/*
* connection.c
*/
int connections_init LDAP_P((void));
int connections_shutdown LDAP_P((void));
int connections_destroy LDAP_P((void));
int connections_timeout_idle LDAP_P((time_t));
void connection_activity( Connection *conn );
long connection_init LDAP_P((
ber_socket_t s,
const char* name, const char* addr));
void connection_closing LDAP_P(( Connection *c ));
int connection_state_closing LDAP_P(( Connection *c ));
char *connection_state2str LDAP_P(( int state ));
int connection_write LDAP_P((ber_socket_t s));
int connection_read LDAP_P((ber_socket_t s));
unsigned long connections_nextid(void);
Connection* connection_first LDAP_P((ber_socket_t *));
Connection* connection_next LDAP_P((Connection *, ber_socket_t *));
void connection_done LDAP_P((Connection *));
/*
* dn.c
*/
char * dn_normalize( char *dn );
char * dn_normalize_case( char *dn );
char * dn_parent( Backend *be, char *dn );
int dn_issuffix( char *dn, char *suffix );
int dn_type( char *dn );
char * dn_upcase( char *dn );
char * dn_normalize LDAP_P(( char *dn ));
char * dn_normalize_case LDAP_P(( char *dn ));
char * dn_parent LDAP_P(( Backend *be, char *dn ));
char * dn_rdn LDAP_P(( Backend *be, char *dn ));
int dn_issuffix LDAP_P(( char *dn, char *suffix ));
int dn_type LDAP_P(( char *dn ));
char * dn_upcase LDAP_P(( char *dn ));
char * rdn_attr_value LDAP_P(( char * rdn ));
char * rdn_attr_type LDAP_P(( char * rdn ));
void build_new_dn LDAP_P(( char ** new_dn, char *e_dn, char * p_dn,
char * newrdn ));
/*
* entry.c
*/
Entry * str2entry( char *s );
char * entry2str( Entry *e, int *len, int printid );
void entry_free( Entry *e );
Entry * str2entry LDAP_P(( char *s ));
char * entry2str LDAP_P(( Entry *e, int *len, int printid ));
void entry_free LDAP_P(( Entry *e ));
int entry_cmp LDAP_P(( Entry *a, Entry *b ));
int entry_dn_cmp LDAP_P(( Entry *a, Entry *b ));
int entry_id_cmp LDAP_P(( Entry *a, Entry *b ));
/*
* filter.c
*/
int get_filter( Connection *conn, BerElement *ber, Filter **filt, char **fstr );
void filter_free( Filter *f );
void filter_print( Filter *f );
int get_filter LDAP_P(( Connection *conn, BerElement *ber, Filter **filt, char **fstr ));
void filter_free LDAP_P(( Filter *f ));
void filter_print LDAP_P(( Filter *f ));
/*
* filterentry.c
*/
int test_filter( Backend *be, Connection *conn, Operation *op, Entry *e,
Filter *f );
int test_filter LDAP_P(( Backend *be, Connection *conn, Operation *op, Entry *e,
Filter *f ));
/*
* lock.c
*/
FILE * lock_fopen( char *fname, char *type, FILE **lfp );
int lock_fclose( FILE *fp, FILE *lfp );
FILE * lock_fopen LDAP_P(( char *fname, char *type, FILE **lfp ));
int lock_fclose LDAP_P(( FILE *fp, FILE *lfp ));
/*
* module.c
*/
#ifdef SLAPD_MODULES
int load_module LDAP_P(( const char* file_name, int argc, char *argv[] ));
#endif /* SLAPD_MODULES */
/*
* monitor.c
*/
extern char *supportedExtensions[];
extern char *supportedControls[];
extern char *supportedSASLMechanisms[];
void monitor_info( Connection *conn, Operation *op );
void monitor_info LDAP_P(( Connection *conn, Operation *op ));
/*
* operation.c
*/
void op_free( Operation *op );
Operation * op_add( Operation **olist, BerElement *ber, unsigned long msgid,
unsigned long tag, char *dn, int id, int connid );
void op_delete( Operation **olist, Operation *op );
void slap_op_free LDAP_P(( Operation *op ));
Operation * slap_op_alloc LDAP_P((
BerElement *ber, ber_int_t msgid,
ber_tag_t tag, ber_int_t id ));
int slap_op_add LDAP_P(( Operation **olist, Operation *op ));
int slap_op_remove LDAP_P(( Operation **olist, Operation *op ));
Operation * slap_op_pop LDAP_P(( Operation **olist ));
/*
* phonetic.c
*/
char * first_word( char *s );
char * next_word( char *s );
char * word_dup( char *w );
char * phonetic( char *s );
char * first_word LDAP_P(( char *s ));
char * next_word LDAP_P(( char *s ));
char * word_dup LDAP_P(( char *w ));
char * phonetic LDAP_P(( char *s ));
/*
* repl.c
*/
void replog( Backend *be, int optype, char *dn, void *change, int flag );
void replog LDAP_P(( Backend *be, int optype, char *dn, void *change, int flag ));
/*
* result.c
*/
void send_ldap_result( Connection *conn, Operation *op, int err, char *matched,
char *text );
void send_ldap_search_result( Connection *conn, Operation *op, int err,
char *matched, char *text, int nentries );
void close_connection( Connection *conn, int opconnid, int opid );
void send_ldap_result LDAP_P((
Connection *conn, Operation *op,
int err, char *matched, char *text,
struct berval **refs ));
void send_ldap_disconnect LDAP_P((
Connection *conn, Operation *op,
int err, char *text ));
void send_search_result LDAP_P((
Connection *conn, Operation *op,
int err, char *matched, char *text,
struct berval **refs,
int nentries ));
int send_search_reference LDAP_P((
Backend *be, Connection *conn, Operation *op,
Entry *e, struct berval **refs,
struct berval ***v2refs ));
int send_search_entry LDAP_P((
Backend *be, Connection *conn, Operation *op,
Entry *e, char **attrs, int attrsonly, int opattrs ));
int str2result LDAP_P(( char *s,
int *code, char **matched, char **info ));
/*
* schema.c
*/
int oc_schema_check( Entry *e );
int oc_schema_check LDAP_P(( Entry *e ));
int oc_check_operational_attr LDAP_P(( char *type ));
int oc_check_usermod_attr LDAP_P(( char *type ));
int oc_check_no_usermod_attr LDAP_P(( char *type ));
ObjectClass *oc_find LDAP_P((const char *ocname));
int oc_add LDAP_P((LDAP_OBJECT_CLASS *oc, const char **err));
Syntax *syn_find LDAP_P((const char *synname));
int syn_add LDAP_P((LDAP_SYNTAX *syn, slap_syntax_check_func *check, const char **err));
MatchingRule *mr_find LDAP_P((const char *mrname));
int mr_add LDAP_P((LDAP_MATCHING_RULE *mr, slap_mr_normalize_func *normalize, slap_mr_compare_func *compare, const char **err));
void schema_info LDAP_P((Connection *conn, Operation *op, char **attrs, int attrsonly));
int schema_init LDAP_P((void));
/*
* schemaparse.c
*/
void parse_oc( Backend *be, char *fname, int lineno, int argc, char **argv );
void parse_oc_old LDAP_P(( Backend *be, char *fname, int lineno, int argc, char **argv ));
void parse_oc LDAP_P(( char *fname, int lineno, char *line ));
void parse_at LDAP_P(( char *fname, int lineno, char *line ));
char *scherr2str LDAP_P((int code));
/*
* str2filter.c
*/
Filter * str2filter( char *str );
Filter * str2filter LDAP_P(( char *str ));
/*
* value.c
*/
int value_add_fast( struct berval ***vals, struct berval **addvals, int nvals,
int naddvals, int *maxvals );
int value_add( struct berval ***vals, struct berval **addvals );
void value_normalize( char *s, int syntax );
int value_cmp( struct berval *v1, struct berval *v2, int syntax,
int normalize );
int value_ncmp( struct berval *v1, struct berval *v2, int syntax, int len,
int normalize );
int value_find( struct berval **vals, struct berval *v, int syntax,
int normalize );
int value_add_fast LDAP_P(( struct berval ***vals, struct berval **addvals, int nvals,
int naddvals, int *maxvals ));
int value_add LDAP_P(( struct berval ***vals, struct berval **addvals ));
void value_normalize LDAP_P(( char *s, int syntax ));
int value_cmp LDAP_P(( struct berval *v1, struct berval *v2, int syntax,
int normalize ));
int value_find LDAP_P(( struct berval **vals, struct berval *v, int syntax,
int normalize ));
/*
* suffixAlias.c
*/
char *suffixAlias LDAP_P(( char *dn, Operation *op, Backend *be ));
/*
* user.c
*/
#if defined(HAVE_PWD_H) && defined(HAVE_GRP_H)
void slap_init_user LDAP_P(( char *username, char *groupname ));
#endif
/*
* Other...
*/
extern struct berval **default_referral;
extern char *replogfile;
extern const char Versionstr[];
extern int active_threads;
extern int defsize;
extern int deftime;
extern int g_argc;
extern int global_default_access;
extern int global_lastmod;
extern int global_idletimeout;
extern int global_schemacheck;
extern char *global_realm;
extern int lber_debug;
extern int ldap_syslog;
extern ldap_pvt_thread_mutex_t num_sent_mutex;
extern long num_bytes_sent;
extern long num_pdu_sent;
extern long num_entries_sent;
extern long num_refs_sent;
extern ldap_pvt_thread_mutex_t num_ops_mutex;
extern long num_ops_completed;
extern long num_ops_initiated;
extern char *slapd_pid_file;
extern char *slapd_args_file;
extern char **g_argv;
extern time_t starttime;
time_t slap_get_time LDAP_P((void));
extern ldap_pvt_thread_mutex_t active_threads_mutex;
extern ldap_pvt_thread_cond_t active_threads_cond;
extern ldap_pvt_thread_mutex_t entry2str_mutex;
extern ldap_pvt_thread_mutex_t replog_mutex;
#ifdef SLAPD_CRYPT
extern ldap_pvt_thread_mutex_t crypt_mutex;
#endif
extern ldap_pvt_thread_mutex_t gmtime_mutex;
extern struct acl *global_acl;
int slap_init LDAP_P((int mode, char* name));
int slap_startup LDAP_P((int dbnum));
int slap_shutdown LDAP_P((int dbnum));
int slap_destroy LDAP_P((void));
struct sockaddr_in;
struct slapd_args {
struct sockaddr_in *addr;
int tcps;
};
extern int slapd_daemon LDAP_P((struct slapd_args *args));
extern int set_socket LDAP_P((struct sockaddr_in *addr));
extern void slapd_set_write LDAP_P((ber_socket_t s, int wake));
extern void slapd_clr_write LDAP_P((ber_socket_t s, int wake));
extern void slapd_set_read LDAP_P((ber_socket_t s, int wake));
extern void slapd_clr_read LDAP_P((ber_socket_t s, int wake));
extern void slapd_remove LDAP_P((ber_socket_t s, int wake));
extern void slap_set_shutdown LDAP_P((int sig));
extern void slap_do_nothing LDAP_P((int sig));
extern void config_info LDAP_P((Connection *conn, Operation *op));
extern void root_dse_info LDAP_P((Connection *conn, Operation *op, char **attrs, int attrsonly));
extern int do_abandon LDAP_P((Connection *conn, Operation *op));
extern int do_add LDAP_P((Connection *conn, Operation *op));
extern int do_bind LDAP_P((Connection *conn, Operation *op));
extern int do_compare LDAP_P((Connection *conn, Operation *op));
extern int do_delete LDAP_P((Connection *conn, Operation *op));
extern int do_modify LDAP_P((Connection *conn, Operation *op));
extern int do_modrdn LDAP_P((Connection *conn, Operation *op));
extern int do_search LDAP_P((Connection *conn, Operation *op));
extern int do_unbind LDAP_P((Connection *conn, Operation *op));
extern int do_extended LDAP_P((Connection *conn, Operation *op));
extern ber_socket_t dtblsize;
LDAP_END_DECL
#endif /* _proto_slap */

View file

@ -1,105 +1,95 @@
/* result.c - routines to send ldap results, errors, and referrals */
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <signal.h>
#include "portable.h"
#include <stdio.h>
#include <ac/socket.h>
#include <ac/errno.h>
#include <ac/signal.h>
#include <ac/string.h>
#include <ac/time.h>
#include <ac/unistd.h>
#include "slap.h"
#ifndef SYSERRLIST_IN_STDIO
extern int sys_nerr;
extern char *sys_errlist[];
#endif
extern int active_threads;
extern pthread_mutex_t active_threads_mutex;
extern pthread_mutex_t new_conn_mutex;
extern pthread_t listener_tid;
extern struct acl *acl_get_applicable();
extern long num_entries_sent;
extern long num_bytes_sent;
extern pthread_mutex_t num_sent_mutex;
/* we need LBER internals */
#include "../../libraries/liblber/lber-int.h"
void close_connection();
static void
send_ldap_result2(
Connection *conn,
Operation *op,
int err,
char *matched,
char *text,
int nentries
)
static char *v2ref( struct berval **ref )
{
BerElement *ber;
int rc, sd;
unsigned long tag, bytes;
size_t len, i;
char *v2;
Debug( LDAP_DEBUG_TRACE, "send_ldap_result %d:%s:%s\n", err, matched ?
matched : "", text ? text : "" );
if(ref == NULL) return NULL;
switch ( op->o_tag ) {
case LBER_DEFAULT:
tag = LBER_SEQUENCE;
break;
len = sizeof("Referral:");
v2 = ch_strdup("Referral:");
case LDAP_REQ_SEARCH:
tag = LDAP_RES_SEARCH_RESULT;
for( i=0; ref[i] != NULL; i++ ) {
v2 = ch_realloc( v2, len + ref[i]->bv_len + 1 );
v2[len-1] = '\n';
memcpy(&v2[len], ref[i]->bv_val, ref[i]->bv_len );
len += ref[i]->bv_len;
}
v2[len-1] = '\0';
return v2;
}
static ber_tag_t req2res( ber_tag_t tag )
{
switch( tag ) {
case LDAP_REQ_ADD:
case LDAP_REQ_BIND:
case LDAP_REQ_COMPARE:
case LDAP_REQ_EXTENDED:
case LDAP_REQ_MODIFY:
case LDAP_REQ_MODRDN:
tag++;
break;
case LDAP_REQ_DELETE:
tag = LDAP_RES_DELETE;
break;
default:
tag = op->o_tag + 1;
case LDAP_REQ_ABANDON:
case LDAP_REQ_UNBIND:
tag = LBER_SEQUENCE;
break;
}
return tag;
}
#ifdef COMPAT30
if ( (ber = ber_alloc_t( conn->c_version == 30 ? 0 : LBER_USE_DER ))
== NULLBER ) {
#else
if ( (ber = der_alloc()) == NULLBER ) {
#endif
Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
return;
}
#ifdef CLDAP
if ( op->o_cldap ) {
rc = ber_printf( ber, "{is{t{ess}}}", op->o_msgid, "", tag,
err, matched ? matched : "", text ? text : "" );
} else
#endif
#ifdef COMPAT30
if ( conn->c_version == 30 ) {
rc = ber_printf( ber, "{it{{ess}}}", op->o_msgid, tag, err,
matched ? matched : "", text ? text : "" );
} else
#endif
rc = ber_printf( ber, "{it{ess}}", op->o_msgid, tag, err,
matched ? matched : "", text ? text : "" );
if ( rc == -1 ) {
Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
return;
}
long send_ldap_ber(
Connection *conn,
BerElement *ber )
{
ber_len_t bytes = ber_pvt_ber_bytes( ber );
/* write only one pdu at a time - wait til it's our turn */
pthread_mutex_lock( &conn->c_pdumutex );
ldap_pvt_thread_mutex_lock( &conn->c_write_mutex );
/* lock the connection */
ldap_pvt_thread_mutex_lock( &conn->c_mutex );
/* write the pdu */
bytes = ber->ber_ptr - ber->ber_buf;
pthread_mutex_lock( &new_conn_mutex );
while ( conn->c_connid == op->o_connid && ber_flush( &conn->c_sb, ber,
1 ) != 0 ) {
pthread_mutex_unlock( &new_conn_mutex );
while( 1 ) {
int err;
if ( connection_state_closing( conn ) ) {
ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
return 0;
}
if ( ber_flush( conn->c_sb, ber, 1 ) == 0 ) {
break;
}
err = errno;
/*
* we got an error. if it's ewouldblock, we need to
* wait on the socket being writable. otherwise, figure
@ -107,77 +97,281 @@ send_ldap_result2(
*/
Debug( LDAP_DEBUG_CONNS, "ber_flush failed errno %d msg (%s)\n",
errno, errno > -1 && errno < sys_nerr ? sys_errlist[errno]
err, err > -1 && err < sys_nerr ? sys_errlist[err]
: "unknown", 0 );
if ( errno != EWOULDBLOCK && errno != EAGAIN ) {
close_connection( conn, op->o_connid, op->o_opid );
if ( err != EWOULDBLOCK && err != EAGAIN ) {
connection_closing( conn );
pthread_mutex_unlock( &conn->c_pdumutex );
return;
ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
return( -1 );
}
/* wait for socket to be write-ready */
pthread_mutex_lock( &active_threads_mutex );
active_threads--;
conn->c_writewaiter = 1;
pthread_kill( listener_tid, SIGUSR1 );
pthread_cond_wait( &conn->c_wcv, &active_threads_mutex );
pthread_mutex_unlock( &active_threads_mutex );
slapd_set_write( ber_pvt_sb_get_desc( conn->c_sb ), 1 );
pthread_yield();
pthread_mutex_lock( &new_conn_mutex );
ldap_pvt_thread_cond_wait( &conn->c_write_cv, &conn->c_mutex );
conn->c_writewaiter = 0;
}
pthread_mutex_unlock( &new_conn_mutex );
pthread_mutex_unlock( &conn->c_pdumutex );
pthread_mutex_lock( &num_sent_mutex );
ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
Debug( LDAP_DEBUG_TRACE, "<= send_ldap_ber\n", 0, 0, 0 );
return bytes;
}
static void
send_ldap_response(
Connection *conn,
Operation *op,
ber_tag_t tag,
ber_int_t msgid,
ber_int_t err,
char *matched,
char *text,
struct berval **ref,
char *resoid,
struct berval *resdata
)
{
BerElement *ber;
int rc;
long bytes;
ber = ber_alloc_t( LBER_USE_DER );
if ( ber == NULL ) {
Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
return;
}
#ifdef LDAP_CONNECTIONLESS
if ( op->o_cldap ) {
rc = ber_printf( ber, "{is{t{ess}}}", msgid, "", tag,
err, matched ? matched : "", text ? text : "" );
} else
#endif
{
rc = ber_printf( ber, "{it{ess",
msgid, tag, err,
matched == NULL ? "" : matched,
text == NULL ? "" : text );
if( rc != -1 && ref != NULL ) {
rc = ber_printf( ber, "{v}", ref );
}
if( rc != -1 && resoid != NULL ) {
rc = ber_printf( ber, "s", resoid );
}
if( rc != -1 && resdata != NULL ) {
rc = ber_printf( ber, "O", resdata );
}
if( rc != -1 ) {
rc = ber_printf( ber, "}}" );
}
}
if ( rc == -1 ) {
Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
return;
}
/* send BER */
bytes = send_ldap_ber( conn, ber );
if ( bytes < 0 ) {
Debug( LDAP_DEBUG_ANY,
"send_ldap_response: ber write failed\n",
0, 0, 0 );
return;
}
ldap_pvt_thread_mutex_lock( &num_sent_mutex );
num_bytes_sent += bytes;
pthread_mutex_unlock( &num_sent_mutex );
num_pdu_sent++;
ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
return;
}
void
send_ldap_disconnect(
Connection *conn,
Operation *op,
ber_int_t err,
char *text
)
{
ber_tag_t tag;
ber_int_t msgid;
char *reqoid;
#define LDAP_UNSOLICITED_ERROR(e) \
( (e) == LDAP_PROTOCOL_ERROR \
|| (e) == LDAP_STRONG_AUTH_REQUIRED \
|| (e) == LDAP_UNAVAILABLE )
assert( LDAP_UNSOLICITED_ERROR( err ) );
Debug( LDAP_DEBUG_TRACE,
"send_ldap_disconnect %d:%s\n",
err, text ? text : "", NULL );
if ( op->o_protocol < LDAP_VERSION3 ) {
reqoid = NULL;
tag = req2res( op->o_tag );
msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
} else {
reqoid = LDAP_NOTICE_DISCONNECT;
tag = LDAP_RES_EXTENDED;
msgid = 0;
}
#ifdef LDAP_CONNECTIONLESS
if ( op->o_cldap ) {
ber_pvt_sb_udp_set_dst( &conn->c_sb, &op->o_clientaddr );
Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n",
inet_ntoa(((struct sockaddr_in *)
&op->o_clientaddr)->sin_addr ),
((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
0 );
}
#endif
send_ldap_response( conn, op, tag, msgid,
err, NULL, text, NULL,
reqoid, NULL );
Statslog( LDAP_DEBUG_STATS,
"conn=%d op=%d RESULT err=%d tag=%d nentries=%d\n", conn->c_connid,
op->o_opid, err, tag, nentries );
return;
"conn=%ld op=%ld DISCONNECT err=%ld tag=%lu text=%s\n",
(long) conn->c_connid, (long) op->o_opid,
(long) tag, (long) err, text );
}
void
send_ldap_result(
Connection *conn,
Operation *op,
int err,
ber_int_t err,
char *matched,
char *text
char *text,
struct berval **ref
)
{
#ifdef CLDAP
ber_tag_t tag;
ber_int_t msgid;
char *tmp = NULL;
assert( !LDAP_API_ERROR( err ) );
Debug( LDAP_DEBUG_TRACE, "send_ldap_result %d:%s:%s\n",
err, matched ? matched : "", text ? text : "" );
assert( err != LDAP_PARTIAL_RESULTS );
if ( err == LDAP_REFERRAL ) {
if( ref == NULL ) {
err = LDAP_NO_SUCH_OBJECT;
} else if ( op->o_protocol < LDAP_VERSION3 ) {
err = LDAP_PARTIAL_RESULTS;
tmp = text = v2ref( ref );
ref = NULL;
}
}
#ifdef LDAP_CONNECTIONLESS
if ( op->o_cldap ) {
SAFEMEMCPY( (char *)conn->c_sb.sb_useaddr, &op->o_clientaddr,
sizeof( struct sockaddr ));
ber_pvt_sb_udp_set_dst( &conn->c_sb, &op->o_clientaddr );
Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n",
inet_ntoa(((struct sockaddr_in *)
conn->c_sb.sb_useaddr)->sin_addr ),
((struct sockaddr_in *) conn->c_sb.sb_useaddr)->sin_port,
&op->o_clientaddr)->sin_addr ),
((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
0 );
}
#endif
send_ldap_result2( conn, op, err, matched, text, 0 );
send_ldap_response( conn, op, tag, msgid,
err, matched, text, ref,
NULL, NULL );
Statslog( LDAP_DEBUG_STATS,
"conn=%ld op=%ld RESULT err=%ld tag=%lu text=%s\n",
(long) conn->c_connid, (long) op->o_opid,
(long) err, (long) tag, text );
if( tmp != NULL ) {
free(tmp);
}
}
void
send_ldap_search_result(
send_search_result(
Connection *conn,
Operation *op,
int err,
ber_int_t err,
char *matched,
char *text,
char *text,
struct berval **refs,
int nentries
)
{
send_ldap_result2( conn, op, err, matched, text, nentries );
ber_tag_t tag;
ber_int_t msgid;
char *tmp = NULL;
assert( !LDAP_API_ERROR( err ) );
Debug( LDAP_DEBUG_TRACE, "send_ldap_search_result %d:%s:%s\n",
err, matched ? matched : "", text ? text : "" );
assert( err != LDAP_PARTIAL_RESULTS );
if( op->o_protocol < LDAP_VERSION3 ) {
/* send references in search results */
if( err == LDAP_REFERRAL ) {
err = LDAP_PARTIAL_RESULTS;
tmp = text = v2ref( refs );
refs = NULL;
}
} else {
/* don't send references in search results */
if( err == LDAP_REFERRAL ) {
err = LDAP_SUCCESS;
refs = NULL;
}
}
#ifdef LDAP_CONNECTIONLESS
if ( op->o_cldap ) {
ber_pvt_sb_udp_set_dst( &conn->c_sb, &op->o_clientaddr );
Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n",
inet_ntoa(((struct sockaddr_in *)
&op->o_clientaddr)->sin_addr ),
((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
0 );
}
#endif
send_ldap_response( conn, op, tag, msgid,
err, matched, text, refs,
NULL, NULL );
Statslog( LDAP_DEBUG_STATS,
"conn=%ld op=%ld SEARCH RESULT err=%ld tag=%lu text=%s\n",
(long) conn->c_connid, (long) op->o_opid,
(long) err, (long) tag, text );
}
int
send_search_entry(
Backend *be,
@ -185,179 +379,247 @@ send_search_entry(
Operation *op,
Entry *e,
char **attrs,
int attrsonly
int attrsonly,
int opattrs
)
{
BerElement *ber;
Attribute *a;
int i, rc, bytes, sd;
int i, rc=-1, bytes;
struct acl *acl;
char *edn;
Debug( LDAP_DEBUG_TRACE, "=> send_search_entry (%s)\n", e->e_dn, 0, 0 );
if ( ! access_allowed( be, conn, op, e, "entry", NULL, op->o_dn,
ACL_READ ) ) {
#if defined( SLAPD_SCHEMA_DN )
{
/* this could be backend specific */
struct berval val;
val.bv_val = SLAPD_SCHEMA_DN;
val.bv_len = strlen( val.bv_val );
attr_merge( e, "subschemaSubentry", vals );
ldap_memfree( val.bv_val );
}
#endif
if ( ! access_allowed( be, conn, op, e,
"entry", NULL, ACL_READ ) )
{
Debug( LDAP_DEBUG_ACL, "acl: access to entry not allowed\n",
0, 0, 0 );
return( 1 );
}
#ifdef COMPAT30
if ( (ber = ber_alloc_t( conn->c_version == 30 ? 0 : LBER_USE_DER ))
== NULLBER ) {
#else
if ( (ber = der_alloc()) == NULLBER ) {
#endif
edn = e->e_ndn;
ber = ber_alloc_t( LBER_USE_DER );
if ( ber == NULL ) {
Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL,
"ber_alloc" );
return( 1 );
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
NULL, "allocating BER error", NULL );
goto error_return;
}
#ifdef COMPAT30
if ( conn->c_version == 30 ) {
rc = ber_printf( ber, "{it{{s{", op->o_msgid,
LDAP_RES_SEARCH_ENTRY, e->e_dn );
} else
#endif
rc = ber_printf( ber, "{it{s{", op->o_msgid,
LDAP_RES_SEARCH_ENTRY, e->e_dn );
rc = ber_printf( ber, "{it{s{", op->o_msgid,
LDAP_RES_SEARCH_ENTRY, e->e_dn );
if ( rc == -1 ) {
Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
ber_free( ber, 1 );
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL,
"ber_printf dn" );
return( 1 );
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
NULL, "encoding dn error", NULL );
goto error_return;
}
for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
if ( attrs != NULL && ! charray_inlist( attrs, a->a_type ) ) {
regmatch_t matches[MAXREMATCHES];
if ( attrs == NULL ) {
/* all addrs request, skip operational attributes */
if( !opattrs && oc_check_operational_attr( a->a_type )) {
continue;
}
} else {
/* specific addrs requested */
if ( !charray_inlist( attrs, a->a_type )
&& !charray_inlist( attrs, LDAP_ALL_USER_ATTRIBUTES ) )
{
continue;
}
}
acl = acl_get_applicable( be, op, e, a->a_type,
MAXREMATCHES, matches );
if ( ! acl_access_allowed( acl, be, conn, e,
NULL, op, ACL_READ, edn, matches ) )
{
continue;
}
acl = acl_get_applicable( be, op, e, a->a_type );
if ( ! acl_access_allowed( acl, be, conn, e, NULL, op,
ACL_READ ) ) {
continue;
}
if ( ber_printf( ber, "{s[", a->a_type ) == -1 ) {
if (( rc = ber_printf( ber, "{s[" /*]}*/ , a->a_type )) == -1 ) {
Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
ber_free( ber, 1 );
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
NULL, "ber_printf type" );
return( 1 );
NULL, "encoding type error", NULL );
goto error_return;
}
if ( ! attrsonly ) {
for ( i = 0; a->a_vals[i] != NULL; i++ ) {
if ( a->a_syntax & SYNTAX_DN &&
! acl_access_allowed( acl, be, conn, e,
a->a_vals[i], op, ACL_READ ) )
if ( a->a_syntax & SYNTAX_DN &&
! acl_access_allowed( acl, be, conn, e, a->a_vals[i], op,
ACL_READ, edn, matches) )
{
continue;
}
if ( ber_printf( ber, "o",
a->a_vals[i]->bv_val,
a->a_vals[i]->bv_len ) == -1 )
{
if (( rc = ber_printf( ber, "O", a->a_vals[i] )) == -1 ) {
Debug( LDAP_DEBUG_ANY,
"ber_printf failed\n", 0, 0, 0 );
ber_free( ber, 1 );
send_ldap_result( conn, op,
LDAP_OPERATIONS_ERROR, NULL,
"ber_printf value" );
return( 1 );
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
NULL, "encoding value error", NULL );
goto error_return;
}
}
}
if ( ber_printf( ber, "]}" ) == -1 ) {
if (( rc = ber_printf( ber, /*{[*/ "]}" )) == -1 ) {
Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
ber_free( ber, 1 );
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
NULL, "ber_printf type end" );
return( 1 );
NULL, "encode end error", NULL );
goto error_return;
}
}
#ifdef COMPAT30
if ( conn->c_version == 30 ) {
rc = ber_printf( ber, "}}}}" );
} else
#endif
rc = ber_printf( ber, "}}}" );
rc = ber_printf( ber, /*{{{*/ "}}}" );
if ( rc == -1 ) {
Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
ber_free( ber, 1 );
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL,
"ber_printf entry end" );
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
NULL, "encode entry end error", NULL );
return( 1 );
}
/* write only one pdu at a time - wait til it's our turn */
pthread_mutex_lock( &conn->c_pdumutex );
bytes = send_ldap_ber( conn, ber );
bytes = ber->ber_ptr - ber->ber_buf;
pthread_mutex_lock( &new_conn_mutex );
while ( conn->c_connid == op->o_connid && ber_flush( &conn->c_sb, ber,
1 ) != 0 ) {
pthread_mutex_unlock( &new_conn_mutex );
/*
* we got an error. if it's ewouldblock, we need to
* wait on the socket being writable. otherwise, figure
* it's a hard error and return.
*/
Debug( LDAP_DEBUG_CONNS, "ber_flush failed errno %d msg (%s)\n",
errno, errno > -1 && errno < sys_nerr ? sys_errlist[errno]
: "unknown", 0 );
if ( errno != EWOULDBLOCK && errno != EAGAIN ) {
close_connection( conn, op->o_connid, op->o_opid );
pthread_mutex_unlock( &conn->c_pdumutex );
return( -1 );
}
/* wait for socket to be write-ready */
pthread_mutex_lock( &active_threads_mutex );
active_threads--;
conn->c_writewaiter = 1;
pthread_kill( listener_tid, SIGUSR1 );
pthread_cond_wait( &conn->c_wcv, &active_threads_mutex );
pthread_mutex_unlock( &active_threads_mutex );
pthread_yield();
pthread_mutex_lock( &new_conn_mutex );
if ( bytes < 0 ) {
Debug( LDAP_DEBUG_ANY,
"send_ldap_response: ber write failed\n",
0, 0, 0 );
return -1;
}
pthread_mutex_unlock( &new_conn_mutex );
pthread_mutex_unlock( &conn->c_pdumutex );
pthread_mutex_lock( &num_sent_mutex );
ldap_pvt_thread_mutex_lock( &num_sent_mutex );
num_bytes_sent += bytes;
num_entries_sent++;
pthread_mutex_unlock( &num_sent_mutex );
num_pdu_sent++;
ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
pthread_mutex_lock( &new_conn_mutex );
if ( conn->c_connid == op->o_connid ) {
rc = 0;
Statslog( LDAP_DEBUG_STATS2, "conn=%d op=%d ENTRY dn=\"%s\"\n",
conn->c_connid, op->o_opid, e->e_dn, 0, 0 );
} else {
rc = -1;
}
pthread_mutex_unlock( &new_conn_mutex );
Statslog( LDAP_DEBUG_STATS2, "conn=%ld op=%ld ENTRY dn=\"%s\"\n",
(long) conn->c_connid, (long) op->o_opid, e->e_dn, 0, 0 );
Debug( LDAP_DEBUG_TRACE, "<= send_search_entry\n", 0, 0, 0 );
rc = 0;
error_return:;
return( rc );
}
int
send_search_reference(
Backend *be,
Connection *conn,
Operation *op,
Entry *e,
struct berval **refs,
struct berval ***v2refs
)
{
BerElement *ber;
int rc;
int bytes;
Debug( LDAP_DEBUG_TRACE, "=> send_search_entry (%s)\n", e->e_dn, 0, 0 );
if ( ! access_allowed( be, conn, op, e,
"entry", NULL, ACL_READ ) )
{
Debug( LDAP_DEBUG_ACL,
"send_search_reference: access to entry not allowed\n",
0, 0, 0 );
return( 1 );
}
if ( ! access_allowed( be, conn, op, e,
"ref", NULL, ACL_READ ) )
{
Debug( LDAP_DEBUG_ACL,
"send_search_reference: access to reference not allowed\n",
0, 0, 0 );
return( 1 );
}
if( refs == NULL ) {
Debug( LDAP_DEBUG_ANY,
"send_search_reference: null ref in (%s)\n",
e->e_dn, 0, 0 );
return( 1 );
}
if( op->o_protocol < LDAP_VERSION3 ) {
/* save the references for the result */
if( *refs == NULL ) {
value_add( v2refs, refs );
}
return 0;
}
ber = ber_alloc_t( LBER_USE_DER );
if ( ber == NULL ) {
Debug( LDAP_DEBUG_ANY,
"send_search_reference: ber_alloc failed\n", 0, 0, 0 );
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
NULL, "alloc BER error", NULL );
return -1;
}
rc = ber_printf( ber, "{it{V}}", op->o_msgid,
LDAP_RES_SEARCH_REFERENCE, refs );
if ( rc == -1 ) {
Debug( LDAP_DEBUG_ANY,
"send_search_reference: ber_printf failed\n", 0, 0, 0 );
ber_free( ber, 1 );
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
NULL, "encode dn error", NULL );
return -1;
}
bytes = send_ldap_ber( conn, ber );
ldap_pvt_thread_mutex_lock( &num_sent_mutex );
num_bytes_sent += bytes;
num_refs_sent++;
num_pdu_sent++;
ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
Statslog( LDAP_DEBUG_STATS2, "conn=%ld op=%ld ENTRY dn=\"%s\"\n",
(long) conn->c_connid, (long) op->o_opid, e->e_dn, 0, 0 );
Debug( LDAP_DEBUG_TRACE, "<= send_search_entry\n", 0, 0, 0 );
return 0;
}
int
str2result(
char *s,
@ -411,24 +673,3 @@ str2result(
return( rc );
}
/*
* close_connection - close a connection. takes the connection to close,
* the connid associated with the operation generating the close (so we
* don't accidentally close a connection that's not ours), and the opid
* of the operation generating the close (for logging purposes).
*/
void
close_connection( Connection *conn, int opconnid, int opid )
{
pthread_mutex_lock( &new_conn_mutex );
if ( conn->c_sb.sb_sd != -1 && conn->c_connid == opconnid ) {
Statslog( LDAP_DEBUG_STATS,
"conn=%d op=%d fd=%d closed errno=%d\n", conn->c_connid,
opid, conn->c_sb.sb_sd, errno, 0 );
close( conn->c_sb.sb_sd );
conn->c_sb.sb_sd = -1;
conn->c_version = 0;
}
pthread_mutex_unlock( &new_conn_mutex );
}

105
servers/slapd/root_dse.c Normal file
View file

@ -0,0 +1,105 @@
/* root_dse.c - Provides the ROOT DSA-Specific Entry
*
* Copyright 1999 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted only
* as authorized by the OpenLDAP Public License. A copy of this
* license is available at http://www.OpenLDAP.org/license.html or
* in file LICENSE in the top-level directory of the distribution.
*/
#include "portable.h"
#include <stdio.h>
#include "ldap_defaults.h"
#include "slap.h"
void
root_dse_info( Connection *conn, Operation *op, char **attrs, int attrsonly )
{
char buf[BUFSIZ];
Entry *e;
struct berval val;
struct berval *vals[2];
int i, j;
vals[0] = &val;
vals[1] = NULL;
e = (Entry *) ch_calloc( 1, sizeof(Entry) );
e->e_attrs = NULL;
e->e_dn = ch_strdup( LDAP_ROOT_DSE );
e->e_ndn = dn_normalize_case( ch_strdup( LDAP_ROOT_DSE ));
e->e_private = NULL;
for ( i = 0; i < nbackends; i++ ) {
for ( j = 0; backends[i].be_suffix[j] != NULL; j++ ) {
val.bv_val = backends[i].be_suffix[j];
val.bv_len = strlen( val.bv_val );
attr_merge( e, "namingContexts", vals );
}
}
#if defined( SLAPD_MONITOR_DN )
val.bv_val = SLAPD_MONITOR_DN;
val.bv_len = strlen( val.bv_val );
attr_merge( e, "namingContexts", vals );
/* subschemasubentry is added by send_search_entry() */
#endif
#if defined( SLAPD_CONFIG_DN )
val.bv_val = SLAPD_CONFIG_DN;
val.bv_len = strlen( val.bv_val );
attr_merge( e, "namingContexts", vals );
#endif
#if defined( SLAPD_SCHEMA_DN )
val.bv_val = SLAPD_SCHEMA_DN;
val.bv_len = strlen( val.bv_val );
attr_merge( e, "namingContexts", vals );
#endif
/* altServer unsupported */
/* supportedControl */
for ( i=0; supportedControls[i] != NULL; i++ ) {
val.bv_val = supportedControls[i];
val.bv_len = strlen( val.bv_val );
attr_merge( e, "supportedControl", vals );
}
/* supportedExtension */
for ( i=0; supportedExtensions[i] != NULL; i++ ) {
val.bv_val = supportedExtensions[i];
val.bv_len = strlen( val.bv_val );
attr_merge( e, "supportedExtension", vals );
}
/* supportedLDAPVersion */
for ( i=LDAP_VERSION_MIN; i<=LDAP_VERSION_MAX; i++ ) {
sprintf(buf,"%d",i);
val.bv_val = buf;
val.bv_len = strlen( val.bv_val );
attr_merge( e, "supportedLDAPVersion", vals );
}
/* supportedSASLMechanism */
for ( i=0; supportedSASLMechanisms[i] != NULL; i++ ) {
val.bv_val = supportedSASLMechanisms[i];
val.bv_len = strlen( val.bv_val );
attr_merge( e, "supportedSASLMechanism", vals );
}
if ( default_referral != NULL ) {
attr_merge( e, "ref", default_referral );
}
send_search_entry( &backends[0], conn, op, e, attrs, attrsonly, 1 );
send_search_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL, 1 );
entry_free( e );
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,445 @@
# OpenLDAP Core schema
# Includes "standard" schema items from RFC2251-RFC2256
# Standard X.501(93) Operational Attribute Types from RFC2252
attribute ( 2.5.18.1 NAME 'createTimestamp' EQUALITY generalizedTimeMatch
ORDERING generalizedTimeOrderingMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )
attribute ( 2.5.18.2 NAME 'modifyTimestamp' EQUALITY generalizedTimeMatch
ORDERING generalizedTimeOrderingMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )
attribute ( 2.5.18.3 NAME 'creatorsName' EQUALITY distinguishedNameMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )
attribute ( 2.5.18.4 NAME 'modifiersName' EQUALITY distinguishedNameMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )
attribute ( 2.5.18.10 NAME 'subschemaSubentry'
EQUALITY distinguishedNameMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 NO-USER-MODIFICATION
SINGLE-VALUE USAGE directoryOperation )
attribute ( 2.5.21.5 NAME 'attributeTypes'
EQUALITY objectIdentifierFirstComponentMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.3 USAGE directoryOperation )
attribute ( 2.5.21.6 NAME 'objectClasses'
EQUALITY objectIdentifierFirstComponentMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.37 USAGE directoryOperation )
attribute ( 2.5.21.4 NAME 'matchingRules'
EQUALITY objectIdentifierFirstComponentMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.30 USAGE directoryOperation )
attribute ( 2.5.21.8 NAME 'matchingRuleUse'
EQUALITY objectIdentifierFirstComponentMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.31 USAGE directoryOperation )
# LDAP Operational Attributes from RFC2252
attribute ( 1.3.6.1.4.1.1466.101.120.5 NAME 'namingContexts'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 USAGE dSAOperation )
attribute ( 1.3.6.1.4.1.1466.101.120.6 NAME 'altServer'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 USAGE dSAOperation )
attribute ( 1.3.6.1.4.1.1466.101.120.7 NAME 'supportedExtension'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 USAGE dSAOperation )
attribute ( 1.3.6.1.4.1.1466.101.120.13 NAME 'supportedControl'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 USAGE dSAOperation )
attribute ( 1.3.6.1.4.1.1466.101.120.14 NAME 'supportedSASLMechanisms'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE dSAOperation )
attribute ( 1.3.6.1.4.1.1466.101.120.15 NAME 'supportedLDAPVersion'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 USAGE dSAOperation )
# LDAP Subschema Atrribute from RFC2252
attribute ( 1.3.6.1.4.1.1466.101.120.16 NAME 'ldapSyntaxes'
EQUALITY objectIdentifierFirstComponentMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.54 USAGE directoryOperation )
# X.500 Subschema attributes from RFC2252
attribute ( 2.5.21.1 NAME 'dITStructureRules' EQUALITY integerFirstComponentMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.17 USAGE directoryOperation )
attribute ( 2.5.21.7 NAME 'nameForms'
EQUALITY objectIdentifierFirstComponentMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.35 USAGE directoryOperation )
attribute ( 2.5.21.2 NAME 'dITContentRules'
EQUALITY objectIdentifierFirstComponentMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.16 USAGE directoryOperation )
# Object Classes from RFC2252
# extensibleObject moved forward, since it depends on top
# ldapSyntaxes (operational) is admissible in next:
objectclass ( 2.5.20.1 NAME 'subschema' AUXILIARY
MAY ( dITStructureRules $ nameForms $ ditContentRules $
objectClasses $ attributeTypes $ matchingRules $
matchingRuleUse ) )
# Standard attribute types from RFC2256
attribute ( 2.5.4.0 NAME 'objectClass' EQUALITY objectIdentifierMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )
attribute ( 2.5.4.1 NAME 'aliasedObjectName' EQUALITY distinguishedNameMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE )
# Defined, but no longer used
attribute ( 2.5.4.2 NAME 'knowledgeInformation' EQUALITY caseIgnoreMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )
# Place here since other attribute types derive from it
attribute ( 2.5.4.41 NAME 'name' EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )
attribute ( 2.5.4.3 NAME ( 'cn' 'commonName' ) SUP name )
attribute ( 2.5.4.4 NAME ( 'sn' 'surname' ) SUP name )
attribute ( 2.5.4.5 NAME 'serialNumber' EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.44{64} )
# (2-letter code from ISO 3166)
attribute ( 2.5.4.6 NAME ( 'c' 'countryName' ) SUP name SINGLE-VALUE )
attribute ( 2.5.4.7 NAME ( 'l' 'localityName' ) SUP name )
attribute ( 2.5.4.8 NAME ( 'st' 'stateOrProvinceName' ) SUP name )
attribute ( 2.5.4.9 NAME ( 'street' 'streetAddress' ) EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
attribute ( 2.5.4.10 NAME ( 'o' 'organizationName' ) SUP name )
attribute ( 2.5.4.11 NAME ( 'ou' 'organizationalUnitName' ) SUP name )
attribute ( 2.5.4.12 NAME 'title' SUP name )
attribute ( 2.5.4.13 NAME 'description' EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} )
# Obsoleted by enhancedSearchGuide
attribute ( 2.5.4.14 NAME 'searchGuide'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.25 )
attribute ( 2.5.4.15 NAME 'businessCategory' EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
# Show stopper: we don't have the definition of caseIgnoreListSubstringsMatch
#attribute ( 2.5.4.16 NAME 'postalAddress' EQUALITY caseIgnoreListMatch
# SUBSTR caseIgnoreListSubstringsMatch
# SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )
attribute ( 2.5.4.16 NAME 'postalAddress' EQUALITY caseIgnoreListMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )
attribute ( 2.5.4.17 NAME 'postalCode' EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{40} )
attribute ( 2.5.4.18 NAME 'postOfficeBox' EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{40} )
attribute ( 2.5.4.19 NAME 'physicalDeliveryOfficeName' EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
attribute ( 2.5.4.20 NAME 'telephoneNumber' EQUALITY telephoneNumberMatch
SUBSTR telephoneNumberSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.50{32} )
attribute ( 2.5.4.21 NAME 'telexNumber'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.52 )
attribute ( 2.5.4.22 NAME 'teletexTerminalIdentifier'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.51 )
attribute ( 2.5.4.23 NAME ( 'facsimileTelephoneNumber' 'fax' )
SYNTAX 1.3.6.1.4.1.1466.115.121.1.22 )
attribute ( 2.5.4.24 NAME 'x121Address' EQUALITY numericStringMatch
SUBSTR numericStringSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.36{15} )
attribute ( 2.5.4.25 NAME 'internationaliSDNNumber' EQUALITY numericStringMatch
SUBSTR numericStringSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.36{16} )
attribute ( 2.5.4.26 NAME 'registeredAddress' SUP postalAddress
SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )
attribute ( 2.5.4.27 NAME 'destinationIndicator' EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.44{128} )
attribute ( 2.5.4.28 NAME 'preferredDeliveryMethod'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.14
SINGLE-VALUE )
attribute ( 2.5.4.29 NAME 'presentationAddress'
EQUALITY presentationAddressMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.43
SINGLE-VALUE )
attribute ( 2.5.4.30 NAME 'supportedApplicationContext'
EQUALITY objectIdentifierMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )
# Placed here because others derive from it
# We had a dn definition in slapd.at.conf and Netscape lists both
# names for that OID
attribute ( 2.5.4.49 NAME ( 'distinguishedName' 'dn' )
EQUALITY distinguishedNameMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )
attribute ( 2.5.4.31 NAME 'member' SUP distinguishedName )
attribute ( 2.5.4.32 NAME 'owner' SUP distinguishedName )
attribute ( 2.5.4.33 NAME 'roleOccupant' SUP distinguishedName )
attribute ( 2.5.4.34 NAME 'seeAlso' SUP distinguishedName )
attribute ( 2.5.4.35 NAME 'userPassword' EQUALITY octetStringMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{128} )
# Must be stored and requested in the binary form, as
# userCertificate;binary
attribute ( 2.5.4.36 NAME 'userCertificate'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 )
# As above
attribute ( 2.5.4.37 NAME 'cACertificate'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 )
# As above
attribute ( 2.5.4.38 NAME 'authorityRevocationList'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.9 )
# As above
attribute ( 2.5.4.39 NAME 'certificateRevocationList'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.9 )
# As above
attribute ( 2.5.4.40 NAME 'crossCertificatePair'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.10 )
# 2.5.4.41 is 'name', moved above since other attribute types derive from it
attribute ( 2.5.4.42 NAME 'givenName' SUP name )
attribute ( 2.5.4.43 NAME 'initials' SUP name )
attribute ( 2.5.4.45 NAME 'x500UniqueIdentifier' EQUALITY bitStringMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )
attribute ( 2.5.4.46 NAME 'dnQualifier' EQUALITY caseIgnoreMatch
ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 )
attribute ( 2.5.4.47 NAME 'enhancedSearchGuide'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.21 )
attribute ( 2.5.4.48 NAME 'protocolInformation'
EQUALITY protocolInformationMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )
# 2.5.4.49 is distinguishedName, moved up
attribute ( 2.5.4.50 NAME 'uniqueMember' EQUALITY uniqueMemberMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )
attribute ( 2.5.4.51 NAME 'houseIdentifier' EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )
# This attribute is to be stored and requested in the binary form, as
# 'supportedAlgorithms;binary'.
attribute ( 2.5.4.52 NAME 'supportedAlgorithms'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.49 )
# This attribute is to be stored and requested in the binary form, as
# 'deltaRevocationList;binary'.
attribute ( 2.5.4.53 NAME 'deltaRevocationList'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.9 )
attribute ( 2.5.4.54 NAME 'dmdName' SUP name )
# Standard object classes from RFC2256
objectclass ( 2.5.6.0 NAME 'top' ABSTRACT MUST objectClass )
objectclass ( 2.5.6.1 NAME 'alias' SUP top STRUCTURAL MUST aliasedObjectName )
objectclass ( 2.5.6.2 NAME 'country' SUP top STRUCTURAL MUST c
MAY ( searchGuide $ description ) )
objectclass ( 2.5.6.3 NAME 'locality' SUP top STRUCTURAL
MAY ( street $ seeAlso $ searchGuide $ st $ l $ description ) )
objectclass ( 2.5.6.4 NAME 'organization' SUP top STRUCTURAL MUST o
MAY ( userPassword $ searchGuide $ seeAlso $ businessCategory $
x121Address $ registeredAddress $ destinationIndicator $
preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
telephoneNumber $ internationaliSDNNumber $
facsimileTelephoneNumber $
street $ postOfficeBox $ postalCode $ postalAddress $
physicalDeliveryOfficeName $ st $ l $ description ) )
objectclass ( 2.5.6.5 NAME 'organizationalUnit' SUP top STRUCTURAL MUST ou
MAY ( userPassword $ searchGuide $ seeAlso $ businessCategory $
x121Address $ registeredAddress $ destinationIndicator $
preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
telephoneNumber $ internationaliSDNNumber $
facsimileTelephoneNumber $
street $ postOfficeBox $ postalCode $ postalAddress $
physicalDeliveryOfficeName $ st $ l $ description ) )
objectclass ( 2.5.6.6 NAME 'person' SUP top STRUCTURAL MUST ( sn $ cn )
MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) )
objectclass ( 2.5.6.7 NAME 'organizationalPerson' SUP person STRUCTURAL
MAY ( title $ x121Address $ registeredAddress $
destinationIndicator $
preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
telephoneNumber $ internationaliSDNNumber $
facsimileTelephoneNumber $
street $ postOfficeBox $ postalCode $ postalAddress $
physicalDeliveryOfficeName $ ou $ st $ l ) )
# Notice that preferredDeliveryMethod is duplicate
objectclass ( 2.5.6.8 NAME 'organizationalRole' SUP top STRUCTURAL MUST cn
MAY ( x121Address $ registeredAddress $ destinationIndicator $
preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
telephoneNumber $ internationaliSDNNumber $
facsimileTelephoneNumber $
seeAlso $ roleOccupant $ preferredDeliveryMethod $ street $
postOfficeBox $ postalCode $ postalAddress $
physicalDeliveryOfficeName $ ou $ st $ l $ description ) )
objectclass ( 2.5.6.9 NAME 'groupOfNames' SUP top STRUCTURAL MUST ( member $ cn )
MAY ( businessCategory $ seeAlso $ owner $ ou $ o $ description ) )
# Notice that preferredDeliveryMethod is duplicate
# It seems they could not agree on wheter telephoneNumber is MAY
# in person. Probably it wasn't originally at was added as an
# afterthought
objectclass ( 2.5.6.10 NAME 'residentialPerson' SUP person STRUCTURAL MUST l
MAY ( businessCategory $ x121Address $ registeredAddress $
destinationIndicator $ preferredDeliveryMethod $ telexNumber $
teletexTerminalIdentifier $ telephoneNumber $
internationaliSDNNumber $
facsimileTelephoneNumber $ preferredDeliveryMethod $ street $
postOfficeBox $ postalCode $ postalAddress $
physicalDeliveryOfficeName $ st $ l ) )
objectclass ( 2.5.6.11 NAME 'applicationProcess' SUP top STRUCTURAL MUST cn
MAY ( seeAlso $ ou $ l $ description ) )
objectclass ( 2.5.6.12 NAME 'applicationEntity' SUP top STRUCTURAL
MUST ( presentationAddress $ cn )
MAY ( supportedApplicationContext $ seeAlso $ ou $ o $ l $
description ) )
# This one was wrong in our schema, it only allowed the aditional
# knowledgeInformation attribute, while it is derived from
# applicationEntity and should allow all its attributes as well.
objectclass ( 2.5.6.13 NAME 'dSA' SUP applicationEntity STRUCTURAL
MAY knowledgeInformation )
objectclass ( 2.5.6.14 NAME 'device' SUP top STRUCTURAL MUST cn
MAY ( serialNumber $ seeAlso $ owner $ ou $ o $ l $ description ) )
objectclass ( 2.5.6.15 NAME 'strongAuthenticationUser' SUP top AUXILIARY
MUST userCertificate )
objectclass ( 2.5.6.16 NAME 'certificationAuthority' SUP top AUXILIARY
MUST ( authorityRevocationList $ certificateRevocationList $
cACertificate ) MAY crossCertificatePair )
# New
objectclass ( 2.5.6.17 NAME 'groupOfUniqueNames' SUP top STRUCTURAL
MUST ( uniqueMember $ cn )
MAY ( businessCategory $ seeAlso $ owner $ ou $ o $ description ) )
# New
objectclass ( 2.5.6.18 NAME 'userSecurityInformation' SUP top AUXILIARY
MAY ( supportedAlgorithms ) )
# New
objectclass ( 2.5.6.16.2 NAME 'certificationAuthority-V2' SUP
certificationAuthority
AUXILIARY MAY ( deltaRevocationList ) )
# New
objectclass ( 2.5.6.19 NAME 'cRLDistributionPoint' SUP top STRUCTURAL
MUST ( cn ) MAY ( certificateRevocationList $
authorityRevocationList $
deltaRevocationList ) )
# New
objectclass ( 2.5.6.20 NAME 'dmd' SUP top STRUCTURAL MUST ( dmdName )
MAY ( userPassword $ searchGuide $ seeAlso $ businessCategory $
x121Address $ registeredAddress $ destinationIndicator $
preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
telephoneNumber $ internationaliSDNNumber $
facsimileTelephoneNumber $
street $ postOfficeBox $ postalCode $ postalAddress $
physicalDeliveryOfficeName $ st $ l $ description ) )
# Next objectclass is defined in RFC2252, but has to be put after top
objectclass ( 1.3.6.1.4.1.1466.101.120.111 NAME 'extensibleObject'
SUP top AUXILIARY )
#
# From draft-ietf-ldapext-nameref-00.txt
# used to represent referrals in the directory
#
attribute ( 2.16.840.1.113730.3.1.34 NAME 'ref' DESC 'URL Reference'
EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.1466.115.121.1.26
USAGE distributedOperation )
objectclass ( 2.16.840.1.113730.3.2.6 NAME 'referral'
SUP top STRUCTURAL MAY ( ref ) )

View file

@ -10,33 +10,42 @@
* is provided ``as is'' without express or implied warranty.
*/
#include "portable.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "ldap_defaults.h"
#include "slap.h"
#include "ldapconfig.h"
extern int get_filter();
extern Backend *select_backend();
extern char *default_referral;
void
do_search( conn, op )
Connection *conn; /* where to send results */
Operation *op; /* info about the op to which we're responding */
int
do_search(
Connection *conn, /* where to send results */
Operation *op /* info about the op to which we're responding */
)
{
int i, err;
int scope, deref, attrsonly;
int sizelimit, timelimit;
char *base, *fstr;
Filter *filter;
char **attrs;
ber_int_t scope, deref, attrsonly;
ber_int_t sizelimit, timelimit;
char *base = NULL, *fstr = NULL;
Filter *filter = NULL;
char **attrs = NULL;
Backend *be;
int rc;
Debug( LDAP_DEBUG_TRACE, "do_search\n", 0, 0, 0 );
if( op->o_bind_in_progress ) {
Debug( LDAP_DEBUG_ANY, "do_search: SASL bind in progress.\n",
0, 0, 0 );
send_ldap_result( conn, op, LDAP_SASL_BIND_IN_PROGRESS, NULL,
"SASL bind in progress", NULL );
return LDAP_SASL_BIND_IN_PROGRESS;
}
/*
* Parse the search request. It looks like this:
*
@ -62,52 +71,67 @@ do_search( conn, op )
*/
/* baseObject, scope, derefAliases, sizelimit, timelimit, attrsOnly */
if ( ber_scanf( op->o_ber, "{aiiiib", &base, &scope, &deref, &sizelimit,
if ( ber_scanf( op->o_ber, "{aiiiib",
&base, &scope, &deref, &sizelimit,
&timelimit, &attrsonly ) == LBER_ERROR ) {
send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL, "" );
return;
send_ldap_disconnect( conn, op,
LDAP_PROTOCOL_ERROR, "decoding error" );
rc = -1;
goto return_results;
}
if ( scope != LDAP_SCOPE_BASE && scope != LDAP_SCOPE_ONELEVEL
&& scope != LDAP_SCOPE_SUBTREE ) {
free( base );
send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL,
"Unknown search scope" );
return;
send_ldap_disconnect( conn, op,
LDAP_PROTOCOL_ERROR, "decoding error" );
rc = -1;
goto return_results;
}
(void) dn_normalize( base );
(void) dn_normalize_case( base );
Debug( LDAP_DEBUG_ARGS, "SRCH \"%s\" %d %d", base, scope, deref );
Debug( LDAP_DEBUG_ARGS, " %d %d %d\n", sizelimit, timelimit,
attrsonly);
/* filter - returns a "normalized" version */
filter = NULL;
fstr = NULL;
if ( (err = get_filter( conn, op->o_ber, &filter, &fstr )) != 0 ) {
if ( fstr != NULL ) {
free( fstr );
if( err == -1 ) {
send_ldap_disconnect( conn, op,
LDAP_PROTOCOL_ERROR, "decode error" );
} else {
send_ldap_result( conn, op, err,
NULL, "Bad search filter", NULL );
}
free( base );
send_ldap_result( conn, op, err, NULL, "Bad search filter" );
return;
goto return_results;
}
Debug( LDAP_DEBUG_ARGS, " filter: %s\n", fstr, 0, 0 );
/* attributes */
attrs = NULL;
if ( ber_scanf( op->o_ber, "{v}}", &attrs ) == LBER_ERROR ) {
free( base );
free( fstr );
send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, NULL, "" );
return;
if ( ber_scanf( op->o_ber, /*{*/ "{v}}", &attrs ) == LBER_ERROR ) {
send_ldap_disconnect( conn, op,
LDAP_PROTOCOL_ERROR, "decoding error" );
rc = -1;
goto return_results;
}
if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_ANY, "do_search: get_ctrls failed\n", 0, 0, 0 );
goto return_results;
}
rc = 0;
Debug( LDAP_DEBUG_ARGS, " attrs:", 0, 0, 0 );
if ( attrs != NULL ) {
for ( i = 0; attrs[i] != NULL; i++ ) {
attr_normalize( attrs[i] );
Debug( LDAP_DEBUG_ARGS, " %s", attrs[i], 0, 0 );
}
}
Debug( LDAP_DEBUG_ARGS, "\n", 0, 0, 0 );
Statslog( LDAP_DEBUG_STATS,
@ -117,63 +141,62 @@ do_search( conn, op )
#if defined( SLAPD_MONITOR_DN ) || defined( SLAPD_CONFIG_DN ) || defined( SLAPD_SCHEMA_DN )
if ( scope == LDAP_SCOPE_BASE ) {
#if defined( SLAPD_MONITOR_DN )
if ( strcasecmp( base, SLAPD_MONITOR_DN ) == 0 ) {
free( base );
free( fstr );
if ( strcmp( base, SLAPD_MONITOR_DN ) == 0 ) {
monitor_info( conn, op );
return;
goto return_results;
}
#endif
#if defined( SLAPD_CONFIG_DN )
if ( strcasecmp( base, SLAPD_CONFIG_DN ) == 0 ) {
free( base );
free( fstr );
if ( strcmp( base, SLAPD_CONFIG_DN ) == 0 ) {
config_info( conn, op );
return;
goto return_results;
}
#endif
#if defined( SLAPD_SCHEMA_DN )
if ( strcasecmp( base, SLAPD_SCHEMA_DN ) == 0 ) {
free( base );
free( fstr );
schema_info( conn, op );
return;
if ( strcmp( base, SLAPD_SCHEMA_DN ) == 0 ) {
schema_info( conn, op, attrs, attrsonly );
goto return_results;
}
#endif
}
#endif /* monitor or config or schema dn */
if ( strcmp( base, LDAP_ROOT_DSE ) == 0 && scope == LDAP_SCOPE_BASE ) {
root_dse_info( conn, op, attrs, attrsonly );
goto return_results;
}
/*
* We could be serving multiple database backends. Select the
* appropriate one, or send a referral to our "referral server"
* if we don't hold it.
*/
if ( (be = select_backend( base )) == NULL ) {
send_ldap_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
default_referral );
send_ldap_result( conn, op, rc = LDAP_REFERRAL,
NULL, NULL, default_referral );
free( base );
free( fstr );
filter_free( filter );
if ( attrs != NULL ) {
charray_free( attrs );
}
return;
goto return_results;
}
/* translate the base if it matches an aliased base part */
base = suffixAlias ( base, op, be );
/* actually do the search and send the result(s) */
if ( be->be_search != NULL ) {
if ( be->be_search ) {
(*be->be_search)( be, conn, op, base, scope, deref, sizelimit,
timelimit, filter, fstr, attrs, attrsonly );
} else {
send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
"Function not implemented" );
send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
NULL, "Function not implemented", NULL );
}
free( base );
free( fstr );
filter_free( filter );
return_results:;
if( base != NULL) free( base );
if( fstr != NULL) free( fstr );
if( filter != NULL) filter_free( filter );
if ( attrs != NULL ) {
charray_free( attrs );
}
return rc;
}

167
servers/slapd/slapd.dsw Normal file
View file

@ -0,0 +1,167 @@
Microsoft Developer Studio Workspace File, Format Version 5.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "backldbm"=".\back-ldbm\backldbm.dsp" - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "libavl"=..\..\libraries\libavl\libavl.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "liblber"=..\..\libraries\liblber\liblber.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "libldap_r"=..\..\libraries\libldap_r\libldap_r.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name liblber
End Project Dependency
}}}
###############################################################################
Project: "libldbm"=..\..\libraries\libldbm\libldbm.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "libldif"=..\..\libraries\libldif\libldif.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "liblutil"=..\..\libraries\liblutil\liblutil.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "libslapd"=.\libslapd.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "setup"=..\..\include\setup.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "slapd"=.\slapd.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name libavl
End Project Dependency
Begin Project Dependency
Project_Dep_Name liblber
End Project Dependency
Begin Project Dependency
Project_Dep_Name libldbm
End Project Dependency
Begin Project Dependency
Project_Dep_Name libldif
End Project Dependency
Begin Project Dependency
Project_Dep_Name liblutil
End Project Dependency
Begin Project Dependency
Project_Dep_Name libldap_r
End Project Dependency
Begin Project Dependency
Project_Dep_Name backldbm
End Project Dependency
Begin Project Dependency
Project_Dep_Name libslapd
End Project Dependency
Begin Project Dependency
Project_Dep_Name setup
End Project Dependency
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################

View file

@ -0,0 +1,64 @@
/*
* Mimic unused interfaces of slapd...
* needed for linking.
*/
#include "portable.h"
#include <stdio.h>
#include "../slap.h"
#ifdef WIN32
time_t starttime;
#endif
/* bogus ../results.c */
int str2result(
char* s,
int *code,
char **matched,
char **info )
{
assert(0);
return 0;
}
void
send_ldap_result(
Connection *conn,
Operation *op,
int err,
char *matched,
char *text
)
{
assert(0);
}
void
send_search_result(
Connection *conn,
Operation *op,
int err,
char *matched,
char *text,
int nentries
)
{
assert(0);
}
int
send_search_entry(
Backend *be,
Connection *conn,
Operation *op,
Entry *e,
char **attrs,
int attrsonly,
int opattrs
)
{
assert(0);
return -1;
}