+#define RUNQ_INTERVAL 36000 /* a long time */
+
+static MatchingRule *mr_dnSubtreeMatch;
+
+enum {
+ REFINT_ATTRS = 1,
+ REFINT_NOTHING,
+ REFINT_MODIFIERSNAME
+};
+
+static ConfigDriver refint_cf_gen;
+
+static ConfigTable refintcfg[] = {
+ { "refint_attributes", "attribute...", 2, 0, 0,
+ ARG_MAGIC|REFINT_ATTRS, refint_cf_gen,
+ "( OLcfgOvAt:11.1 NAME 'olcRefintAttribute' "
+ "DESC 'Attributes for referential integrity' "
+ "EQUALITY caseIgnoreMatch "
+ "SYNTAX OMsDirectoryString )", NULL, NULL },
+ { "refint_nothing", "string", 2, 2, 0,
+ ARG_DN|ARG_MAGIC|REFINT_NOTHING, refint_cf_gen,
+ "( OLcfgOvAt:11.2 NAME 'olcRefintNothing' "
+ "DESC 'Replacement DN to supply when needed' "
+ "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
+ { "refint_modifiersName", "DN", 2, 2, 0,
+ ARG_DN|ARG_MAGIC|REFINT_MODIFIERSNAME, refint_cf_gen,
+ "( OLcfgOvAt:11.3 NAME 'olcRefintModifiersName' "
+ "DESC 'The DN to use as modifiersName' "
+ "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
+ { NULL, NULL, 0, 0, 0, ARG_IGNORED }
+};
+
+static ConfigOCs refintocs[] = {
+ { "( OLcfgOvOc:11.1 "
+ "NAME 'olcRefintConfig' "
+ "DESC 'Referential integrity configuration' "
+ "SUP olcOverlayConfig "
+ "MAY ( olcRefintAttribute "
+ "$ olcRefintNothing "
+ "$ olcRefintModifiersName "
+ ") )",
+ Cft_Overlay, refintcfg },
+ { NULL, 0, NULL }
+};
+
+static int
+refint_cf_gen(ConfigArgs *c)
+{
+ slap_overinst *on = (slap_overinst *)c->bi;
+ refint_data *dd = (refint_data *)on->on_bi.bi_private;
+ refint_attrs *ip, *pip, **pipp = NULL;
+ AttributeDescription *ad;
+ const char *text;
+ int rc = ARG_BAD_CONF;
+ int i;
+
+ switch ( c->op ) {
+ case SLAP_CONFIG_EMIT:
+ switch ( c->type ) {
+ case REFINT_ATTRS:
+ ip = dd->attrs;
+ while ( ip ) {
+ value_add_one( &c->rvalue_vals,
+ &ip->attr->ad_cname );
+ ip = ip->next;
+ }
+ rc = 0;
+ break;
+ case REFINT_NOTHING:
+ if ( !BER_BVISEMPTY( &dd->nothing )) {
+ rc = value_add_one( &c->rvalue_vals,
+ &dd->nothing );
+ if ( rc ) return rc;
+ rc = value_add_one( &c->rvalue_nvals,
+ &dd->nnothing );
+ return rc;
+ }
+ rc = 0;
+ break;
+ case REFINT_MODIFIERSNAME:
+ if ( !BER_BVISEMPTY( &dd->refint_dn )) {
+ rc = value_add_one( &c->rvalue_vals,
+ &dd->refint_dn );
+ if ( rc ) return rc;
+ rc = value_add_one( &c->rvalue_nvals,
+ &dd->refint_ndn );
+ return rc;
+ }
+ rc = 0;
+ break;
+ default:
+ abort ();
+ }
+ break;
+ case LDAP_MOD_DELETE:
+ switch ( c->type ) {
+ case REFINT_ATTRS:
+ pipp = &dd->attrs;
+ if ( c->valx < 0 ) {
+ ip = *pipp;
+ *pipp = NULL;
+ while ( ip ) {
+ pip = ip;
+ ip = ip->next;
+ ch_free ( pip );
+ }
+ } else {
+ /* delete from linked list */
+ for ( i=0; i < c->valx; ++i ) {
+ pipp = &(*pipp)->next;
+ }
+ ip = *pipp;
+ *pipp = (*pipp)->next;
+
+ /* AttributeDescriptions are global so
+ * shouldn't be freed here... */
+ ch_free ( ip );
+ }
+ rc = 0;
+ break;
+ case REFINT_NOTHING:
+ if ( dd->nothing.bv_val )
+ ber_memfree ( dd->nothing.bv_val );
+ if ( dd->nnothing.bv_val )
+ ber_memfree ( dd->nnothing.bv_val );
+ dd->nothing.bv_len = 0;
+ dd->nnothing.bv_len = 0;
+ rc = 0;
+ break;
+ case REFINT_MODIFIERSNAME:
+ if ( dd->refint_dn.bv_val )
+ ber_memfree ( dd->refint_dn.bv_val );
+ if ( dd->refint_ndn.bv_val )
+ ber_memfree ( dd->refint_ndn.bv_val );
+ dd->refint_dn.bv_len = 0;
+ dd->refint_ndn.bv_len = 0;
+ rc = 0;
+ break;
+ default:
+ abort ();
+ }
+ break;
+ case SLAP_CONFIG_ADD:
+ /* fallthrough to LDAP_MOD_ADD */
+ case LDAP_MOD_ADD:
+ switch ( c->type ) {
+ case REFINT_ATTRS:
+ rc = 0;
+ for ( i=1; i < c->argc; ++i ) {
+ ad = NULL;
+ if ( slap_str2ad ( c->argv[i], &ad, &text )
+ == LDAP_SUCCESS) {
+ ip = ch_malloc (
+ sizeof ( refint_attrs ) );
+ ip->attr = ad;
+ ip->next = dd->attrs;
+ dd->attrs = ip;
+ } else {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "%s <%s>: %s", c->argv[0], c->argv[i], text );
+ Debug ( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
+ "%s: %s\n", c->log, c->cr_msg, 0 );
+ rc = ARG_BAD_CONF;
+ }
+ }
+ break;
+ case REFINT_NOTHING:
+ if ( dd->nothing.bv_val )
+ ber_memfree ( dd->nothing.bv_val );
+ if ( dd->nnothing.bv_val )
+ ber_memfree ( dd->nnothing.bv_val );
+ dd->nothing = c->value_dn;
+ dd->nnothing = c->value_ndn;
+ rc = 0;
+ break;
+ case REFINT_MODIFIERSNAME:
+ if ( dd->refint_dn.bv_val )
+ ber_memfree ( dd->refint_dn.bv_val );
+ if ( dd->refint_ndn.bv_val )
+ ber_memfree ( dd->refint_ndn.bv_val );
+ dd->refint_dn = c->value_dn;
+ dd->refint_ndn = c->value_ndn;
+ rc = 0;
+ break;
+ default:
+ abort ();
+ }
+ break;
+ default:
+ abort ();
+ }
+
+ return rc;
+}
+