コード例 #1
0
ファイル: windows_private.c プロジェクト: leto/389-ds
/*  writes the current cookie into dse.ldif under the replication agreement entry 
	returns: ldap result code of the operation. */
int 
windows_private_save_dirsync_cookie(const Repl_Agmt *ra)
{
	Dirsync_Private *dp = NULL;
    Slapi_PBlock *pb = NULL;
	Slapi_DN* sdn = NULL;
	int rc = 0;
	Slapi_Mods *mods = NULL;

    
  
	LDAPDebug0Args( LDAP_DEBUG_TRACE, "=> windows_private_save_dirsync_cookie\n" );
	PR_ASSERT(ra);

	dp = (Dirsync_Private *) agmt_get_priv(ra);
	PR_ASSERT (dp);


	pb = slapi_pblock_new ();
  
    mods = windows_private_get_cookie_mod(dp, LDAP_MOD_REPLACE);
    sdn = slapi_sdn_dup( agmt_get_dn_byref(ra) );

    slapi_modify_internal_set_pb_ext (pb, sdn, 
            slapi_mods_get_ldapmods_byref(mods), NULL, NULL, 
            repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), 0);
    slapi_modify_internal_pb (pb);

    slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);

    if (rc == LDAP_NO_SUCH_ATTRIBUTE)
    {	/* try again, but as an add instead */
		slapi_mods_free(&mods);
		mods = windows_private_get_cookie_mod(dp, LDAP_MOD_ADD);
		slapi_modify_internal_set_pb_ext (pb, sdn,
		        slapi_mods_get_ldapmods_byref(mods), NULL, NULL, 
		        repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), 0);
		slapi_modify_internal_pb (pb);
	
		slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
    }

	slapi_pblock_destroy (pb);
	slapi_mods_free(&mods);
	slapi_sdn_free(&sdn);

	LDAPDebug0Args( LDAP_DEBUG_TRACE, "<= windows_private_save_dirsync_cookie\n" );
	return rc;
}
コード例 #2
0
ファイル: common.c プロジェクト: LiptonB/freeipa
int ipapwd_set_extradata(const char *dn,
                         const char *principal,
                         time_t unixtime)
{
    Slapi_Mods *smods;
    Slapi_Value *va[2] = { NULL };
    struct berval bv;
    char *xdata;
    int xd_len;
    int p_len;
    int ret;

    p_len = strlen(principal);
    xd_len = 2 + 4 + p_len + 1;
    xdata = malloc(xd_len);
    if (!xdata) {
        return LDAP_OPERATIONS_ERROR;
    }

    smods = slapi_mods_new();

    /* data type id */
    xdata[0] = 0x00;
    xdata[1] = 0x02;

    /* unix timestamp in Little Endian */
    xdata[2] = unixtime & 0xff;
    xdata[3] = (unixtime & 0xff00) >> 8;
    xdata[4] = (unixtime & 0xff0000) >> 16;
    xdata[5] = (unixtime & 0xff000000) >> 24;

    /* append the principal name */
    strncpy(&xdata[6], principal, p_len);

    xdata[xd_len -1] = 0;

    bv.bv_val = xdata;
    bv.bv_len = xd_len;
    va[0] = slapi_value_new_berval(&bv);

    slapi_mods_add_mod_values(smods, LDAP_MOD_REPLACE, "krbExtraData", va);

    ret = ipapwd_apply_mods(dn, smods);

    slapi_value_free(&va[0]);
    slapi_mods_free(&smods);

    return ret;
}
コード例 #3
0
ファイル: ldbm_modify.c プロジェクト: Firstyear/ds
/* Modify context structure destructor */
int modify_term(modify_context *mc,struct backend *be)
{
    ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;

    slapi_mods_free(&mc->smods);
    /* Unlock and return entries */
    if (mc->old_entry)  {
        cache_unlock_entry(&inst->inst_cache, mc->old_entry);
        CACHE_RETURN( &(inst->inst_cache), &(mc->old_entry) );
        mc->old_entry= NULL;
    }

    CACHE_RETURN(&(inst->inst_cache), &(mc->new_entry));
    mc->new_entry= NULL;
    return 0;
}
コード例 #4
0
ファイル: common.c プロジェクト: LiptonB/freeipa
/* Modify the Password attributes of the entry */
int ipapwd_SetPassword(struct ipapwd_krbcfg *krbcfg,
                       struct ipapwd_data *data, int is_krb)
{
    int ret = 0;
    Slapi_Mods *smods = NULL;
    Slapi_Value **svals = NULL;
    Slapi_Value **ntvals = NULL;
    Slapi_Value **pwvals = NULL;
    char *nt = NULL;
    int is_smb = 0;
    int is_ipant = 0;
    int is_host = 0;
    Slapi_Value *sambaSamAccount;
    Slapi_Value *ipaNTUserAttrs;
    Slapi_Value *ipaHost;
    char *errMesg = NULL;
    char *modtime = NULL;

