Net2/usr/src/contrib/isode/quipu/find_entry.c

/* find_entry.c - */

#ifndef lint
static char *rcsid = "$Header: /f/osi/quipu/RCS/find_entry.c,v 7.4 91/03/09 11:56:56 mrose Exp $";
#endif

/*
 * $Header: /f/osi/quipu/RCS/find_entry.c,v 7.4 91/03/09 11:56:56 mrose Exp $
 *
 *
 * $Log:	find_entry.c,v $
 * Revision 7.4  91/03/09  11:56:56  mrose
 * update
 * 
 * Revision 7.3  91/02/22  09:39:22  mrose
 * Interim 6.8
 * 
 * Revision 7.2  90/10/17  11:54:19  mrose
 * sync
 * 
 * Revision 7.1  90/07/09  14:46:12  mrose
 * sync
 * 
 * Revision 7.0  89/11/23  22:17:40  mrose
 * Release 6.0
 * 
 */

/*
 *                                NOTICE
 *
 *    Acquisition, use, and distribution of this module and related
 *    materials are subject to the restrictions of a license agreement.
 *    Consult the Preface in the User's Manual for the full terms of
 *    this agreement.
 *
 */


#include "quipu/util.h"
#include "quipu/commonarg.h"
#include "quipu/entry.h"
#include "quipu/ds_error.h"
#include "quipu/connection.h"
#ifdef TURBO_AVL
#include "quipu/turbo.h"
#endif

extern Entry database_root;
extern LLog * log_dsap;
extern time_t timenow;
extern time_t cache_timeout;
extern DN  mydsadn;
extern struct di_block * di_alloc();
extern int dn_print ();

