/* Called for all modify and modrdn ops. If the current op was replicated * from elsewhere, all of the attrs should already be present. */ void slap_mods_opattrs( Operation *op, Modifications **modsp, int manage_ctxcsn ) { struct berval name, timestamp, csn = BER_BVNULL; struct berval nname; char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; char csnbuf[ LDAP_PVT_CSNSTR_BUFSIZE ]; Modifications *mod, **modtail, *modlast; int gotcsn = 0, gotmname = 0, gotmtime = 0; if ( SLAP_LASTMOD( op->o_bd ) && !op->orm_no_opattrs ) { char *ptr; timestamp.bv_val = timebuf; for ( modtail = modsp; *modtail; modtail = &(*modtail)->sml_next ) { if ( (*modtail)->sml_op != LDAP_MOD_ADD && (*modtail)->sml_op != SLAP_MOD_SOFTADD && (*modtail)->sml_op != SLAP_MOD_ADD_IF_NOT_PRESENT && (*modtail)->sml_op != LDAP_MOD_REPLACE ) { continue; } if ( (*modtail)->sml_desc == slap_schema.si_ad_entryCSN ) { csn = (*modtail)->sml_values[0]; gotcsn = 1; } else if ( (*modtail)->sml_desc == slap_schema.si_ad_modifiersName ) { gotmname = 1; } else if ( (*modtail)->sml_desc == slap_schema.si_ad_modifyTimestamp ) { gotmtime = 1; } } if ( BER_BVISEMPTY( &op->o_csn )) { if ( !gotcsn ) { csn.bv_val = csnbuf; csn.bv_len = sizeof( csnbuf ); slap_get_csn( op, &csn, manage_ctxcsn ); } else { if ( manage_ctxcsn ) { slap_queue_csn( op, &csn ); } } } else { csn = op->o_csn; } ptr = ber_bvchr( &csn, '#' ); if ( ptr ) { timestamp.bv_len = STRLENOF("YYYYMMDDHHMMSSZ"); AC_MEMCPY( timebuf, csn.bv_val, timestamp.bv_len ); timebuf[timestamp.bv_len-1] = 'Z'; timebuf[timestamp.bv_len] = '\0'; } else { time_t now = slap_get_time(); timestamp.bv_len = sizeof(timebuf); slap_timestamp( &now, ×tamp ); } if ( BER_BVISEMPTY( &op->o_dn ) ) { BER_BVSTR( &name, SLAPD_ANONYMOUS ); nname = name; } else { name = op->o_dn; nname = op->o_ndn; } if ( !gotcsn ) { mod = (Modifications *) ch_malloc( sizeof( Modifications ) ); mod->sml_op = LDAP_MOD_REPLACE; mod->sml_flags = SLAP_MOD_INTERNAL; mod->sml_next = NULL; BER_BVZERO( &mod->sml_type ); mod->sml_desc = slap_schema.si_ad_entryCSN; mod->sml_numvals = 1; mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); ber_dupbv( &mod->sml_values[0], &csn ); BER_BVZERO( &mod->sml_values[1] ); assert( !BER_BVISNULL( &mod->sml_values[0] ) ); mod->sml_nvalues = NULL; *modtail = mod; modlast = mod; modtail = &mod->sml_next; } if ( !gotmname ) { mod = (Modifications *) ch_malloc( sizeof( Modifications ) ); mod->sml_op = LDAP_MOD_REPLACE; mod->sml_flags = SLAP_MOD_INTERNAL; mod->sml_next = NULL; BER_BVZERO( &mod->sml_type ); mod->sml_desc = slap_schema.si_ad_modifiersName; mod->sml_numvals = 1; mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); ber_dupbv( &mod->sml_values[0], &name ); BER_BVZERO( &mod->sml_values[1] ); assert( !BER_BVISNULL( &mod->sml_values[0] ) ); mod->sml_nvalues = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); ber_dupbv( &mod->sml_nvalues[0], &nname ); BER_BVZERO( &mod->sml_nvalues[1] ); assert( !BER_BVISNULL( &mod->sml_nvalues[0] ) ); *modtail = mod; modtail = &mod->sml_next; } if ( !gotmtime ) { mod = (Modifications *) ch_malloc( sizeof( Modifications ) ); mod->sml_op = LDAP_MOD_REPLACE; mod->sml_flags = SLAP_MOD_INTERNAL; mod->sml_next = NULL; BER_BVZERO( &mod->sml_type ); mod->sml_desc = slap_schema.si_ad_modifyTimestamp; mod->sml_numvals = 1; mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); ber_dupbv( &mod->sml_values[0], ×tamp ); BER_BVZERO( &mod->sml_values[1] ); assert( !BER_BVISNULL( &mod->sml_values[0] ) ); mod->sml_nvalues = NULL; *modtail = mod; modtail = &mod->sml_next; } } }
int schema_info( Entry **entry, const char **text ) { AttributeDescription *ad_structuralObjectClass = slap_schema.si_ad_structuralObjectClass; AttributeDescription *ad_objectClass = slap_schema.si_ad_objectClass; AttributeDescription *ad_createTimestamp = slap_schema.si_ad_createTimestamp; AttributeDescription *ad_modifyTimestamp = slap_schema.si_ad_modifyTimestamp; Entry *e; struct berval vals[5]; struct berval nvals[5]; e = entry_alloc(); if( e == NULL ) { /* Out of memory, do something about it */ Debug( LDAP_DEBUG_ANY, "schema_info: entry_alloc failed - out of memory.\n", 0, 0, 0 ); *text = "out of memory"; return LDAP_OTHER; } e->e_attrs = NULL; /* backend-specific schema info should be created by the * backend itself */ ber_dupbv( &e->e_name, &frontendDB->be_schemadn ); ber_dupbv( &e->e_nname, &frontendDB->be_schemandn ); e->e_private = NULL; BER_BVSTR( &vals[0], "subentry" ); if( attr_merge_one( e, ad_structuralObjectClass, vals, NULL ) ) { /* Out of memory, do something about it */ entry_free( e ); *text = "out of memory"; return LDAP_OTHER; } BER_BVSTR( &vals[0], "top" ); BER_BVSTR( &vals[1], "subentry" ); BER_BVSTR( &vals[2], "subschema" ); BER_BVSTR( &vals[3], "extensibleObject" ); BER_BVZERO( &vals[4] ); if ( attr_merge( e, ad_objectClass, vals, NULL ) ) { /* Out of memory, do something about it */ entry_free( e ); *text = "out of memory"; return LDAP_OTHER; } { int rc; AttributeDescription *desc = NULL; struct berval rdn = frontendDB->be_schemadn; vals[0].bv_val = ber_bvchr( &rdn, '=' ); if( vals[0].bv_val == NULL ) { *text = "improperly configured subschema subentry"; return LDAP_OTHER; } vals[0].bv_val++; vals[0].bv_len = rdn.bv_len - (vals[0].bv_val - rdn.bv_val); rdn.bv_len -= vals[0].bv_len + 1; rc = slap_bv2ad( &rdn, &desc, text ); if( rc != LDAP_SUCCESS ) { entry_free( e ); *text = "improperly configured subschema subentry"; return LDAP_OTHER; } nvals[0].bv_val = ber_bvchr( &frontendDB->be_schemandn, '=' ); assert( nvals[0].bv_val != NULL ); nvals[0].bv_val++; nvals[0].bv_len = frontendDB->be_schemandn.bv_len - (nvals[0].bv_val - frontendDB->be_schemandn.bv_val); if ( attr_merge_one( e, desc, vals, nvals ) ) { /* Out of memory, do something about it */ entry_free( e ); *text = "out of memory"; return LDAP_OTHER; } } { char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; /* * According to RFC 4512: Servers SHOULD maintain the 'creatorsName', 'createTimestamp', 'modifiersName', and 'modifyTimestamp' attributes for all entries of the DIT. * to be conservative, we declare schema created * AND modified at server startup time ... */ vals[0].bv_val = timebuf; vals[0].bv_len = sizeof( timebuf ); slap_timestamp( &starttime, vals ); if( attr_merge_one( e, ad_createTimestamp, vals, NULL ) ) { /* Out of memory, do something about it */ entry_free( e ); *text = "out of memory"; return LDAP_OTHER; } if( attr_merge_one( e, ad_modifyTimestamp, vals, NULL ) ) { /* Out of memory, do something about it */ entry_free( e ); *text = "out of memory"; return LDAP_OTHER; } } if ( syn_schema_info( e ) || mr_schema_info( e ) || mru_schema_info( e ) || at_schema_info( e ) || oc_schema_info( e ) || cr_schema_info( e ) ) { /* Out of memory, do something about it */ entry_free( e ); *text = "out of memory"; return LDAP_OTHER; } *entry = e; return LDAP_SUCCESS; }
int slapadd( int argc, char **argv ) { char *buf = NULL; const char *text; char textbuf[SLAP_TEXT_BUFLEN] = { '\0' }; size_t textlen = sizeof textbuf; const char *progname = "slapadd"; struct berval csn; struct berval maxcsn[ SLAP_SYNC_SID_MAX + 1 ]; unsigned long sid; struct berval bvtext; Attribute *attr; Entry *ctxcsn_e; ID ctxcsn_id, id; OperationBuffer opbuf; Operation *op; int match; int checkvals; int lineno, nextline; int lmax; int rc = EXIT_SUCCESS; int manage = 0; /* default "000" */ csnsid = 0; slap_tool_init( progname, SLAPADD, argc, argv ); memset( &opbuf, 0, sizeof(opbuf) ); op = &opbuf.ob_op; op->o_hdr = &opbuf.ob_hdr; if( !be->be_entry_open || !be->be_entry_close || !be->be_entry_put || (update_ctxcsn && (!be->be_dn2id_get || !be->be_entry_get || !be->be_entry_modify)) ) { fprintf( stderr, "%s: database doesn't support necessary operations.\n", progname ); if ( dryrun ) { fprintf( stderr, "\t(dry) continuing...\n" ); } else { exit( EXIT_FAILURE ); } } checkvals = (slapMode & SLAP_TOOL_QUICK) ? 0 : 1; lmax = 0; nextline = 0; /* enforce schema checking unless not disabled */ if ( (slapMode & SLAP_TOOL_NO_SCHEMA_CHECK) == 0) { SLAP_DBFLAGS(be) &= ~(SLAP_DBFLAG_NO_SCHEMA_CHECK); } if( !dryrun && be->be_entry_open( be, 1 ) != 0 ) { fprintf( stderr, "%s: could not open database.\n", progname ); exit( EXIT_FAILURE ); } if ( update_ctxcsn ) { maxcsn[ 0 ].bv_val = maxcsnbuf; for ( sid = 1; sid <= SLAP_SYNC_SID_MAX; sid++ ) { maxcsn[ sid ].bv_val = maxcsn[ sid - 1 ].bv_val + LDAP_LUTIL_CSNSTR_BUFSIZE; maxcsn[ sid ].bv_len = 0; } } /* nextline is the line number of the end of the current entry */ for( lineno=1; ldif_read_record( ldiffp, &nextline, &buf, &lmax ); lineno=nextline+1 ) { Entry *e; if ( lineno < jumpline ) continue; e = str2entry2( buf, checkvals ); /* * Initialize text buffer */ bvtext.bv_len = textlen; bvtext.bv_val = textbuf; bvtext.bv_val[0] = '\0'; if( e == NULL ) { fprintf( stderr, "%s: could not parse entry (line=%d)\n", progname, lineno ); rc = EXIT_FAILURE; if( continuemode ) continue; break; } /* make sure the DN is not empty */ if( BER_BVISEMPTY( &e->e_nname ) && !BER_BVISEMPTY( be->be_nsuffix )) { fprintf( stderr, "%s: empty dn=\"%s\" (line=%d)\n", progname, e->e_dn, lineno ); rc = EXIT_FAILURE; entry_free( e ); if( continuemode ) continue; break; } /* check backend */ if( select_backend( &e->e_nname, nosubordinates ) != be ) { fprintf( stderr, "%s: line %d: " "database (%s) not configured to hold \"%s\"\n", progname, lineno, be ? be->be_suffix[0].bv_val : "<none>", e->e_dn ); fprintf( stderr, "%s: line %d: " "database (%s) not configured to hold \"%s\"\n", progname, lineno, be ? be->be_nsuffix[0].bv_val : "<none>", e->e_ndn ); rc = EXIT_FAILURE; entry_free( e ); if( continuemode ) continue; break; } { Attribute *oc = attr_find( e->e_attrs, slap_schema.si_ad_objectClass ); if( oc == NULL ) { fprintf( stderr, "%s: dn=\"%s\" (line=%d): %s\n", progname, e->e_dn, lineno, "no objectClass attribute"); rc = EXIT_FAILURE; entry_free( e ); if( continuemode ) continue; break; } /* check schema */ op->o_bd = be; if ( (slapMode & SLAP_TOOL_NO_SCHEMA_CHECK) == 0) { rc = entry_schema_check( op, e, NULL, manage, 1, &text, textbuf, textlen ); if( rc != LDAP_SUCCESS ) { fprintf( stderr, "%s: dn=\"%s\" (line=%d): (%d) %s\n", progname, e->e_dn, lineno, rc, text ); rc = EXIT_FAILURE; entry_free( e ); if( continuemode ) continue; break; } textbuf[ 0 ] = '\0'; } } if ( SLAP_LASTMOD(be) ) { time_t now = slap_get_time(); char uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ]; struct berval vals[ 2 ]; struct berval name, timestamp; struct berval nvals[ 2 ]; struct berval nname; char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; vals[1].bv_len = 0; vals[1].bv_val = NULL; nvals[1].bv_len = 0; nvals[1].bv_val = NULL; csn.bv_len = lutil_csnstr( csnbuf, sizeof( csnbuf ), csnsid, 0 ); csn.bv_val = csnbuf; timestamp.bv_val = timebuf; timestamp.bv_len = sizeof(timebuf); slap_timestamp( &now, ×tamp ); if ( BER_BVISEMPTY( &be->be_rootndn ) ) { BER_BVSTR( &name, SLAPD_ANONYMOUS ); nname = name; } else { name = be->be_rootdn; nname = be->be_rootndn; } if( attr_find( e->e_attrs, slap_schema.si_ad_entryUUID ) == NULL ) { vals[0].bv_len = lutil_uuidstr( uuidbuf, sizeof( uuidbuf ) ); vals[0].bv_val = uuidbuf; attr_merge_normalize_one( e, slap_schema.si_ad_entryUUID, vals, NULL ); } if( attr_find( e->e_attrs, slap_schema.si_ad_creatorsName ) == NULL ) { vals[0] = name; nvals[0] = nname; attr_merge( e, slap_schema.si_ad_creatorsName, vals, nvals ); } if( attr_find( e->e_attrs, slap_schema.si_ad_createTimestamp ) == NULL ) { vals[0] = timestamp; attr_merge( e, slap_schema.si_ad_createTimestamp, vals, NULL ); } if( attr_find( e->e_attrs, slap_schema.si_ad_entryCSN ) == NULL ) { vals[0] = csn; attr_merge( e, slap_schema.si_ad_entryCSN, vals, NULL ); } if( attr_find( e->e_attrs, slap_schema.si_ad_modifiersName ) == NULL ) { vals[0] = name; nvals[0] = nname; attr_merge( e, slap_schema.si_ad_modifiersName, vals, nvals ); } if( attr_find( e->e_attrs, slap_schema.si_ad_modifyTimestamp ) == NULL ) { vals[0] = timestamp; attr_merge( e, slap_schema.si_ad_modifyTimestamp, vals, NULL ); } if ( update_ctxcsn ) { int rc_sid; attr = attr_find( e->e_attrs, slap_schema.si_ad_entryCSN ); assert( attr != NULL ); rc_sid = slap_parse_csn_sid( &attr->a_nvals[ 0 ] ); if ( rc_sid < 0 ) { Debug( LDAP_DEBUG_ANY, "%s: could not " "extract SID from entryCSN=%s\n", progname, attr->a_nvals[ 0 ].bv_val, 0 ); } else { assert( rc_sid <= SLAP_SYNC_SID_MAX ); sid = (unsigned)rc_sid; if ( maxcsn[ sid ].bv_len != 0 ) { match = 0; value_match( &match, slap_schema.si_ad_entryCSN, slap_schema.si_ad_entryCSN->ad_type->sat_ordering, SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, &maxcsn[ sid ], &attr->a_nvals[0], &text ); } else { match = -1; } if ( match < 0 ) { strcpy( maxcsn[ sid ].bv_val, attr->a_nvals[0].bv_val ); maxcsn[ sid ].bv_len = attr->a_nvals[0].bv_len; } } } } if ( !dryrun ) { id = be->be_entry_put( be, e, &bvtext ); if( id == NOID ) { fprintf( stderr, "%s: could not add entry dn=\"%s\" " "(line=%d): %s\n", progname, e->e_dn, lineno, bvtext.bv_val ); rc = EXIT_FAILURE; entry_free( e ); if( continuemode ) continue; break; } if ( verbose ) fprintf( stderr, "added: \"%s\" (%08lx)\n", e->e_dn, (long) id ); } else { if ( verbose ) fprintf( stderr, "added: \"%s\"\n", e->e_dn ); } entry_free( e ); } bvtext.bv_len = textlen; bvtext.bv_val = textbuf; bvtext.bv_val[0] = '\0'; if ( rc == EXIT_SUCCESS && update_ctxcsn && !dryrun && sid != SLAP_SYNC_SID_MAX + 1 ) { ctxcsn_id = be->be_dn2id_get( be, be->be_nsuffix ); if ( ctxcsn_id == NOID ) { fprintf( stderr, "%s: context entry is missing\n", progname ); rc = EXIT_FAILURE; } else { ctxcsn_e = be->be_entry_get( be, ctxcsn_id ); if ( ctxcsn_e != NULL ) { Entry *e = entry_dup( ctxcsn_e ); int change; attr = attr_find( e->e_attrs, slap_schema.si_ad_contextCSN ); if ( attr ) { int i; change = 0; for ( i = 0; !BER_BVISNULL( &attr->a_nvals[ i ] ); i++ ) { int rc_sid; rc_sid = slap_parse_csn_sid( &attr->a_nvals[ i ] ); if ( rc_sid < 0 ) { Debug( LDAP_DEBUG_ANY, "%s: unable to extract SID " "from #%d contextCSN=%s\n", progname, i, attr->a_nvals[ i ].bv_val ); continue; } assert( rc_sid <= SLAP_SYNC_SID_MAX ); sid = (unsigned)rc_sid; if ( maxcsn[ sid ].bv_len == 0 ) { match = -1; } else { value_match( &match, slap_schema.si_ad_entryCSN, slap_schema.si_ad_entryCSN->ad_type->sat_ordering, SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, &maxcsn[ sid ], &attr->a_nvals[i], &text ); } if ( match > 0 ) { change = 1; } else { AC_MEMCPY( maxcsn[ sid ].bv_val, attr->a_nvals[ i ].bv_val, attr->a_nvals[ i ].bv_len ); maxcsn[ sid ].bv_val[ attr->a_nvals[ i ].bv_len ] = '\0'; maxcsn[ sid ].bv_len = attr->a_nvals[ i ].bv_len; } } if ( change ) { if ( attr->a_nvals != attr->a_vals ) { ber_bvarray_free( attr->a_nvals ); } attr->a_nvals = NULL; ber_bvarray_free( attr->a_vals ); attr->a_vals = NULL; attr->a_numvals = 0; } } else { change = 1; } if ( change ) { for ( sid = 0; sid <= SLAP_SYNC_SID_MAX; sid++ ) { if ( maxcsn[ sid ].bv_len ) { attr_merge_one( e, slap_schema.si_ad_contextCSN, &maxcsn[ sid], NULL ); } } ctxcsn_id = be->be_entry_modify( be, e, &bvtext ); if( ctxcsn_id == NOID ) { fprintf( stderr, "%s: could not modify ctxcsn\n", progname); rc = EXIT_FAILURE; } else if ( verbose ) { fprintf( stderr, "modified: \"%s\" (%08lx)\n", e->e_dn, (long) ctxcsn_id ); } } entry_free( e ); } } } ch_free( buf ); if ( !dryrun ) { if( be->be_entry_close( be ) ) { rc = EXIT_FAILURE; } if( be->be_sync ) { be->be_sync( be ); } } slap_tool_destroy(); return rc; }
/* * call from within ldap_back_db_open() */ int ldap_back_monitor_db_open( BackendDB *be ) { ldapinfo_t *li = (ldapinfo_t *) be->be_private; char buf[ BACKMONITOR_BUFSIZE ]; Entry *e = NULL; monitor_callback_t *cb = NULL; struct berval suffix, *filter, *base; char *ptr; time_t now; char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; struct berval timestamp; int rc = 0; BackendInfo *mi; monitor_extra_t *mbe; if ( !SLAP_DBMONITORING( be ) ) { return 0; } /* check if monitor is configured and usable */ mi = backend_info( "monitor" ); if ( !mi || !mi->bi_extra ) { SLAP_DBFLAGS( be ) ^= SLAP_DBFLAG_MONITORING; return 0; } mbe = mi->bi_extra; /* don't bother if monitor is not configured */ if ( !mbe->is_configured() ) { static int warning = 0; if ( warning++ == 0 ) { Debug( LDAP_DEBUG_ANY, "ldap_back_monitor_db_open: " "monitoring disabled; " "configure monitor database to enable\n", 0, 0, 0 ); } return 0; } /* set up the fake subsystem that is used to create * the volatile connection entries */ li->li_monitor_info.lmi_mss.mss_name = "back-ldap"; li->li_monitor_info.lmi_mss.mss_flags = MONITOR_F_VOLATILE_CH; li->li_monitor_info.lmi_mss.mss_create = ldap_back_monitor_conn_create; li->li_monitor_info.lmi_li = li; li->li_monitor_info.lmi_scope = LDAP_SCOPE_SUBORDINATE; base = &li->li_monitor_info.lmi_base; BER_BVSTR( base, "cn=databases,cn=monitor" ); filter = &li->li_monitor_info.lmi_filter; BER_BVZERO( filter ); suffix.bv_len = ldap_bv2escaped_filter_value_len( &be->be_nsuffix[ 0 ] ); if ( suffix.bv_len == be->be_nsuffix[ 0 ].bv_len ) { suffix = be->be_nsuffix[ 0 ]; } else { ldap_bv2escaped_filter_value( &be->be_nsuffix[ 0 ], &suffix ); } filter->bv_len = STRLENOF( "(&" ) + li->li_monitor_info.lmi_more_filter.bv_len + STRLENOF( "(monitoredInfo=" ) + strlen( be->bd_info->bi_type ) + STRLENOF( ")(!(monitorOverlay=" ) + strlen( be->bd_info->bi_type ) + STRLENOF( "))(namingContexts:distinguishedNameMatch:=" ) + suffix.bv_len + STRLENOF( "))" ); ptr = filter->bv_val = ch_malloc( filter->bv_len + 1 ); ptr = lutil_strcopy( ptr, "(&" ); ptr = lutil_strncopy( ptr, li->li_monitor_info.lmi_more_filter.bv_val, li->li_monitor_info.lmi_more_filter.bv_len ); ptr = lutil_strcopy( ptr, "(monitoredInfo=" ); ptr = lutil_strcopy( ptr, be->bd_info->bi_type ); ptr = lutil_strcopy( ptr, ")(!(monitorOverlay=" ); ptr = lutil_strcopy( ptr, be->bd_info->bi_type ); ptr = lutil_strcopy( ptr, "))(namingContexts:distinguishedNameMatch:=" ); ptr = lutil_strncopy( ptr, suffix.bv_val, suffix.bv_len ); ptr = lutil_strcopy( ptr, "))" ); ptr[ 0 ] = '\0'; assert( ptr == &filter->bv_val[ filter->bv_len ] ); if ( suffix.bv_val != be->be_nsuffix[ 0 ].bv_val ) { ch_free( suffix.bv_val ); } now = slap_get_time(); timestamp.bv_val = timebuf; timestamp.bv_len = sizeof( timebuf ); slap_timestamp( &now, ×tamp ); /* caller (e.g. an overlay based on back-ldap) may want to use * a different RDN... */ if ( BER_BVISNULL( &li->li_monitor_info.lmi_rdn ) ) { ber_str2bv( "cn=Connections", 0, 1, &li->li_monitor_info.lmi_rdn ); } ptr = ber_bvchr( &li->li_monitor_info.lmi_rdn, '=' ); assert( ptr != NULL ); ptr[ 0 ] = '\0'; ptr++; snprintf( buf, sizeof( buf ), "dn: %s=%s\n" "objectClass: monitorContainer\n" "%s: %s\n" "creatorsName: %s\n" "createTimestamp: %s\n" "modifiersName: %s\n" "modifyTimestamp: %s\n", li->li_monitor_info.lmi_rdn.bv_val, ptr, li->li_monitor_info.lmi_rdn.bv_val, ptr, BER_BVISNULL( &be->be_rootdn ) ? SLAPD_ANONYMOUS : be->be_rootdn.bv_val, timestamp.bv_val, BER_BVISNULL( &be->be_rootdn ) ? SLAPD_ANONYMOUS : be->be_rootdn.bv_val, timestamp.bv_val ); e = str2entry( buf ); if ( e == NULL ) { rc = -1; goto cleanup; } ptr[ -1 ] = '='; /* add labeledURI and special, modifiable URI value */ if ( li->li_uri != NULL ) { struct berval bv; LDAPURLDesc *ludlist = NULL; int rc; rc = ldap_url_parselist_ext( &ludlist, li->li_uri, NULL, LDAP_PVT_URL_PARSE_NOEMPTY_HOST | LDAP_PVT_URL_PARSE_DEF_PORT ); if ( rc != LDAP_URL_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "ldap_back_monitor_db_open: " "unable to parse URI list (ignored)\n", 0, 0, 0 ); } else { for ( ; ludlist != NULL; ) { LDAPURLDesc *next = ludlist->lud_next; bv.bv_val = ldap_url_desc2str( ludlist ); assert( bv.bv_val != NULL ); ldap_free_urldesc( ludlist ); bv.bv_len = strlen( bv.bv_val ); attr_merge_normalize_one( e, slap_schema.si_ad_labeledURI, &bv, NULL ); ch_free( bv.bv_val ); ludlist = next; } } ber_str2bv( li->li_uri, 0, 0, &bv ); attr_merge_normalize_one( e, ad_olmDbURIList, &bv, NULL ); } ber_dupbv( &li->li_monitor_info.lmi_nrdn, &e->e_nname ); cb = ch_calloc( sizeof( monitor_callback_t ), 1 ); cb->mc_update = ldap_back_monitor_update; cb->mc_modify = ldap_back_monitor_modify; cb->mc_free = ldap_back_monitor_free; cb->mc_private = (void *)li; rc = mbe->register_entry_parent( e, cb, (monitor_subsys_t *)&li->li_monitor_info, MONITOR_F_VOLATILE_CH, base, LDAP_SCOPE_SUBORDINATE, filter ); cleanup:; if ( rc != 0 ) { if ( cb != NULL ) { ch_free( cb ); cb = NULL; } if ( e != NULL ) { entry_free( e ); e = NULL; } if ( !BER_BVISNULL( filter ) ) { ch_free( filter->bv_val ); BER_BVZERO( filter ); } } /* store for cleanup */ li->li_monitor_info.lmi_cb = (void *)cb; if ( e != NULL ) { entry_free( e ); } return rc; }
static int pam_sess(nssov_info *ni,TFILE *fp,Operation *op,int action) { struct berval dn, uid, svc, tty, rhost, ruser; int32_t tmpint32; char dnc[1024]; char svcc[256]; char uidc[32]; char ttyc[32]; char rhostc[256]; char ruserc[32]; slap_callback cb = {0}; SlapReply rs = {REP_RESULT}; char timebuf[LDAP_LUTIL_GENTIME_BUFSIZE]; struct berval timestamp, bv[2], *nbv; time_t stamp; Modifications mod; READ_STRING(fp,uidc); uid.bv_val = uidc; uid.bv_len = tmpint32; READ_STRING(fp,dnc); dn.bv_val = dnc; dn.bv_len = tmpint32; READ_STRING(fp,svcc); svc.bv_val = svcc; svc.bv_len = tmpint32; READ_STRING(fp,ttyc); tty.bv_val = ttyc; tty.bv_len = tmpint32; READ_STRING(fp,rhostc); rhost.bv_val = rhostc; rhost.bv_len = tmpint32; READ_STRING(fp,ruserc); ruser.bv_val = ruserc; ruser.bv_len = tmpint32; READ_INT32(fp,stamp); Debug(LDAP_DEBUG_TRACE,"nssov_pam_sess_%c(%s)\n", action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c', dn.bv_val,0); if (!dn.bv_len || !ni->ni_pam_sessions) return 0; { int i, found=0; for (i=0; !BER_BVISNULL(&ni->ni_pam_sessions[i]); i++) { if (ni->ni_pam_sessions[i].bv_len != svc.bv_len) continue; if (!strcasecmp(ni->ni_pam_sessions[i].bv_val, svc.bv_val)) { found = 1; break; } } if (!found) return 0; } slap_op_time( &op->o_time, &op->o_tincr ); timestamp.bv_len = sizeof(timebuf); timestamp.bv_val = timebuf; if (action == NSLCD_ACTION_PAM_SESS_O ) stamp = op->o_time; slap_timestamp( &stamp, ×tamp ); bv[0].bv_len = timestamp.bv_len + global_host_bv.bv_len + svc.bv_len + tty.bv_len + ruser.bv_len + rhost.bv_len + STRLENOF(" (@)"); bv[0].bv_val = op->o_tmpalloc( bv[0].bv_len+1, op->o_tmpmemctx ); sprintf(bv[0].bv_val, "%s %s %s %s (%s@%s)", timestamp.bv_val, global_host_bv.bv_val, svc.bv_val, tty.bv_val, ruser.bv_val, rhost.bv_val); mod.sml_numvals = 1; mod.sml_values = bv; BER_BVZERO(&bv[1]); attr_normalize( ad_loginStatus, bv, &nbv, op->o_tmpmemctx ); mod.sml_nvalues = nbv; mod.sml_desc = ad_loginStatus; mod.sml_op = action == NSLCD_ACTION_PAM_SESS_O ? LDAP_MOD_ADD : LDAP_MOD_DELETE; mod.sml_flags = SLAP_MOD_INTERNAL; mod.sml_next = NULL; cb.sc_response = slap_null_cb; op->o_callback = &cb; op->o_tag = LDAP_REQ_MODIFY; op->o_dn = op->o_bd->be_rootdn; op->o_ndn = op->o_bd->be_rootndn; op->orm_modlist = &mod; op->orm_no_opattrs = 1; op->o_req_dn = dn; op->o_req_ndn = dn; op->o_bd->be_modify( op, &rs ); if ( mod.sml_next ) { slap_mods_free( mod.sml_next, 1 ); } ber_bvarray_free_x( nbv, op->o_tmpmemctx ); WRITE_INT32(fp,NSLCD_VERSION); WRITE_INT32(fp,action); WRITE_INT32(fp,NSLCD_RESULT_BEGIN); WRITE_INT32(fp,op->o_time); return 0; }
static int lastbind_bind_response( Operation *op, SlapReply *rs ) { Modifications *mod = NULL; BackendInfo *bi = op->o_bd->bd_info; Entry *e; int rc; /* we're only interested if the bind was successful */ if ( rs->sr_err != LDAP_SUCCESS ) return SLAP_CB_CONTINUE; rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e ); op->o_bd->bd_info = bi; if ( rc != LDAP_SUCCESS ) { return SLAP_CB_CONTINUE; } { lastbind_info *lbi = (lastbind_info *) op->o_callback->sc_private; time_t now, bindtime = (time_t)-1; Attribute *a; Modifications *m; char nowstr[ LDAP_LUTIL_GENTIME_BUFSIZE ]; struct berval timestamp; /* get the current time */ now = slap_get_time(); /* get authTimestamp attribute, if it exists */ if ((a = attr_find( e->e_attrs, ad_authTimestamp)) != NULL) { bindtime = parse_time( a->a_nvals[0].bv_val ); if (bindtime != (time_t)-1) { /* if the recorded bind time is within our precision, we're done * it doesn't need to be updated (save a write for nothing) */ if ((now - bindtime) < lbi->timestamp_precision) { goto done; } } } /* update the authTimestamp in the user's entry with the current time */ timestamp.bv_val = nowstr; timestamp.bv_len = sizeof(nowstr); slap_timestamp( &now, ×tamp ); m = ch_calloc( sizeof(Modifications), 1 ); m->sml_op = LDAP_MOD_REPLACE; m->sml_flags = 0; m->sml_type = ad_authTimestamp->ad_cname; m->sml_desc = ad_authTimestamp; m->sml_numvals = 1; m->sml_values = ch_calloc( sizeof(struct berval), 2 ); m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 ); ber_dupbv( &m->sml_values[0], ×tamp ); ber_dupbv( &m->sml_nvalues[0], ×tamp ); m->sml_next = mod; mod = m; } done: be_entry_release_r( op, e ); /* perform the update, if necessary */ if ( mod ) { Operation op2 = *op; SlapReply r2 = { REP_RESULT }; slap_callback cb = { NULL, slap_null_cb, NULL, NULL }; /* This is a DSA-specific opattr, it never gets replicated. */ op2.o_tag = LDAP_REQ_MODIFY; op2.o_callback = &cb; op2.orm_modlist = mod; op2.o_dn = op->o_bd->be_rootdn; op2.o_ndn = op->o_bd->be_rootndn; op2.o_dont_replicate = 1; rc = op->o_bd->be_modify( &op2, &r2 ); slap_mods_free( mod, 1 ); } op->o_bd->bd_info = bi; return SLAP_CB_CONTINUE; }
static int dds_op_modify( Operation *op, SlapReply *rs ) { slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; dds_info_t *di = (dds_info_t *)on->on_bi.bi_private; Modifications *mod; Entry *e = NULL; BackendInfo *bi = op->o_bd->bd_info; int was_dynamicObject = 0, is_dynamicObject = 0; struct berval bv_entryTtl = BER_BVNULL; time_t entryTtl = 0; char textbuf[ SLAP_TEXT_BUFLEN ]; if ( DDS_OFF( di ) ) { return SLAP_CB_CONTINUE; } /* bv_entryTtl stores the string representation of the entryTtl * across modifies for consistency checks of the final value; * the bv_val points to a static buffer; the bv_len is zero when * the attribute is deleted. * entryTtl stores the integer representation of the entryTtl; * its value is -1 when the attribute is deleted; it is 0 only * if no modifications of the entryTtl occurred, as an entryTtl * of 0 is invalid. */ bv_entryTtl.bv_val = textbuf; op->o_bd->bd_info = (BackendInfo *)on->on_info; rs->sr_err = be_entry_get_rw( op, &op->o_req_ndn, slap_schema.si_oc_dynamicObject, slap_schema.si_ad_entryTtl, 0, &e ); if ( rs->sr_err == LDAP_SUCCESS && e != NULL ) { Attribute *a = attr_find( e->e_attrs, slap_schema.si_ad_entryTtl ); /* the value of the entryTtl is saved for later checks */ if ( a != NULL ) { unsigned long ttl; int rc; bv_entryTtl.bv_len = a->a_nvals[ 0 ].bv_len; memcpy( bv_entryTtl.bv_val, a->a_nvals[ 0 ].bv_val, bv_entryTtl.bv_len ); bv_entryTtl.bv_val[ bv_entryTtl.bv_len ] = '\0'; rc = lutil_atoul( &ttl, bv_entryTtl.bv_val ); assert( rc == 0 ); entryTtl = (time_t)ttl; } be_entry_release_r( op, e ); e = NULL; was_dynamicObject = is_dynamicObject = 1; } op->o_bd->bd_info = bi; rs->sr_err = LDAP_SUCCESS; for ( mod = op->orm_modlist; mod; mod = mod->sml_next ) { if ( mod->sml_desc == slap_schema.si_ad_objectClass ) { int i; ObjectClass *oc; switch ( mod->sml_op ) { case LDAP_MOD_DELETE: if ( mod->sml_values == NULL ) { is_dynamicObject = 0; break; } for ( i = 0; !BER_BVISNULL( &mod->sml_values[ i ] ); i++ ) { oc = oc_bvfind( &mod->sml_values[ i ] ); if ( oc == slap_schema.si_oc_dynamicObject ) { is_dynamicObject = 0; break; } } break; case LDAP_MOD_REPLACE: if ( mod->sml_values == NULL ) { is_dynamicObject = 0; break; } /* fallthru */ case LDAP_MOD_ADD: for ( i = 0; !BER_BVISNULL( &mod->sml_values[ i ] ); i++ ) { oc = oc_bvfind( &mod->sml_values[ i ] ); if ( oc == slap_schema.si_oc_dynamicObject ) { is_dynamicObject = 1; break; } } break; } } else if ( mod->sml_desc == slap_schema.si_ad_entryTtl ) { unsigned long uttl; time_t ttl; int rc; switch ( mod->sml_op ) { case LDAP_MOD_DELETE: case SLAP_MOD_SOFTDEL: /* FIXME? */ if ( mod->sml_values != NULL ) { if ( BER_BVISEMPTY( &bv_entryTtl ) || !bvmatch( &bv_entryTtl, &mod->sml_values[ 0 ] ) ) { rs->sr_err = backend_attribute( op, NULL, &op->o_req_ndn, slap_schema.si_ad_entry, NULL, ACL_DISCLOSE ); if ( rs->sr_err == LDAP_INSUFFICIENT_ACCESS ) { rs->sr_err = LDAP_NO_SUCH_OBJECT; } else { rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE; } goto done; } } bv_entryTtl.bv_len = 0; entryTtl = -1; break; case LDAP_MOD_REPLACE: bv_entryTtl.bv_len = 0; entryTtl = -1; /* fallthru */ case LDAP_MOD_ADD: case SLAP_MOD_SOFTADD: /* FIXME? */ case SLAP_MOD_ADD_IF_NOT_PRESENT: /* FIXME? */ assert( mod->sml_values != NULL ); assert( BER_BVISNULL( &mod->sml_values[ 1 ] ) ); if ( !BER_BVISEMPTY( &bv_entryTtl ) ) { rs->sr_err = backend_attribute( op, NULL, &op->o_req_ndn, slap_schema.si_ad_entry, NULL, ACL_DISCLOSE ); if ( rs->sr_err == LDAP_INSUFFICIENT_ACCESS ) { rs->sr_err = LDAP_NO_SUCH_OBJECT; } else { rs->sr_text = "attribute 'entryTtl' cannot have multiple values"; rs->sr_err = LDAP_CONSTRAINT_VIOLATION; } goto done; } rc = lutil_atoul( &uttl, mod->sml_values[ 0 ].bv_val ); ttl = (time_t)uttl; assert( rc == 0 ); if ( ttl > DDS_RF2589_MAX_TTL ) { rs->sr_err = LDAP_PROTOCOL_ERROR; rs->sr_text = "invalid time-to-live for dynamicObject"; goto done; } if ( ttl <= 0 || ttl > di->di_max_ttl ) { /* FIXME: I don't understand if this has to be an error, * or an indication that the requested Ttl has been * shortened to di->di_max_ttl >= 1 day */ rs->sr_err = LDAP_SIZELIMIT_EXCEEDED; rs->sr_text = "time-to-live for dynamicObject exceeds administrative limit"; goto done; } entryTtl = ttl; bv_entryTtl.bv_len = mod->sml_values[ 0 ].bv_len; memcpy( bv_entryTtl.bv_val, mod->sml_values[ 0 ].bv_val, bv_entryTtl.bv_len ); bv_entryTtl.bv_val[ bv_entryTtl.bv_len ] = '\0'; break; case LDAP_MOD_INCREMENT: if ( BER_BVISEMPTY( &bv_entryTtl ) ) { rs->sr_err = backend_attribute( op, NULL, &op->o_req_ndn, slap_schema.si_ad_entry, NULL, ACL_DISCLOSE ); if ( rs->sr_err == LDAP_INSUFFICIENT_ACCESS ) { rs->sr_err = LDAP_NO_SUCH_OBJECT; } else { rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE; rs->sr_text = "modify/increment: entryTtl: no such attribute"; } goto done; } entryTtl++; if ( entryTtl > DDS_RF2589_MAX_TTL ) { rs->sr_err = LDAP_PROTOCOL_ERROR; rs->sr_text = "invalid time-to-live for dynamicObject"; } else if ( entryTtl <= 0 || entryTtl > di->di_max_ttl ) { /* FIXME: I don't understand if this has to be an error, * or an indication that the requested Ttl has been * shortened to di->di_max_ttl >= 1 day */ rs->sr_err = LDAP_SIZELIMIT_EXCEEDED; rs->sr_text = "time-to-live for dynamicObject exceeds administrative limit"; } if ( rs->sr_err != LDAP_SUCCESS ) { rc = backend_attribute( op, NULL, &op->o_req_ndn, slap_schema.si_ad_entry, NULL, ACL_DISCLOSE ); if ( rc == LDAP_INSUFFICIENT_ACCESS ) { rs->sr_text = NULL; rs->sr_err = LDAP_NO_SUCH_OBJECT; } goto done; } bv_entryTtl.bv_len = snprintf( textbuf, sizeof( textbuf ), "%ld", entryTtl ); break; default: LDAP_BUG(); break; } } else if ( mod->sml_desc == ad_entryExpireTimestamp ) { /* should have been trapped earlier */ assert( mod->sml_flags & SLAP_MOD_INTERNAL ); } } done:; if ( rs->sr_err == LDAP_SUCCESS ) { int rc; /* FIXME: this could be allowed when the Relax control is used... * in that case: * * TODO * * static => dynamic: * entryTtl must be provided; add * entryExpireTimestamp accordingly * * dynamic => static: * entryTtl must be removed; remove * entryTimestamp accordingly * * ... but we need to make sure that there are no subordinate * issues... */ rc = is_dynamicObject - was_dynamicObject; if ( rc ) { #if 0 /* fix subordinate issues first */ if ( get_relax( op ) ) { switch ( rc ) { case -1: /* need to delete entryTtl to have a consistent entry */ if ( entryTtl != -1 ) { rs->sr_text = "objectClass modification from dynamicObject to static entry requires entryTtl deletion"; rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION; } break; case 1: /* need to add entryTtl to have a consistent entry */ if ( entryTtl <= 0 ) { rs->sr_text = "objectClass modification from static entry to dynamicObject requires entryTtl addition"; rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION; } break; } } else #endif { switch ( rc ) { case -1: rs->sr_text = "objectClass modification cannot turn dynamicObject into static entry"; break; case 1: rs->sr_text = "objectClass modification cannot turn static entry into dynamicObject"; break; } rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION; } if ( rc != LDAP_SUCCESS ) { rc = backend_attribute( op, NULL, &op->o_req_ndn, slap_schema.si_ad_entry, NULL, ACL_DISCLOSE ); if ( rc == LDAP_INSUFFICIENT_ACCESS ) { rs->sr_text = NULL; rs->sr_err = LDAP_NO_SUCH_OBJECT; } } } } if ( rs->sr_err == LDAP_SUCCESS && entryTtl != 0 ) { Modifications *tmpmod = NULL, **modp; for ( modp = &op->orm_modlist; *modp; modp = &(*modp)->sml_next ) ; tmpmod = ch_calloc( 1, sizeof( Modifications ) ); tmpmod->sml_flags = SLAP_MOD_INTERNAL; tmpmod->sml_type = ad_entryExpireTimestamp->ad_cname; tmpmod->sml_desc = ad_entryExpireTimestamp; *modp = tmpmod; if ( entryTtl == -1 ) { /* delete entryExpireTimestamp */ tmpmod->sml_op = LDAP_MOD_DELETE; } else { time_t expire; char tsbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; struct berval bv; /* keep entryExpireTimestamp consistent * with entryTtl */ expire = slap_get_time() + entryTtl; bv.bv_val = tsbuf; bv.bv_len = sizeof( tsbuf ); slap_timestamp( &expire, &bv ); tmpmod->sml_op = LDAP_MOD_REPLACE; value_add_one( &tmpmod->sml_values, &bv ); value_add_one( &tmpmod->sml_nvalues, &bv ); tmpmod->sml_numvals = 1; } } if ( rs->sr_err ) { op->o_bd->bd_info = (BackendInfo *)on->on_info; send_ldap_result( op, rs ); return rs->sr_err; } return SLAP_CB_CONTINUE; }
static int dds_op_add( Operation *op, SlapReply *rs ) { slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; dds_info_t *di = on->on_bi.bi_private; int is_dynamicObject; if ( DDS_OFF( di ) ) { return SLAP_CB_CONTINUE; } is_dynamicObject = is_entry_dynamicObject( op->ora_e ); /* FIXME: do not allow this right now, pending clarification */ if ( is_dynamicObject ) { rs->sr_err = LDAP_SUCCESS; if ( is_entry_referral( op->ora_e ) ) { rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION; rs->sr_text = "a referral cannot be a dynamicObject"; } else if ( is_entry_alias( op->ora_e ) ) { rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION; rs->sr_text = "an alias cannot be a dynamicObject"; } if ( rs->sr_err != LDAP_SUCCESS ) { op->o_bd->bd_info = (BackendInfo *)on->on_info; send_ldap_result( op, rs ); return rs->sr_err; } } /* we don't allow dynamicObjects to have static subordinates */ if ( !dn_match( &op->o_req_ndn, &op->o_bd->be_nsuffix[ 0 ] ) ) { struct berval p_ndn; Entry *e = NULL; int rc; BackendInfo *bi = op->o_bd->bd_info; dnParent( &op->o_req_ndn, &p_ndn ); op->o_bd->bd_info = (BackendInfo *)on->on_info; rc = be_entry_get_rw( op, &p_ndn, slap_schema.si_oc_dynamicObject, NULL, 0, &e ); if ( rc == LDAP_SUCCESS && e != NULL ) { if ( !is_dynamicObject ) { /* return referral only if "disclose" * is granted on the object */ if ( ! access_allowed( op, e, slap_schema.si_ad_entry, NULL, ACL_DISCLOSE, NULL ) ) { rc = rs->sr_err = LDAP_NO_SUCH_OBJECT; send_ldap_result( op, rs ); } else { rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION; send_ldap_error( op, rs, rc, "no static subordinate entries allowed for dynamicObject" ); } } be_entry_release_r( op, e ); if ( rc != LDAP_SUCCESS ) { return rc; } } op->o_bd->bd_info = bi; } /* handle dynamic object operational attr(s) */ if ( is_dynamicObject ) { time_t ttl, expire; char ttlbuf[STRLENOF("31557600") + 1]; char tsbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; struct berval bv; if ( !be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) { ldap_pvt_thread_mutex_lock( &di->di_mutex ); rs->sr_err = ( di->di_max_dynamicObjects && di->di_num_dynamicObjects >= di->di_max_dynamicObjects ); ldap_pvt_thread_mutex_unlock( &di->di_mutex ); if ( rs->sr_err ) { op->o_bd->bd_info = (BackendInfo *)on->on_info; send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "too many dynamicObjects in context" ); return rs->sr_err; } } ttl = DDS_DEFAULT_TTL( di ); /* assert because should be checked at configure */ assert( ttl <= DDS_RF2589_MAX_TTL ); bv.bv_val = ttlbuf; bv.bv_len = snprintf( ttlbuf, sizeof( ttlbuf ), "%ld", ttl ); assert( bv.bv_len < sizeof( ttlbuf ) ); /* FIXME: apparently, values in op->ora_e are malloc'ed * on the thread's slab; works fine by chance, * only because the attribute doesn't exist yet. */ assert( attr_find( op->ora_e->e_attrs, slap_schema.si_ad_entryTtl ) == NULL ); attr_merge_one( op->ora_e, slap_schema.si_ad_entryTtl, &bv, &bv ); expire = slap_get_time() + ttl; bv.bv_val = tsbuf; bv.bv_len = sizeof( tsbuf ); slap_timestamp( &expire, &bv ); assert( attr_find( op->ora_e->e_attrs, ad_entryExpireTimestamp ) == NULL ); attr_merge_one( op->ora_e, ad_entryExpireTimestamp, &bv, &bv ); /* if required, install counter callback */ if ( di->di_max_dynamicObjects > 0) { slap_callback *sc; sc = op->o_tmpalloc( sizeof( slap_callback ), op->o_tmpmemctx ); sc->sc_cleanup = dds_freeit_cb; sc->sc_response = dds_counter_cb; sc->sc_private = di; sc->sc_next = op->o_callback; op->o_callback = sc; } } return SLAP_CB_CONTINUE; }
static int dds_expire( void *ctx, dds_info_t *di ) { Connection conn = { 0 }; OperationBuffer opbuf; Operation *op; slap_callback sc = { 0 }; dds_cb_t dc = { 0 }; dds_expire_t *de = NULL, **dep; SlapReply rs = { REP_RESULT }; time_t expire; char tsbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; struct berval ts; int ndeletes, ntotdeletes; int rc; char *extra = ""; connection_fake_init2( &conn, &opbuf, ctx, 0 ); op = &opbuf.ob_op; op->o_tag = LDAP_REQ_SEARCH; memset( &op->oq_search, 0, sizeof( op->oq_search ) ); op->o_bd = select_backend( &di->di_nsuffix[ 0 ], 0 ); op->o_req_dn = op->o_bd->be_suffix[ 0 ]; op->o_req_ndn = op->o_bd->be_nsuffix[ 0 ]; op->o_dn = op->o_bd->be_rootdn; op->o_ndn = op->o_bd->be_rootndn; op->ors_scope = LDAP_SCOPE_SUBTREE; op->ors_tlimit = DDS_INTERVAL( di )/2 + 1; op->ors_slimit = SLAP_NO_LIMIT; op->ors_attrs = slap_anlist_no_attrs; expire = slap_get_time() - di->di_tolerance; ts.bv_val = tsbuf; ts.bv_len = sizeof( tsbuf ); slap_timestamp( &expire, &ts ); op->ors_filterstr.bv_len = STRLENOF( "(&(objectClass=" ")(" "<=" "))" ) + slap_schema.si_oc_dynamicObject->soc_cname.bv_len + ad_entryExpireTimestamp->ad_cname.bv_len + ts.bv_len; op->ors_filterstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len + 1, op->o_tmpmemctx ); snprintf( op->ors_filterstr.bv_val, op->ors_filterstr.bv_len + 1, "(&(objectClass=%s)(%s<=%s))", slap_schema.si_oc_dynamicObject->soc_cname.bv_val, ad_entryExpireTimestamp->ad_cname.bv_val, ts.bv_val ); op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val ); if ( op->ors_filter == NULL ) { rs.sr_err = LDAP_OTHER; goto done_search; } op->o_callback = ≻ sc.sc_response = dds_expire_cb; sc.sc_private = &dc; (void)op->o_bd->bd_info->bi_op_search( op, &rs ); done_search:; op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx ); filter_free_x( op, op->ors_filter, 1 ); rc = rs.sr_err; switch ( rs.sr_err ) { case LDAP_SUCCESS: break; case LDAP_NO_SUCH_OBJECT: /* (ITS#5267) database not created yet? */ rs.sr_err = LDAP_SUCCESS; extra = " (ignored)"; /* fallthru */ default: Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, "DDS expired objects lookup failed err=%d%s\n", rc, extra ); goto done; } op->o_tag = LDAP_REQ_DELETE; op->o_callback = ≻ sc.sc_response = slap_null_cb; sc.sc_private = NULL; slap_biglock_acquire(op->o_bd); for ( ntotdeletes = 0, ndeletes = 1; dc.dc_ndnlist != NULL && ndeletes > 0; ) { ndeletes = 0; for ( dep = &dc.dc_ndnlist; *dep != NULL; ) { de = *dep; op->o_req_dn = de->de_ndn; op->o_req_ndn = de->de_ndn; (void)op->o_bd->bd_info->bi_op_delete( op, &rs ); switch ( rs.sr_err ) { case LDAP_SUCCESS: Log1( LDAP_DEBUG_STATS, LDAP_LEVEL_INFO, "DDS dn=\"%s\" expired.\n", de->de_ndn.bv_val ); ndeletes++; break; case LDAP_NOT_ALLOWED_ON_NONLEAF: Log1( LDAP_DEBUG_ANY, LDAP_LEVEL_NOTICE, "DDS dn=\"%s\" is non-leaf; " "deferring.\n", de->de_ndn.bv_val ); dep = &de->de_next; de = NULL; break; default: Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_NOTICE, "DDS dn=\"%s\" err=%d; " "deferring.\n", de->de_ndn.bv_val, rs.sr_err ); break; } if ( de != NULL ) { *dep = de->de_next; op->o_tmpfree( de, op->o_tmpmemctx ); } } ntotdeletes += ndeletes; } slap_biglock_release(op->o_bd); rs.sr_err = LDAP_SUCCESS; Log1( LDAP_DEBUG_STATS, LDAP_LEVEL_INFO, "DDS expired=%d\n", ntotdeletes ); done:; return rs.sr_err; }