    LOG_TRACE("=>\n");

    sambaSamAccount = slapi_value_new_string("sambaSamAccount");
    if (slapi_entry_attr_has_syntax_value(data->target,
                                          "objectClass", sambaSamAccount)) {
        is_smb = 1;
    }
    slapi_value_free(&sambaSamAccount);

    ipaNTUserAttrs = slapi_value_new_string("ipaNTUserAttrs");
    if (slapi_entry_attr_has_syntax_value(data->target,
                                          "objectClass", ipaNTUserAttrs)) {
        is_ipant = 1;
    }
    slapi_value_free(&ipaNTUserAttrs);

    ipaHost = slapi_value_new_string("ipaHost");
    if (slapi_entry_attr_has_syntax_value(data->target,
                                          "objectClass", ipaHost)) {
        is_host = 1;
    }
    slapi_value_free(&ipaHost);

    ret = ipapwd_gen_hashes(krbcfg, data,
                            data->password,
                            is_krb, is_smb, is_ipant,
                            &svals, &nt, &ntvals, &errMesg);
    if (ret) {
        goto free_and_return;
    }

    smods = slapi_mods_new();

    if (svals) {
        slapi_mods_add_mod_values(smods, LDAP_MOD_REPLACE,
                                  "krbPrincipalKey", svals);

		/* krbLastPwdChange is used to tell whether a host entry has a
		 * keytab so don't set it on hosts.
		 */
        if (!is_host) {
	    /* change Last Password Change field with the current date */
            ret = ipapwd_setdate(data->target, smods, "krbLastPwdChange",
                                 data->timeNow, false);
            if (ret != LDAP_SUCCESS)
                goto free_and_return;

	    /* set Password Expiration date */
            ret = ipapwd_setdate(data->target, smods, "krbPasswordExpiration",
                                 data->expireTime, (data->expireTime == 0));
            if (ret != LDAP_SUCCESS)
                goto free_and_return;
	}
    }

    if (nt && is_smb) {
        slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
                              "sambaNTPassword", nt);
    }

    if (ntvals && is_ipant) {
        slapi_mods_add_mod_values(smods, LDAP_MOD_REPLACE,
                                  "ipaNTHash", ntvals);
    }

    if (is_smb) {
        /* with samba integration we need to also set sambaPwdLastSet or
         * samba will decide the user has to change the password again */
        if (data->changetype == IPA_CHANGETYPE_ADMIN) {
            /* if it is an admin change instead we need to let know to
             * samba as well that the use rmust change its password */
            modtime = slapi_ch_smprintf("0");
        } else {
            modtime = slapi_ch_smprintf("%ld", (long)data->timeNow);
        }
        if (!modtime) {
            LOG_FATAL("failed to smprintf string!\n");
            ret = LDAP_OPERATIONS_ERROR;
            goto free_and_return;
        }
        slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
                              "sambaPwdLastset", modtime);
    }
    if (is_krb) {
        if (data->changetype == IPA_CHANGETYPE_ADMIN) {
            slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
                                 "krbLoginFailedCount", "0");
        }
    }
    /* let DS encode the password itself, this allows also other plugins to
     * intercept it to perform operations like synchronization with Active
     * Directory domains through the replication plugin */
    slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
                          "userPassword", data->password);

    /* set password history */
    if (data->policy.history_length > 0) {
        pwvals = ipapwd_setPasswordHistory(smods, data);
        if (pwvals) {
            slapi_mods_add_mod_values(smods, LDAP_MOD_REPLACE,
                                      "passwordHistory", pwvals);
        }
    }

    /* FIXME:
     * instead of replace we should use a delete/add so that we are
     * completely sure nobody else modified the entry meanwhile and
     * fail if that's the case */

    /* commit changes */
    ret = ipapwd_apply_mods(data->dn, smods);

    LOG_TRACE("<= result: %d\n", ret);