int	  find_entry (object,ca,acl_who,dn_stack,master,ent_p,err,di_p,optype)
DN		  object;
common_args	* ca;
DN		  acl_who;
struct dn_seq	* dn_stack;
int		  master;
Entry		* ent_p;
struct DSError	* err;
struct di_block	**di_p;
int optype;
{
int deref = FALSE;
extern time_t cache_timeout;
DN dn_found;
int res;

	DLOG (log_dsap,LLOG_TRACE,("find_entry"));
	err->dse_type = DSE_NOERROR;

	if ((ca->ca_servicecontrol.svc_options & SVC_OPT_DONTDEREFERENCEALIAS) == 0) 
		deref = TRUE;

	if ((ca->ca_servicecontrol.svc_options & SVC_OPT_DONTUSECOPY) != 0)
		master = TRUE;

	switch(really_find_entry(object,deref,dn_stack,master,ent_p,err,di_p))
	{
	case DS_OK:
	    DLOG(log_dsap, LLOG_DEBUG, ("find_entry - rfe: OK"));
	    /* Have set up ent_p continue processing */
	    break;

	case DS_CONTINUE:
	    DLOG(log_dsap, LLOG_DEBUG, ("find_entry - rfe: CONT"));
#ifdef DEBUG
	    di_list_log((*di_p));
#endif
	    /* Have set up di_blocks of DSAs to be questioned */
	    return(DS_CONTINUE);

	case DS_X500_ERROR:
	    DLOG(log_dsap, LLOG_DEBUG, ("find_entry - rfe: X500_ERROR"));
	    /* Have set up an error */
	    return(DS_X500_ERROR);

	default:
	    /* Scream */
	    LLOG(log_dsap, LLOG_EXCEPTIONS, ("really_find_entry failed in find_entry 1"));
	    return(DS_ERROR_LOCAL);
	}

	dn_found = get_copy_dn (*ent_p);

	/* if the returned entry is a CONSTRUCTOR, return a referral */
	if ((*ent_p)->e_data == E_TYPE_CONSTRUCTOR) {
	        DLOG(log_dsap, LLOG_DEBUG, ("find_entry - constructor"));
		res = constructor_dsa_info(dn_found,dn_stack,FALSE,(*ent_p),err,di_p);
		dn_free (dn_found);
		return (res);
	}

	/* if the returned entry is a COPY, - check service controls */
	if (((*ent_p)->e_data != E_DATA_MASTER) && (master)) {

		/* DSAs are special for read/modify */
		if ((optype == OP_READ) || 
		    (optype == OP_MODIFYRDN) ||
		    (optype == OP_MODIFYENTRY)) {
			if ((quipu_ctx_supported (*ent_p) == 2) && (quipu_version_7 (*ent_p))) {
				if (dn_cmp (dn_found, mydsadn) == 0) 
					goto out;
mk_ref:;
				(*di_p) = di_alloc();
				(*di_p)->di_type = DI_TASK;
				(*di_p)->di_dn = dn_found;
				(*di_p)->di_target = dn_cpy(dn_found);
				(*di_p)->di_reftype = RT_UNDEFINED;
				(*di_p)->di_rdn_resolved = CR_RDNRESOLVED_NOTDEFINED;
				(*di_p)->di_aliasedRDNs = CR_NOALIASEDRDNS;
				(*di_p)->di_entry = *ent_p;
				(*ent_p)->e_refcount++;
				(*di_p)->di_state = DI_COMPLETE;
				return DS_CONTINUE;
			}
		}

	        DLOG(log_dsap, LLOG_DEBUG, ("find_entry - slave master needed"));
		res = constructor_dsa_info(dn_found,dn_stack,TRUE,(*ent_p),err,di_p);
		dn_free (dn_found);
		return (res);

	} else if ( ((optype == OP_MODIFYRDN) || (optype == OP_MODIFYENTRY)) &&
		  (quipu_ctx_supported (*ent_p) == 2) && 
		   quipu_version_7 (*ent_p) &&
		  (dn_cmp (dn_found, mydsadn) != 0))
			goto mk_ref;

#ifdef WRONG_BEHAVIOUR

	/* if this is right, we need to make sure that dsa_info */
	/* pick ups the correct external reference */

	if ((*ent_p)->e_external && 
	    ((*ent_p)->e_reftype != RT_NONSPECIFICSUBORDINATE)) {
		res = constructor_dsa_info(dn_found,dn_stack,TRUE,(*ent_p),err,di_p);
		dn_free (dn_found);
		return (res);
	}
#endif

	if (((*ent_p)->e_data == E_TYPE_CACHE_FROM_MASTER) && 
	        (timenow - (*ent_p)->e_age > cache_timeout)) {
	        DLOG(log_dsap, LLOG_DEBUG, ("find_entry - cache timed out"));
		res = constructor_dsa_info(dn_found,dn_stack,TRUE,(*ent_p),err,di_p);
		delete_cache (dn_found);
		dn_free (dn_found);
		return (res);
	}

out:;
	dn_free (dn_found);

	if ((*ent_p)->e_parent == NULLENTRY)
	{
		DLOG(log_dsap, LLOG_DEBUG, ("find_entry: (*ent_p)->e_parent is NULLENTRY"));
		return (DS_OK);     /* no acl for root entry */
	}

	if (check_acl (acl_who,ACL_DETECT, (*ent_p)->e_parent->e_acl->ac_child, object) == NOTOK) {
		err->dse_type = DSE_SECURITYERROR;
		err->ERR_SECURITY.DSE_sc_problem = DSE_SC_ACCESSRIGHTS;
		return (DS_X500_ERROR);
	}

	if (check_acl (acl_who,ACL_DETECT, (*ent_p)->e_acl->ac_entry, object) == NOTOK) {
		err->dse_type = DSE_SECURITYERROR;
		err->ERR_SECURITY.DSE_sc_problem = DSE_SC_ACCESSRIGHTS;
		return (DS_X500_ERROR);
	}

	return (DS_OK);
}

