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

/* ds_add.c - */

#ifndef lint
static char *rcsid = "$Header: /f/osi/quipu/RCS/ds_add.c,v 7.4 91/02/22 09:38:41 mrose Interim $";
#endif

/*
 * $Header: /f/osi/quipu/RCS/ds_add.c,v 7.4 91/02/22 09:38:41 mrose Interim $
 *
 *
 * $Log:	ds_add.c,v $
 * Revision 7.4  91/02/22  09:38:41  mrose
 * Interim 6.8
 * 
 * Revision 7.3  90/10/17  11:53:36  mrose
 * sync
 * 
 * Revision 7.2  90/07/09  14:45:37  mrose
 * sync
 * 
 * Revision 7.1  90/01/11  18:37:19  mrose
 * real-sync
 * 
 * Revision 7.0  89/11/23  22:17:03  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/config.h"
#include "quipu/util.h"
#include "quipu/entry.h"
#include "quipu/add.h"
#include "quipu/malloc.h"
#ifdef TURBO_AVL
#include "quipu/turbo.h"
#endif
#include "pepsy.h"
#include "quipu/DAS_pre_defs.h"

extern Entry database_root;
extern LLog * log_dsap;
extern int local_master_size;
extern DN mydsadn;

extern AttributeType at_masterdsa;
extern AttributeType at_slavedsa;
extern AttributeType at_objectclass;

#ifdef TURBO_INDEX
extern AttributeType *turbo_index_types;
#endif

do_ds_addentry (arg, error, binddn,target,di_p,dsp)
    struct ds_addentry_arg      *arg;
    struct DSError              *error;
    DN                          binddn;
    DN                          target;
    struct di_block		**di_p;
    char dsp;
{
Entry  entryptr,ptr;
register DN  dntop, dn = NULLDN;
DN  trail = NULLDN;
extern Entry database_root;
ContinuationRef cont_ref_parent ();
char * new_version ();
int retval;
extern int read_only;
#ifdef TURBO_AVL
extern int	entry_cmp();
#endif

	DLOG (log_dsap,LLOG_TRACE,("ds_add"));

	if (!dsp)
		target = arg->ada_object;

	/* stop aliases being dereferenced */
	arg->ada_common.ca_servicecontrol.svc_options |= SVC_OPT_DONTDEREFERENCEALIAS;

	error ->dse_type = DSE_NOERROR;
	/* first of all see if entry exists */

	if (target == NULLDN) {
		error->dse_type = DSE_NAMEERROR;
		error->ERR_NAME.DSE_na_problem = DSE_NA_NOSUCHOBJECT;
		error->ERR_NAME.DSE_na_matched = NULLDN;
		return (DS_ERROR_REMOTE);
	}

	switch (find_entry (target,&(arg->ada_common),binddn,NULLDNSEQ,TRUE,&entryptr, error, di_p, OP_ADDENTRY)) 
	{
	case DS_OK:
		error->dse_type = DSE_UPDATEERROR;
		error->ERR_UPDATE.DSE_up_problem = DSE_UP_ALREADYEXISTS;
		return(DS_ERROR_REMOTE);
	case DS_CONTINUE:
	    /* Filled out di_p - what do we do with it ?? */
	    return(DS_CONTINUE);
	case DS_X500_ERROR:
	    /* Filled out error - what do we do with it ?? */
	    if ((error->dse_type != DSE_NAMEERROR) || (error->ERR_NAME.DSE_na_problem != DSE_NA_NOSUCHOBJECT)) {
		return(DS_X500_ERROR);
	    }
	    ds_error_free (error);  /* not interested - know it does not exist */
	    break;
	default:
	    /* SCREAM */
	    LLOG(log_dsap, LLOG_EXCEPTIONS, ("do_ds_read() - find_entry failed"));
	    return(DS_ERROR_LOCAL);
	}

	/* object does not exist, so create it */

	/* Strong authentication  */
	if ((retval = check_security_parms((caddr_t) arg, 
				_ZAddEntryArgumentDataDAS, 
				&_ZDAS_mod,
				arg->ada_common.ca_security,
				arg->ada_common.ca_sig, &binddn)) != 0)
	{
		error->dse_type = DSE_SECURITYERROR;
		error->ERR_SECURITY.DSE_sc_problem = retval;
		return (DS_ERROR_REMOTE);
	}

	DLOG (log_dsap,LLOG_TRACE,("add - find parent"));

	if ((dntop = dn_cpy(target)) != NULLDN)
		for (dn=dntop; dn->dn_parent != NULLDN; dn=dn->dn_parent)
			trail = dn;

	if (trail == NULLDN) {
		dntop = NULLDN;
		entryptr = database_root;
		if (entryptr->e_data != E_DATA_MASTER) {
			error->dse_type = DSE_REFERRAL;
        		error->ERR_REFERRAL.DSE_ref_prefix = NULLDN;
			if ((error->ERR_REFERRAL.DSE_ref_candidates = cont_ref_parent (NULLDN)) == NULLCONTINUATIONREF) {
				error->dse_type = DSE_SERVICEERROR;
				error->ERR_SERVICE.DSE_sv_problem = DSE_SV_INVALIDREFERENCE;
			}
			return (DS_ERROR_CONNECT);
		}
	} else {
		trail->dn_parent = NULLDN;
		switch(find_child_entry(dntop,&(arg->ada_common),binddn,NULLDNSEQ,TRUE,&(entryptr), error, di_p))
		{
		case DS_OK:
		    /* Filled out entryptr - carry on */
		    break;
		case DS_CONTINUE:
		    /* Filled out di_p - what do we do with it ?? */
		    /* When add returns DS_CONTINUE the target must be changed */
		    return(DS_CONTINUE);

		case DS_X500_ERROR:
		    /* Filled out error - what do we do with it ?? */
		    return(DS_X500_ERROR);
		default:
		    /* SCREAM */
		    LLOG(log_dsap, LLOG_EXCEPTIONS, ("do_ds_add() - find_child_entry failed"));
		    return(DS_ERROR_LOCAL);
		}
	}

	if ( read_only || ((entryptr->e_parent != NULLENTRY) && (entryptr->e_parent->e_lock))) {
		error->dse_type = DSE_SERVICEERROR;
		error->ERR_SERVICE.DSE_sv_problem = DSE_SV_UNWILLINGTOPERFORM;
		dn_free (dntop);
		dn_free (dn);
		return (DS_ERROR_REMOTE);
	}

	/* not prepared to accept operation over DSP */
	if (dsp) {
		error->dse_type = DSE_SECURITYERROR;
		error->ERR_SECURITY.DSE_sc_problem = DSE_SC_AUTHENTICATION;
		dn_free (dntop);
		dn_free (dn);
		return (DS_ERROR_REMOTE);
	}

	DLOG (log_dsap,LLOG_TRACE,("add - acl"));
	if (check_acl (binddn,ACL_ADD,entryptr->e_acl->ac_child,dntop) == NOTOK) {
		error->dse_type = DSE_SECURITYERROR;
		error->ERR_SECURITY.DSE_sc_problem = DSE_SC_ACCESSRIGHTS;
		dn_free (dntop);
		dn_free (dn);
		return (DS_ERROR_REMOTE);
	}

	DLOG (log_dsap,LLOG_TRACE,("add - default"));

	DATABASE_HEAP;

	ptr = get_default_entry (entryptr);
	ptr->e_name = rdn_cpy (dn->dn_rdn);
	ptr->e_attributes = as_cpy (arg->ada_entry);
 
	modify_attr (ptr,binddn);

	DLOG (log_dsap,LLOG_TRACE,("add - unravel"));
	if (unravel_attribute (ptr,error) != OK) {
		dn_free (dntop);
		dn_free (dn);
		entry_free (ptr);
		GENERAL_HEAP;
		return (DS_ERROR_REMOTE);
	}

	if ( ! check_oc_hierarchy(ptr->e_oc)) {
		error->dse_type = DSE_UPDATEERROR;
		error->ERR_UPDATE.DSE_up_problem = DSE_UP_OBJECTCLASSVIOLATION;
		dn_free (dntop);
		dn_free (dn);
		entry_free (ptr);
		GENERAL_HEAP;
		return (DS_ERROR_REMOTE);
	}

	DLOG (log_dsap,LLOG_TRACE,("add - schema"));
	if (check_schema (ptr,NULLATTR,error) != OK) {
		dn_free (dntop);
		dn_free (dn);
		entry_free (ptr);
		GENERAL_HEAP;
		return (DS_ERROR_REMOTE);
	}

	GENERAL_HEAP;

	dn_free (dn);
	dn_free (dntop);