free_and_return:
    if (nt) slapi_ch_free((void **)&nt);
    if (modtime) slapi_ch_free((void **)&modtime);
    slapi_mods_free(&smods);
    ipapwd_free_slapi_value_array(&svals);
    ipapwd_free_slapi_value_array(&ntvals);
    ipapwd_free_slapi_value_array(&pwvals);

    return ret;
}
コード例 #5
0
ファイル: referint.c プロジェクト: ohamada/389ds
/*
 * update multiple attribute values per _do_modify
 */
static int
_update_all_per_mod(Slapi_DN *entrySDN,      /* DN of the searched entry */
                    Slapi_Attr *attr,        /* referred attribute */
                    char *attrName,
                    Slapi_DN *origDN,        /* original DN that was modified */
                    char *newRDN,            /* new RDN from modrdn */
                    const char *newsuperior, /* new superior from modrdn */
                    Slapi_PBlock *mod_pb)
{
    Slapi_Mods *smods = NULL;
    char *newDN = NULL;
    char **dnParts = NULL;
    char *sval = NULL;
    char *newvalue = NULL;
    char *p = NULL;
    size_t dnlen = 0;
    int rc = 0;
    int nval = 0;

    slapi_attr_get_numvalues(attr, &nval);

    if (NULL == newRDN && NULL == newsuperior) {
        /* in delete mode */
        LDAPMod *mods[2];
        char *values_del[2];
        LDAPMod attribute1;

        /* delete old dn so set that up */
        values_del[0] = (char *)slapi_sdn_get_dn(origDN);
        values_del[1] = NULL;
        attribute1.mod_type = attrName;
        attribute1.mod_op = LDAP_MOD_DELETE;
        attribute1.mod_values = values_del;
        mods[0] = &attribute1;
        /* terminate list of mods. */
        mods[1] = NULL;
        rc = _do_modify(mod_pb, entrySDN, mods);
        if (rc) {
            slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
                "_update_all_per_mod: entry %s: deleting \"%s: %s\" failed (%d)"
                "\n", slapi_sdn_get_dn(entrySDN), attrName, slapi_sdn_get_dn(origDN), rc);
        }
    } else {
        /* in modrdn mode */
        const char *superior = NULL;
        int nval = 0;
        Slapi_Value *v = NULL;

        if (NULL == origDN) {
            slapi_log_error(SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
                            "_update_all_per_mod: NULL dn was passed\n");
            goto bail;
        }
        /* need to put together rdn into a dn */
        dnParts = slapi_ldap_explode_dn( slapi_sdn_get_dn(origDN), 0 );
        if (NULL == dnParts) {
            slapi_log_error(SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
                            "_update_all_per_mod: failed to explode dn %s\n",
                            slapi_sdn_get_dn(origDN));
            goto bail;
        }
        if (NULL == newRDN) {
            newRDN = dnParts[0];
        }
        if (newsuperior) {
            superior = newsuperior;
        } else {
            /* do not free superior */
            superior = slapi_dn_find_parent(slapi_sdn_get_dn(origDN));
        }
        /* newRDN and superior are already normalized. */
        newDN = slapi_ch_smprintf("%s,%s", newRDN, superior);
        slapi_dn_ignore_case(newDN);
        /* 
         * Compare the modified dn with the value of 
         * the target attribute of referint to find out
         * the modified dn is the ancestor (case 2) or
         * the value itself (case 1).
         *
         * E.g., 
         * (case 1) 
         * modrdn: uid=A,ou=B,o=C --> uid=A',ou=B',o=C
         *            (origDN)             (newDN)
         * member: uid=A,ou=B,ou=C --> uid=A',ou=B',ou=C
         *            (sval)               (newDN)
         *
         * (case 2) 
         * modrdn: ou=B,o=C --> ou=B',o=C
         *         (origDN)      (newDN)
         * member: uid=A,ou=B,ou=C --> uid=A,ou=B',ou=C
         *         (sval)              (sval' + newDN)
         */
        slapi_attr_get_numvalues(attr, &nval);
        smods = slapi_mods_new();
        slapi_mods_init(smods, 2 * nval + 1);

        for (nval = slapi_attr_first_value(attr, &v);
             nval != -1;
             nval = slapi_attr_next_value(attr, nval, &v)) {
            p = NULL;
            dnlen = 0;

            /* DN syntax, which should be a string */
            sval = slapi_ch_strdup(slapi_value_get_string(v));
            rc = slapi_dn_normalize_case_ext(sval, 0,  &p, &dnlen);
            if (rc == 0) { /* sval is passed in; not terminated */
                *(p + dnlen) = '\0';
                sval = p;
            } else if (rc > 0) {
                slapi_ch_free_string(&sval);
                sval = p;
            }
            /* else: (rc < 0) Ignore the DN normalization error for now. */

            p = PL_strstr(sval, slapi_sdn_get_ndn(origDN));
            if (p == sval) {
                /* (case 1) */
                slapi_mods_add_string(smods, LDAP_MOD_DELETE, attrName, sval);
                slapi_mods_add_string(smods, LDAP_MOD_ADD, attrName, newDN);

            } else if (p) {
                /* (case 2) */
                slapi_mods_add_string(smods, LDAP_MOD_DELETE, attrName, sval);
                *p = '\0';
                newvalue = slapi_ch_smprintf("%s%s", sval, newDN);
                slapi_mods_add_string(smods, LDAP_MOD_ADD, attrName, newvalue);
                slapi_ch_free_string(&newvalue);
            } 
            /* else: value does not include the modified DN.  Ignore it. */
            slapi_ch_free_string(&sval);
        }
        rc = _do_modify(mod_pb, entrySDN, slapi_mods_get_ldapmods_byref(smods));
        if (rc) {
            slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
                        "_update_all_per_mod: entry %s failed (%d)\n",
                        slapi_sdn_get_dn(entrySDN), rc);
        }

        /* cleanup memory allocated for dnParts and newDN */
        if (dnParts){
            slapi_ldap_value_free(dnParts);
            dnParts = NULL;
        }
        slapi_ch_free_string(&newDN);
        slapi_mods_free(&smods);
    }