int	  find_child_entry (object,ca,acl_who,dn_stack,master,ent_p,err,di_p)
DN                        object;
common_args             * ca;
DN    			  acl_who;
struct dn_seq		* dn_stack;
int			  master;
Entry			* ent_p;
struct DSError          * err;
struct di_block		**di_p;
{
/* this is very similar to find_entry(), except a top level */
/* constructor is allowed */
int deref = FALSE;
int res;
DN dn_found;
#ifdef TURBO_AVL
Entry	akid;
#endif

	DLOG (log_dsap,LLOG_DEBUG,("find_child_entry"));
	err->dse_type = DSE_NOERROR;

	if ((ca->ca_servicecontrol.svc_options & SVC_OPT_DONTDEREFERENCEALIAS) == 0)
		deref = TRUE;

	if ((ca->ca_servicecontrol.svc_options & SVC_OPT_DONTUSECOPY) != 0)
		master = TRUE;

	switch(really_find_entry(object,deref,dn_stack,master,ent_p,err,di_p))
	{
	case DS_OK:
	    DLOG(log_dsap, LLOG_DEBUG, ("find_child_entry - rfe: OK"));
	    /* Have set up ent_p continue processing */
	    break;

	case DS_CONTINUE:
	    DLOG(log_dsap, LLOG_DEBUG, ("find_child_entry - rfe: CONTINUE"));
#ifdef DEBUG
	    di_list_log((*di_p));
#endif
	    /* Have set up di_blocks of DSAs to be questioned */
	    return(DS_CONTINUE);

	case DS_X500_ERROR:
	    /* Have set up an error */
	    DLOG(log_dsap, LLOG_DEBUG, ("find_child_entry - rfe: X500_ERROR"));
	    return(DS_X500_ERROR);

	default:
	    /* Scream */
	    LLOG(log_dsap, LLOG_EXCEPTIONS, ("really_find_entry failed in find_entry 1"));
	    return(DS_ERROR_LOCAL);
	}