#ifdef TURBO_AVL
	if ( (!ptr->e_leaf) && (!ptr->e_external) && (!ptr->e_children)) {
#else
	if ( (!ptr->e_leaf) && (!ptr->e_external) && (!ptr->e_child)) {
#endif
		AV_Sequence avs;
		for (avs = ptr->e_master; avs != NULLAV; avs=avs->avseq_next) 
			if (dn_cmp ((DN)avs->avseq_av.av_struct, mydsadn) == 0) {
				create_null_edb (ptr);
				break;
			} 
		if (avs == NULLAV)
			ptr->e_allchildrenpresent = FALSE;
	}

#ifdef TURBO_AVL
	/* add the entry */
	DATABASE_HEAP;
	(void) avl_insert(&entryptr->e_children, (caddr_t) ptr, entry_cmp, avl_dup_error);
	GENERAL_HEAP;
#endif
		
	if (entryptr->e_leaf) {

#ifdef COMPAT_6_0

		/* Turn leaf into non leaf, and add child */
		/* Temporary until managemnet tools do it */

		Attr_Sequence newas;
		
		if (entryptr->e_data != E_DATA_MASTER) {
			DN dn_found;
			struct dn_seq	* dn_stack = NULLDNSEQ;
			int res;

			dn_found = get_copy_dn (entryptr);
			res = constructor_dsa_info(dn_found,dn_stack,TRUE,entryptr,error,di_p);
			dn_free (dn_found);
			entry_free (ptr);
			switch (res) {
			case DS_CONTINUE:
				return(DS_CONTINUE);
			case DS_X500_ERROR:
				return(DS_CONTINUE);
			default:
			    	return(DS_ERROR_LOCAL);
			}
			/* NOTREACHED */
		}

#ifndef TURBO_AVL
		entryptr->e_child = ptr;
#endif
		/* add master and slave attributes */

		DATABASE_HEAP;

		if ((entryptr->e_parent->e_slave == NULLAV) && (entryptr->e_parent->e_master == NULLAV)) {
			extern char * mydsaname;
			entryptr->e_master = str2avs (mydsaname,at_masterdsa);
			newas = as_comp_new (AttrT_cpy(at_masterdsa),entryptr->e_master,NULLACL_INFO);
			entryptr->e_attributes = as_merge (entryptr->e_attributes,newas);
		} else {
			if ((entryptr->e_master = avs_cpy(entryptr->e_parent->e_master)) != NULLAV) {
				newas = as_comp_new (AttrT_cpy(at_masterdsa),entryptr->e_master,NULLACL_INFO);
				entryptr->e_attributes = as_merge (entryptr->e_attributes,newas);
			}
			if ((entryptr->e_slave = avs_cpy (entryptr->e_parent->e_slave)) != NULLAV) {
				newas = as_comp_new (AttrT_cpy(at_slavedsa),entryptr->e_slave,NULLACL_INFO);
				entryptr->e_attributes = as_merge (entryptr->e_attributes,newas);
			}
		}
		/* add new QuipuNonLeaf objectclass */

		/* see if OC inherited */
		if (as_find_type(entryptr->e_attributes,at_objectclass) == NULLATTR) {
			/* OC inherited - pull down */
			newas = as_comp_new (AttrT_cpy(at_objectclass),avs_cpy(entryptr->e_oc),NULLACL_INFO);
			entryptr->e_attributes = as_merge (entryptr->e_attributes,newas);
		}

		newas = as_comp_new (AttrT_cpy(at_objectclass),str2avs(NONLEAFOBJECT,at_objectclass),NULLACL_INFO);
		entryptr->e_attributes = as_merge (entryptr->e_attributes,newas);

		if (entryptr->e_parent != NULLENTRY) {
			if (entryptr->e_parent->e_edbversion)
				free (entryptr->e_parent->e_edbversion);
			entryptr->e_parent->e_edbversion = new_version();
		}
		if (entryptr->e_edbversion)
			free (entryptr->e_edbversion);
		entryptr->e_edbversion = new_version();
		ptr->e_edbversion = new_version();
		entryptr->e_allchildrenpresent = 2;	/* Subtree ! */

		modify_attr (entryptr,binddn);
		if (unravel_attribute (entryptr,error) != OK) 
			fatal (-31,"serious schema error");

#ifdef TURBO_INDEX
		turbo_add2index(ptr);		/* add new entry to index */
		turbo_add2index(entryptr);	/* add parent to index */
#endif

#ifdef TURBO_DISK
		/* write the new entry */
		if (turbo_write(ptr) == NOTOK)
			fatal(-32,"add turbo_write (2) failure - check database");
#else
		if (journal (ptr) == NOTOK)
			fatal (-32,"add journal (2) failure - check database");
#endif

		entryptr->e_leaf = FALSE;

#ifdef TURBO_DISK
		/* rewrite the parent as well */
		if (turbo_write(entryptr) == NOTOK)
			fatal(-31,"add parent turbo_write failed - check database");
#else
		if (journal (entryptr) != OK)
			fatal (-31,"add parent journal failed - check database");
#endif

		GENERAL_HEAP;

		local_master_size++;
		return (OK);

#else	/* COMPAT_6_0 */

		/* Management tools will take care of the situation properly */

		error->ERR_SERVICE.DSE_sv_problem = DSE_SV_UNWILLINGTOPERFORM;
		return(DS_ERROR_REMOTE) ;

#endif	/* COMPAT_6_0 */

#ifdef TURBO_AVL
	}
#else
	} else {
		ptr->e_sibling = entryptr->e_child;
		entryptr->e_child = ptr;
	}
#endif

	if (ptr->e_parent != NULLENTRY) {
		if (ptr->e_parent->e_edbversion)
			free (ptr->e_parent->e_edbversion);
		ptr->e_parent->e_edbversion = new_version();
	}

#ifdef TURBO_INDEX
	turbo_add2index(ptr);
#endif

#ifdef TURBO_DISK
	if (turbo_write(ptr) == NOTOK)
		fatal(-32,"add turbo_write failure - check database");
#else
	if (journal (ptr) == NOTOK)
		fatal (-32,"add journal failure - check database");
#endif

	local_master_size++;
	return (DS_OK);
}