bail:
    return rc;
}
コード例 #6
0
ファイル: memberof_config.c プロジェクト: Firstyear/ds
/*
 * Check if we are modifying the config, or changing the shared config entry
 */
int
memberof_shared_config_validate(Slapi_PBlock *pb)
{
	Slapi_Entry *e = 0;
	Slapi_Entry *resulting_e = 0;
	Slapi_Entry *config_entry = NULL;
	Slapi_DN *sdn = NULL;
	Slapi_DN *config_sdn = NULL;
	Slapi_Mods *smods = 0;
	Slapi_Mod *smod = NULL, *nextmod = NULL;
	LDAPMod **mods = NULL;
	char returntext[SLAPI_DSE_RETURNTEXT_SIZE];
	char *configarea_dn = NULL;
	int ret = SLAPI_PLUGIN_SUCCESS;

	slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn);

	if (slapi_sdn_compare(sdn, memberof_get_plugin_area()) == 0 ||
	    slapi_sdn_compare(sdn, memberof_get_config_area()) == 0)
	{
		slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &e);
		if(e){
			/*
			 * Create a copy of the entry and apply the
			 * mods to create the resulting entry.
			 */
			slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
			smods = slapi_mods_new();
			slapi_mods_init_byref(smods, mods);
			resulting_e = slapi_entry_dup(e);
			if (mods && (slapi_entry_apply_mods(resulting_e, mods) != LDAP_SUCCESS)) {
				/* we don't care about this, the update is invalid and will be caught later */
				goto bail;
			}

			if (slapi_sdn_compare(sdn, memberof_get_plugin_area())){
				/*
				 * This entry is a plugin config area entry, validate it.
				 */
				if( SLAPI_DSE_CALLBACK_ERROR == memberof_validate_config (pb, NULL, resulting_e, &ret, returntext,0)) {
					ret = LDAP_UNWILLING_TO_PERFORM;
				}
			} else {
				/*
				 * This is the memberOf plugin entry, check if we are adding/replacing the
				 * plugin config area.
				 */
				nextmod = slapi_mod_new();
				for (smod = slapi_mods_get_first_smod(smods, nextmod);
					 smod != NULL;
					 smod = slapi_mods_get_next_smod(smods, nextmod) )
				{
					if ( PL_strcasecmp(SLAPI_PLUGIN_SHARED_CONFIG_AREA, slapi_mod_get_type(smod)) == 0 )
					{
						/*
						 * Okay, we are modifying the plugin config area, we only care about
						 * adds and replaces.
						 */
						if(SLAPI_IS_MOD_REPLACE(slapi_mod_get_operation(smod)) ||
						   SLAPI_IS_MOD_ADD(slapi_mod_get_operation(smod)))
						{
						    struct berval *bv = NULL;
						    int rc = 0;

							bv = slapi_mod_get_first_value(smod);
							configarea_dn = slapi_ch_strdup(bv->bv_val);
							if(configarea_dn){
								/* Check the DN syntax */
								rc = slapi_dn_syntax_check(pb, configarea_dn, 1);
								if (rc) { /* syntax check failed */
									PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
										"%s does not contain a valid DN (%s)",
										SLAPI_PLUGIN_SHARED_CONFIG_AREA, configarea_dn);
									ret = LDAP_UNWILLING_TO_PERFORM;
									goto bail;
								}

								/* Check if the plugin config area entry exists */
								if((config_sdn = slapi_sdn_new_dn_byval(configarea_dn))){
									rc = slapi_search_internal_get_entry(config_sdn, NULL, &config_entry,
										memberof_get_plugin_id());
									if(config_entry){
										int err = 0;
										/*
										 * Validate the settings from the new config area.
										 */
										if ( memberof_validate_config(pb, NULL, config_entry, &err, returntext,0)
											 == SLAPI_DSE_CALLBACK_ERROR )
										{
											ret = LDAP_UNWILLING_TO_PERFORM;
											goto bail;

										}
									} else {
										/* The config area does not exist */
										PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
											"Unable to locate shared config entry (%s) error %d",
											slapi_sdn_get_dn(memberof_get_config_area()), rc);
										ret = LDAP_UNWILLING_TO_PERFORM;
										goto bail;
									}
								}
							}
							slapi_ch_free_string(&configarea_dn);
							slapi_sdn_free(&config_sdn);
						}
					}
				}
			}
		} else {
			PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,"Unable to locate shared config entry (%s)",
				slapi_sdn_get_dn(memberof_get_config_area()));
			ret = LDAP_UNWILLING_TO_PERFORM;
		}
   	}