	/* check to see if children OK */
#ifdef TURBO_AVL
	if ((*ent_p)->e_children != NULLAVL && (*ent_p)->e_allchildrenpresent
	    != FALSE) {
#else
	if (((*ent_p)->e_child != NULLENTRY) && ((*ent_p)->e_allchildrenpresent != FALSE)) {
#endif
	    	DLOG(log_dsap, LLOG_DEBUG, ("find_child_entry - children OK"));
#ifdef TURBO_AVL
		akid = (Entry) avl_getone((*ent_p)->e_children);
		switch (akid->e_data) {
#else
		switch ((*ent_p)->e_child->e_data) {
#endif
		case E_DATA_MASTER:
			DLOG(log_dsap, LLOG_DEBUG, ("find_child_entry - children masters"));
			break;
		case E_TYPE_SLAVE:
			/* see if we can use a copy ... */
			DLOG(log_dsap, LLOG_DEBUG, ("find_child_entry - children slaves"));
		    	if (master) {
				dn_found = get_copy_dn (*ent_p);
				res = constructor_dsa_info_aux(dn_found,dn_stack,master,(*ent_p),err,di_p);
				dn_free (dn_found);
				return (res);
		    	}
			break;
		default:
			DLOG(log_dsap, LLOG_DEBUG, ("find_child_entry - default"));
			dn_found = get_copy_dn (*ent_p);
			res = constructor_dsa_info_aux(dn_found,dn_stack,master,(*ent_p),err,di_p);
			dn_free (dn_found);
			return (res);
		}
	} else if ( (! isleaf(*ent_p)) || (*ent_p)->e_external) {
		DLOG(log_dsap, LLOG_DEBUG, ("find_child_entry - children NOTOK"));
		dn_found = get_copy_dn (*ent_p);
		res = constructor_dsa_info_aux(dn_found,dn_stack,master,(*ent_p),err,di_p);
		dn_free (dn_found);
		return (res);
	}

	if (check_acl (acl_who,ACL_DETECT, (*ent_p)->e_acl->ac_child, object) == NOTOK) {
		err->dse_type = DSE_SECURITYERROR;
		err->ERR_SECURITY.DSE_sc_problem = DSE_SC_ACCESSRIGHTS;
		return (DS_X500_ERROR);
		}

	return (DS_OK);
}

int	  really_find_entry (object, deref, dn_stack, master, ent_p, err, di_p)
DN		  object;
int		  deref;
struct dn_seq	* dn_stack;
int		  master;	/* Generate only master references - NB
				   does not imply returned entry is master */
Entry		* ent_p;
struct DSError	* err;
struct di_block	**di_p;
{
#ifdef TURBO_AVL
Entry parent;
Avlnode *kids;
int entryrdn_cmp ();
#else
register RDN a_rdn;
Entry  trail;
#endif
register RDN b_rdn;
DN     tdn, dn, dn_trail = NULLDN;
DN     aliasdn = NULLDN;
int rdns, aliases;

	DLOG (log_dsap,LLOG_TRACE,("really find entry"));

	if (deref == -2) {
		/* alias loop */
		err->dse_type = DSE_NAMEERROR;
		err->ERR_NAME.DSE_na_problem = DSE_NA_ALIASDEREFERENCE;
		err->ERR_NAME.DSE_na_matched = NULLDN;
		return (DS_X500_ERROR);
	}

	if (database_root == NULLENTRY) {
		LLOG (log_dsap,LLOG_NOTICE,("null root !!!"));
		return(dsa_info_parent(object, err, di_p, master));
	}

	if ((dn = object) == NULLDN) {
		DLOG(log_dsap,LLOG_DEBUG,("really_fe - DS_OK: database_root"));
		(*ent_p) = database_root;
		return (DS_OK);
	}

	b_rdn = dn->dn_rdn;
#ifdef TURBO_AVL
 	if ((kids = database_root->e_children) == NULLAVL) {
#else
	if (((*ent_p) = database_root->e_child) == NULLENTRY) {
#endif
		DLOG(log_dsap, LLOG_DEBUG, ("database->e_child == NULLENTRY"));
		return (no_reply_child (object,dn,dn_stack,master,database_root,err,di_p));
	}

#ifdef TURBO_AVL
 	parent = database_root;
#else
	a_rdn = (*ent_p)->e_name ;
#endif

	for(rdns = 1, aliases = 0 ; ; rdns++ ) { /* break or return out */
#ifdef TURBO_AVL
 		*ent_p = (Entry) avl_find(kids, (caddr_t) b_rdn, entryrdn_cmp);
 		if ( *ent_p == NULLENTRY ) {
 			int res = no_reply_edb(object, dn_trail, dn_stack,
 			    master, parent, err, di_p);
			if (res == DS_CONTINUE) 
				di_rdns (*di_p,rdns,aliases);
			if (aliasdn)
				dn_free (aliasdn);
			return res;
		}
#else
		trail = NULLENTRY;
		while (rdn_cmp (a_rdn, b_rdn) != OK) {
			trail = (*ent_p);
			(*ent_p) = (*ent_p)->e_sibling ;
			if ( (*ent_p) == NULLENTRY ) {
				int res = no_reply_edb (object,dn_trail,dn_stack,master,trail->e_parent,err,di_p);
				if (res == DS_CONTINUE) 
					di_rdns (*di_p,rdns,aliases);

				if (aliasdn)
					dn_free (aliasdn);
				return res;
			}
			a_rdn = (*ent_p)->e_name ;
		}

		/* make found element first in list - optimistaion */
		if (trail != NULLENTRY) {  /* NOT already the first */
			trail->e_sibling = (*ent_p)->e_sibling;
			(*ent_p)->e_sibling = (*ent_p)->e_parent->e_child;
			(*ent_p)->e_parent->e_child = (*ent_p);
		}
#endif /* TURBO_AVL */

		if ( (*ent_p)->e_alias != NULLDN )
			/* got an alias entry */
			if (deref != FALSE) {
				Entry	  new_entry;
				int	  new_deref;
				DN 	  t_aliasdn;

				err->dse_type = DSE_NAMEERROR;
				new_deref = (deref == -1) ? -2 : -1;
				switch(really_find_entry ((*ent_p)->e_alias,new_deref,dn_stack,master,&(new_entry),err,di_p))
				{
				case DS_OK:
				    DLOG(log_dsap, LLOG_DEBUG, ("rfe:rfe:OK"));
				    (*ent_p) = new_entry;
				    t_aliasdn = aliasdn;
				    aliasdn = get_copy_dn(new_entry);
				    aliases = 0;
				    for (tdn=aliasdn; tdn != NULLDN; tdn=tdn->dn_parent) 
					    aliases++;

				    tdn = dn->dn_parent;
				    if (aliasdn == NULLDN)
					    dn = aliasdn = dn_cpy(tdn);
				    else {
					    for (dn = aliasdn; 
						 dn->dn_parent != NULLDN;
						 dn = dn->dn_parent)
						    ;
					    dn->dn_parent = dn_cpy(tdn);
				    }
				    if (t_aliasdn)
					dn_free (t_aliasdn);

				    object = aliasdn;
				    break;
				case DS_CONTINUE:
				    DLOG(log_dsap, LLOG_DEBUG, ("rfe:rfe:CONT"));
#ifdef DEBUG
	        			di_list_log((*di_p));
#endif
					di_rdns (*di_p,rdns,aliases);

				        if (aliasdn)
						dn_free (aliasdn);
					return(DS_CONTINUE);
				case DS_X500_ERROR:
				    DLOG(log_dsap, LLOG_DEBUG, ("rfe:rfe:X500ERR"));
					if ((err->dse_type == DSE_NAMEERROR) && 
						( err->ERR_NAME.DSE_na_problem == DSE_NA_ALIASDEREFERENCE)) {
						if (err->ERR_NAME.DSE_na_matched == NULLDN) {
							DN tmp_dn;
							tmp_dn = dn->dn_parent;
							dn->dn_parent = NULLDN;
							err->ERR_NAME.DSE_na_matched = dn_cpy(object);
							dn->dn_parent = tmp_dn;
							pslog (log_dsap,LLOG_EXCEPTIONS,"Alias deref Problem",dn_print,(caddr_t)err->ERR_NAME.DSE_na_matched);
						}
						if (aliasdn)
							dn_free (aliasdn);
						return (DS_X500_ERROR);
					} else {
						ds_error_free (err);
						err->dse_type = DSE_NAMEERROR;
						err->ERR_NAME.DSE_na_problem = DSE_NA_ALIASPROBLEM;
						err->ERR_NAME.DSE_na_matched = dn_cpy((*ent_p)->e_alias);
						pslog (log_dsap,LLOG_EXCEPTIONS,"Alias Problem",dn_print,(caddr_t)err->ERR_NAME.DSE_na_matched);
						if (aliasdn)
							dn_free (aliasdn);
						return (DS_X500_ERROR);
					}
				default:
				    if (aliasdn)
					dn_free (aliasdn);
				    DLOG(log_dsap, LLOG_DEBUG, ("rfe:rfe:localerror"));
					return(DS_ERROR_LOCAL);
				}
				

			} else if ( dn->dn_parent == NULLDN) {
				DLOG(log_dsap,LLOG_DEBUG,("really_fe - DS_OK: ?1"));
				if (aliasdn)
					dn_free (aliasdn);
				return(DS_OK);
			} else {
				/* alias on route - error in this case */
				DN tmp_dn;
				err->dse_type = DSE_NAMEERROR;
				err->ERR_NAME.DSE_na_problem = DSE_NA_ALIASDEREFERENCE;
				tmp_dn = dn->dn_parent;
				dn->dn_parent = NULLDN;
				err->ERR_NAME.DSE_na_matched = dn_cpy(object);
				dn->dn_parent = tmp_dn;
				pslog (log_dsap,LLOG_EXCEPTIONS,"Alias deref(2) Problem",dn_print,(caddr_t)err->ERR_NAME.DSE_na_matched);
				if (aliasdn)
					dn_free (aliasdn);
				return (DS_X500_ERROR);
			}


		if (dn->dn_parent == NULLDN) {
			DLOG(log_dsap,LLOG_DEBUG,("really_fe - DS_OK: ?2"));
			if (aliasdn)
				dn_free (aliasdn);
			return (DS_OK);
		}

#ifdef TURBO_AVL
		if ((*ent_p)->e_children == NULLAVL) {
#else
		if ( (*ent_p)->e_child == NULLENTRY ) {
#endif
			int res = no_reply_child (object,dn,dn_stack,master,(*ent_p),err,di_p);
		        if (res == DS_CONTINUE) 
				di_rdns (*di_p,rdns,aliases);

			if (aliasdn)
				dn_free (aliasdn);
			return res;						
		}

		dn_trail = dn;
		dn = dn->dn_parent;
		b_rdn = dn->dn_rdn;

#ifdef TURBO_AVL
		kids = (*ent_p)->e_children;
		parent = *ent_p;
#else
		(*ent_p) = (*ent_p)->e_child;
		a_rdn = (*ent_p)->e_name;
#endif
	}
	/* NOTREACHED */
}


int	  referral_dsa_info (object,dn_stack,master,ptr,err,di_p,chain)
DN		  object;
struct dn_seq	* dn_stack;
int		  master;
Entry		  ptr;
struct DSError	* err;
struct di_block	**di_p;
char chain;
{
int ret;
struct di_block     * di_tmp;

	DLOG (log_dsap,LLOG_TRACE,("referral dsa_info"));
	/* generate a referral to a DUA if possible */

	if (ptr != NULLENTRY)
		ptr=ptr->e_parent;

	if ((ret = constructor_dsa_info_aux(object,dn_stack,master,ptr,err,di_p)) != DS_CONTINUE)
		return ret;

	/* Try to make a referral - if not schedule a chain !!! */
	if (chain)
		return DS_CONTINUE;

	/* PROBLEM: The following will get the best referral from our point 
	 * of view.  This may not be the same from the DUAs point of view !!!
         */
	sort_dsa_list (di_p);
        for(di_tmp= *di_p; di_tmp!=NULL_DI_BLOCK; di_tmp=di_tmp->di_next)
        {
                if(di_tmp->di_state == DI_DEFERRED)
                        continue;

                if(di2cref(di_tmp, err, DS_CTX_X500_DAP) == OK)
                    return (DS_X500_ERROR);	/* return the referral !! */
        }
	return DS_CONTINUE;

}

int	  constructor_dsa_info (object,dn_stack,master,ptr,err,di_p)
DN		  object;
struct dn_seq	* dn_stack;
int		  master;
Entry		  ptr;
struct DSError	* err;
struct di_block	**di_p;
{
	DLOG (log_dsap,LLOG_TRACE,("constructor dsa_info"));

	if (ptr != NULLENTRY)
		ptr=ptr->e_parent;
		
	return(constructor_dsa_info_aux(object,dn_stack,master,ptr,err,di_p));
}

int	  constructor_dsa_info_aux(object,dn_stack,master,ptr,err,di_p)
DN		  object;
struct dn_seq	* dn_stack;
int		  master;
Entry		  ptr;
struct DSError	* err;
struct di_block	**di_p;
{
	DLOG (log_dsap,LLOG_TRACE,("construct dsa_info aux"));

	/* follow entry back, until something that is not a CONSTRUCTOR */

	for (; ptr!= NULLENTRY; ptr=ptr->e_parent)
		if ((ptr->e_data == E_DATA_MASTER) ||
		    (ptr->e_data == E_TYPE_SLAVE) ||
	    	    ((ptr->e_data == E_TYPE_CACHE_FROM_MASTER) &&
		     (timenow - ptr->e_age < cache_timeout))) {
			if ( (ptr->e_master == NULLAV) && (ptr->e_slave == NULLAV))
				continue ;
			return(dsa_info_new(object,dn_stack,master,ptr,err,di_p));
		}

	return(dsa_info_parent(object,err,di_p,master));
}

int	  no_reply_child (object,dn,dn_stack,master,entryptr,err,di_p)
DN		  object;
DN		  dn; 	/* tail - not matched */
struct dn_seq	* dn_stack;
int		  master;
Entry		  entryptr;
struct DSError	* err;
struct di_block	**di_p;
{
DN dn_tmp;
	
	DLOG (log_dsap,LLOG_TRACE,("no reply child"));

	if (isleaf(entryptr))
	{
		DLOG (log_dsap,LLOG_DEBUG,("definate NO"));
		if (dn != NULLDN) {
			dn_tmp = dn->dn_parent;
			dn->dn_parent = NULLDN;
		} else
			object = NULLDN;
		err->dse_type = DSE_NAMEERROR;
		err->ERR_NAME.DSE_na_problem = DSE_NA_NOSUCHOBJECT;
		err->ERR_NAME.DSE_na_matched = dn_cpy (object);
		if (dn != NULLDN)
			dn->dn_parent = dn_tmp;

		return(DS_X500_ERROR);
	}
	
	return(constructor_dsa_info_aux (object, dn_stack, master, entryptr, err, di_p));
}

int	  no_reply_edb (object,dn,dn_stack,master,entryptr,err,di_p)
DN		  object;
DN		  dn; 	/* tail - not matched */
struct dn_seq	* dn_stack;
int		  master;
Entry		  entryptr;
struct DSError	* err;
struct di_block	**di_p;
{
DN dn_tmp;
#ifdef TURBO_AVL
Entry akid;
#endif

	DLOG (log_dsap,LLOG_TRACE,("no reply edb"));

	if (isleaf(entryptr)) {
		DLOG (log_dsap,LLOG_DEBUG,("definate NO"));
		if (dn != NULLDN) {
			dn_tmp = dn->dn_parent;
			dn->dn_parent = NULLDN;
		} else
			object = NULLDN;
		err->dse_type = DSE_NAMEERROR;
		err->ERR_NAME.DSE_na_problem = DSE_NA_NOSUCHOBJECT;
		err->ERR_NAME.DSE_na_matched = dn_cpy (object);
		if (dn != NULLDN)
			dn->dn_parent = dn_tmp;

		return(DS_X500_ERROR);
	}

#ifdef TURBO_AVL
	if (entryptr->e_children == NULLAVL) {
#else
	if (entryptr->e_child == NULLENTRY) {
#endif
		return(constructor_dsa_info(object,dn_stack,master,entryptr,err,di_p));
	}

#ifdef TURBO_AVL
	akid = (Entry) avl_getone(entryptr->e_children);
	if ((akid->e_data == E_DATA_MASTER)
	    || ((! master) && (akid->e_data == E_TYPE_SLAVE)) ) {
#else
	if ((entryptr->e_child->e_data == E_DATA_MASTER)
		|| ((! master) && (entryptr->e_child->e_data == E_TYPE_SLAVE))) {
#endif
		DLOG (log_dsap,LLOG_DEBUG,("definate NO"));
		if (dn != NULLDN) {
			dn_tmp = dn->dn_parent;
			dn->dn_parent = NULLDN;
		} else
			object = NULLDN;
		err->dse_type = DSE_NAMEERROR;
		err->ERR_NAME.DSE_na_problem = DSE_NA_NOSUCHOBJECT;
		err->ERR_NAME.DSE_na_matched = dn_cpy (object);
		if (dn != NULLDN)
			dn->dn_parent = dn_tmp;
		return(DS_X500_ERROR);
	}

	/* build a referral */
	return(constructor_dsa_info_aux(object,dn_stack,master,entryptr,err,di_p));
}