bail:

	if (ret){
		slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ret);
		slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, returntext);
		slapi_log_err(SLAPI_LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM, "memberof_shared_config_validate - %s/n",
			returntext);
	}
	slapi_sdn_free(&config_sdn);
	if(nextmod)
		slapi_mod_free(&nextmod);
	slapi_mods_free(&smods);
	slapi_entry_free(resulting_e);
	slapi_entry_free(config_entry);
	slapi_ch_free_string(&configarea_dn);

	return ret;
}
コード例 #7
0
ファイル: parents.c プロジェクト: leto/389-ds
int
parent_update_on_childchange(modify_context *mc,int op, size_t *new_sub_count )
{
	int ret = 0;
	int mod_op = 0;
	Slapi_Attr	*read_attr = NULL;
	size_t current_sub_count = 0;
	int already_present = 0;
	int repl_op = 0;
	Slapi_Mods *smods = NULL;
	char value_buffer[20]; /* enough digits for 2^64 children */

	if (new_sub_count)
		*new_sub_count = 0;

	repl_op = PARENTUPDATE_TOMBSTONE_MASK & op;
	op &= PARENTUPDATE_MASK;

	/* Check nobody is trying to use op == 3, it's not implemented yet */
	PR_ASSERT( (op == PARENTUPDATE_ADD) || (op == PARENTUPDATE_DEL));

	/* We want to invent a mods set to be passed to modify_apply_mods() */

	/* For now, we're only interested in subordinatecount. 
	   We first examine the present value for the attribute. 
	   If it isn't present and we're adding, we assign value 1 to the attribute and add it.
	   If it is present, we increment or decrement depending upon whether we're adding or deleting.
	   If the value after decrementing is zero, we remove it.
	*/

	smods = slapi_mods_new();

	/* Get the present value of the subcount attr, or 0 if not present */
	ret = slapi_entry_attr_find(mc->old_entry->ep_entry,numsubordinates,&read_attr);
	if (0 == ret) {
		/* decode the value */
		Slapi_Value *sval;
		slapi_attr_first_value( read_attr, &sval );
		if (sval!=NULL) {
			const struct berval *bval = slapi_value_get_berval(sval);
			if(NULL != bval) {
			    already_present = 1;
			    current_sub_count = atol(bval->bv_val);
			}
		}
	}

	if (PARENTUPDATE_DELETE_TOMBSTONE != repl_op) {
		/* are we adding ? */
		if ( (PARENTUPDATE_ADD == op) && !already_present) {
			/* If so, and the parent entry does not already have a subcount 
			 * attribute, we need to add it */
			mod_op = LDAP_MOD_ADD;
		} else  if (PARENTUPDATE_DEL == op) {
			if (!already_present) {
				/* This means that something is wrong---deleting a child but no subcount present on parent */
				LDAPDebug0Args( LDAP_DEBUG_ANY,
				                "numsubordinates assertion failure\n" );
				slapi_mods_free(&smods);
				return -1;
			} else {
				if (current_sub_count == 1) {
					mod_op = LDAP_MOD_DELETE;
				} else {
					mod_op = LDAP_MOD_REPLACE;
				}
			}
		} else {
			/* (PARENTUPDATE_ADD == op) && already_present */
			mod_op = LDAP_MOD_REPLACE;
		}

		/* Now compute the new value */
		if (PARENTUPDATE_ADD == op) {
			current_sub_count++;
		} else {
			current_sub_count--;
		}

		if (mod_op == LDAP_MOD_DELETE) {
			slapi_mods_add(smods, mod_op | LDAP_MOD_BVALUES,
			               numsubordinates, 0, NULL);
		} else {
			sprintf(value_buffer,"%lu", current_sub_count);
			slapi_mods_add(smods, mod_op | LDAP_MOD_BVALUES, 
			               numsubordinates, strlen(value_buffer), value_buffer);
		}
		if (new_sub_count) {
			*new_sub_count = current_sub_count;
		}
	}

	/* tombstoneNumSubordinates is needed only when this is repl op
	 * and a child is being deleted */
	if (repl_op && (PARENTUPDATE_DEL == op)) {
		current_sub_count = LDAP_MAXINT;
		ret = slapi_entry_attr_find(mc->old_entry->ep_entry,
		                            tombstone_numsubordinates, &read_attr);
		if (0 == ret) {
			/* decode the value */
			Slapi_Value *sval;
			slapi_attr_first_value( read_attr, &sval );
			if (sval!=NULL) {
				const struct berval *bval = slapi_value_get_berval(sval);
				if(NULL != bval) {
					current_sub_count = atol(bval->bv_val);
				}
			}
		}

		if (PARENTUPDATE_DELETE_TOMBSTONE == repl_op) {
			/* deleting a tombstone entry: 
			 * reaping or manually deleting it */
			if ((current_sub_count != LDAP_MAXINT) && 
			    (current_sub_count > 0)) {
				current_sub_count--;
				mod_op = LDAP_MOD_REPLACE;
				sprintf(value_buffer,"%lu", current_sub_count);
				slapi_mods_add(smods, mod_op | LDAP_MOD_BVALUES, 
				               tombstone_numsubordinates,
				               strlen(value_buffer), value_buffer);
			}
		}

		if (PARENTUPDATE_CREATE_TOMBSTONE == repl_op) {
			/* creating a tombstone entry */
			if (current_sub_count != LDAP_MAXINT) {
				current_sub_count++;
			} else { /* tombstonenumsubordinates does not exist */
				current_sub_count = 1;
			}
			mod_op = LDAP_MOD_REPLACE;
			sprintf(value_buffer,"%lu", current_sub_count);
			slapi_mods_add(smods, mod_op | LDAP_MOD_BVALUES,
			               tombstone_numsubordinates, 
			               strlen(value_buffer), value_buffer);
		}
	}

	ret = modify_apply_mods(mc, smods); /* smods passed in */
	return ret;
}