]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/overlays/lastmod.c
ITS#4358
[openldap] / servers / slapd / overlays / lastmod.c
index 6c832f41aae43d8637b546d654acdbdad7889850..fb5bda9651e851200807c1c32b22b72fb7750464 100644 (file)
@@ -1,7 +1,7 @@
 /* lastmod.c - returns last modification info */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 2004 The OpenLDAP Foundation.
+ * Copyright 2004-2006 The OpenLDAP Foundation.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -108,11 +108,8 @@ static struct m_s {
                "SINGLE-VALUE )", 0,
                offsetof( struct lastmod_schema_t, lms_ad_lastmodEnabled ) },
        { NULL }
-};
 
-static const struct berval *write_exop[] = {
-       &slap_EXOP_MODIFY_PASSWD,
-       NULL
+       /* FIXME: what about UUID of last modified entry? */
 };
 
 static int
@@ -286,7 +283,6 @@ lastmod_op_func( Operation *op, SlapReply *rs )
 {
        slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
        lastmod_info_t          *lmi = (lastmod_info_t *)on->on_bi.bi_private;
-       unsigned                i;
        Modifications           *ml;
 
        if ( dn_match( &op->o_req_ndn, &lmi->lmi_e->e_nname ) ) {
@@ -303,29 +299,14 @@ lastmod_op_func( Operation *op, SlapReply *rs )
 
                case LDAP_REQ_EXTENDED:
                        /* if write, reject; otherwise process */
-                       for ( i = 0; write_exop[ i ] != NULL; i++ ) {
-                               if ( ber_bvcmp( write_exop[ i ], &op->oq_extended.rs_reqoid ) == 0 ) {
-                                       rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
-                                       rs->sr_text = "not allowed within namingContext";
-                                       goto return_error;
-                               }
+                       if ( exop_is_write( op )) {
+                               rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
+                               rs->sr_text = "not allowed within namingContext";
+                               goto return_error;
                        }
                        return lastmod_exop( op, rs );
 
                case LDAP_REQ_MODIFY:
-                       /* if global overlay, modlist is not checked yet */
-                       if ( op->orm_modlist->sml_desc == NULL ) {
-                               char textbuf[SLAP_TEXT_BUFLEN];
-                               size_t textlen = sizeof textbuf;
-
-                               rs->sr_err = slap_mods_check( op->orm_modlist, 0, &rs->sr_text,
-                                               textbuf, textlen, NULL );
-
-                               if ( rs->sr_err ) {
-                                       goto return_error;
-                               }
-                       }
-
                        /* allow only changes to overlay status */
                        for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
                                if ( ad_cmp( ml->sml_desc, slap_schema.si_ad_modifiersName ) != 0
@@ -355,16 +336,16 @@ lastmod_op_func( Operation *op, SlapReply *rs )
 
 return_referral:;
        op->o_bd->bd_info = (BackendInfo *)on->on_info;
-       rs->sr_ref = referral_rewrite( SLAPD_GLOBAL(default_referral),
+       rs->sr_ref = referral_rewrite( default_referral,
                        NULL, &op->o_req_dn, op->ors_scope );
 
        if ( !rs->sr_ref ) {
-               rs->sr_ref = SLAPD_GLOBAL( default_referral );
+               rs->sr_ref = default_referral;
        }
        rs->sr_err = LDAP_REFERRAL;
        send_ldap_result( op, rs );
 
-       if ( rs->sr_ref != SLAPD_GLOBAL( default_referral )) {
+       if ( rs->sr_ref != default_referral ) {
                ber_bvarray_free( rs->sr_ref );
        }
        rs->sr_ref = NULL;
@@ -381,15 +362,25 @@ return_error:;
 
 static int
 best_guess( Operation *op,
+               struct berval *bv_entryCSN, struct berval *bv_nentryCSN,
                struct berval *bv_modifyTimestamp, struct berval *bv_nmodifyTimestamp,
                struct berval *bv_modifiersName, struct berval *bv_nmodifiersName )
 {
+       if ( bv_entryCSN ) {
+               char            csnbuf[ LDAP_LUTIL_CSNSTR_BUFSIZE ];
+               struct berval   entryCSN;
+       
+               entryCSN.bv_val = csnbuf;
+               entryCSN.bv_len = sizeof( csnbuf );
+               slap_get_csn( NULL, &entryCSN, 0 );
+
+               ber_dupbv( bv_entryCSN, &entryCSN );
+               ber_dupbv( bv_nentryCSN, &entryCSN );
+       }
+
        if ( bv_modifyTimestamp ) {
-               struct tm       *tm;
-#ifdef HAVE_GMTIME_R
-               struct tm       tm_buf;
-#endif
                char            tmbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
+               struct berval timestamp;
                time_t          currtime;
 
                /* best guess */
@@ -399,18 +390,11 @@ best_guess( Operation *op,
                /* maybe we better use the time the operation was initiated */
                currtime = op->o_time;
 
-#ifndef HAVE_GMTIME_R
-               ldap_pvt_thread_mutex_lock( &SLAPD_GLOBAL( gmtime_mutex ));
-               tm = gmtime( &currtime );
-#else /* HAVE_GMTIME_R */
-               tm = gmtime_r( &currtime, &tm_buf );
-#endif /* HAVE_GMTIME_R */
-               lutil_gentime( tmbuf, sizeof( tmbuf ), tm );
-#ifndef HAVE_GMTIME_R
-               ldap_pvt_thread_mutex_unlock( &SLAPD_GLOBAL(gmtime_mutex) );
-#endif
+               timestamp.bv_val = tmbuf;
+               timestamp.bv_len = sizeof(tmbuf);
+               slap_timestamp( &currtime, &timestamp );
 
-               ber_str2bv( tmbuf, 0, 1, bv_modifyTimestamp );
+               ber_dupbv( bv_modifyTimestamp, &timestamp );
                ber_dupbv( bv_nmodifyTimestamp, bv_modifyTimestamp );
        }
 
@@ -430,7 +414,9 @@ lastmod_update( Operation *op, SlapReply *rs )
        lastmod_info_t          *lmi = (lastmod_info_t *)on->on_bi.bi_private;
        Attribute               *a;
        Modifications           *ml = NULL;
-       struct berval           bv_modifyTimestamp = BER_BVNULL,
+       struct berval           bv_entryCSN = BER_BVNULL,
+                               bv_nentryCSN = BER_BVNULL,
+                               bv_modifyTimestamp = BER_BVNULL,
                                bv_nmodifyTimestamp = BER_BVNULL,
                                bv_modifiersName = BER_BVNULL,
                                bv_nmodifiersName = BER_BVNULL,
@@ -445,10 +431,14 @@ lastmod_update( Operation *op, SlapReply *rs )
        case LDAP_REQ_ADD:
                lmt = LASTMOD_ADD;
                e = op->ora_e;
-               a = attr_find( e->e_attrs, slap_schema.si_ad_modifiersName );
+               a = attr_find( e->e_attrs, slap_schema.si_ad_entryCSN );
                if ( a != NULL ) {
-                       ber_dupbv( &bv_modifiersName, &a->a_vals[0] );
-                       ber_dupbv( &bv_nmodifiersName, &a->a_nvals[0] );
+                       ber_dupbv( &bv_entryCSN, &a->a_vals[0] );
+                       if ( a->a_nvals && !BER_BVISNULL( &a->a_nvals[0] ) ) {
+                               ber_dupbv( &bv_nentryCSN, &a->a_nvals[0] );
+                       } else {
+                               ber_dupbv( &bv_nentryCSN, &a->a_vals[0] );
+                       }
                }
                a = attr_find( e->e_attrs, slap_schema.si_ad_modifyTimestamp );
                if ( a != NULL ) {
@@ -459,6 +449,11 @@ lastmod_update( Operation *op, SlapReply *rs )
                                ber_dupbv( &bv_nmodifyTimestamp, &a->a_vals[0] );
                        }
                }
+               a = attr_find( e->e_attrs, slap_schema.si_ad_modifiersName );
+               if ( a != NULL ) {
+                       ber_dupbv( &bv_modifiersName, &a->a_vals[0] );
+                       ber_dupbv( &bv_nmodifiersName, &a->a_nvals[0] );
+               }
                ber_dupbv( &bv_name, &e->e_name );
                ber_dupbv( &bv_nname, &e->e_nname );
                break;
@@ -466,7 +461,8 @@ lastmod_update( Operation *op, SlapReply *rs )
        case LDAP_REQ_DELETE:
                lmt = LASTMOD_DELETE;
 
-               best_guess( op, &bv_modifyTimestamp, &bv_nmodifyTimestamp,
+               best_guess( op, &bv_entryCSN, &bv_nentryCSN,
+                               &bv_modifyTimestamp, &bv_nmodifyTimestamp,
                                &bv_modifiersName, &bv_nmodifiersName );
 
                ber_dupbv( &bv_name, &op->o_req_dn );
@@ -478,7 +474,8 @@ lastmod_update( Operation *op, SlapReply *rs )
 
                /* actually, password change is wrapped around a backend 
                 * call to modify, so it never shows up as an exop... */
-               best_guess( op, &bv_modifyTimestamp, &bv_nmodifyTimestamp,
+               best_guess( op, &bv_entryCSN, &bv_nentryCSN,
+                               &bv_modifyTimestamp, &bv_nmodifyTimestamp,
                                &bv_modifiersName, &bv_nmodifiersName );
 
                ber_dupbv( &bv_name, &op->o_req_dn );
@@ -487,13 +484,28 @@ lastmod_update( Operation *op, SlapReply *rs )
 
        case LDAP_REQ_MODIFY:
                lmt = LASTMOD_MODIFY;
+               rc = 3;
 
                for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
                        if ( ad_cmp( ml->sml_desc , slap_schema.si_ad_modifiersName ) == 0 ) {
                                ber_dupbv( &bv_modifiersName, &ml->sml_values[0] );
                                ber_dupbv( &bv_nmodifiersName, &ml->sml_nvalues[0] );
 
-                               if ( !BER_BVISNULL( &bv_modifyTimestamp ) ) {
+                               rc--;
+                               if ( !rc ) {
+                                       break;
+                               }
+
+                       } else if ( ad_cmp( ml->sml_desc, slap_schema.si_ad_entryCSN ) == 0 ) {
+                               ber_dupbv( &bv_entryCSN, &ml->sml_values[0] );
+                               if ( ml->sml_nvalues && !BER_BVISNULL( &ml->sml_nvalues[0] ) ) {
+                                       ber_dupbv( &bv_nentryCSN, &ml->sml_nvalues[0] );
+                               } else {
+                                       ber_dupbv( &bv_nentryCSN, &ml->sml_values[0] );
+                               }
+
+                               rc --;
+                               if ( !rc ) {
                                        break;
                                }
 
@@ -505,7 +517,8 @@ lastmod_update( Operation *op, SlapReply *rs )
                                        ber_dupbv( &bv_nmodifyTimestamp, &ml->sml_values[0] );
                                }
 
-                               if ( !BER_BVISNULL( &bv_modifiersName ) ) {
+                               rc --;
+                               if ( !rc ) {
                                        break;
                                }
                        }
@@ -513,12 +526,15 @@ lastmod_update( Operation *op, SlapReply *rs )
 
                /* if rooted at global overlay, opattrs are not yet in place */
                if ( BER_BVISNULL( &bv_modifiersName ) ) {
-                       best_guess( op, NULL, NULL, &bv_modifiersName, &bv_nmodifiersName );
+                       best_guess( op, NULL, NULL, NULL, NULL, &bv_modifiersName, &bv_nmodifiersName );
+               }
+
+               if ( BER_BVISNULL( &bv_entryCSN ) ) {
+                       best_guess( op, &bv_entryCSN, &bv_nentryCSN, NULL, NULL, NULL, NULL );
                }
 
-               /* if rooted at global overlay, opattrs are not yet in place */
                if ( BER_BVISNULL( &bv_modifyTimestamp ) ) {
-                       best_guess( op, &bv_modifyTimestamp, &bv_nmodifyTimestamp, NULL, NULL );
+                       best_guess( op, NULL, NULL, &bv_modifyTimestamp, &bv_nmodifyTimestamp, NULL, NULL );
                }
 
                ber_dupbv( &bv_name, &op->o_req_dn );
@@ -555,6 +571,15 @@ lastmod_update( Operation *op, SlapReply *rs )
                                        ber_dupbv( &bv_modifiersName, &a->a_vals[0] );
                                        ber_dupbv( &bv_nmodifiersName, &a->a_nvals[0] );
                                }
+                               a = attr_find( e->e_attrs, slap_schema.si_ad_entryCSN );
+                               if ( a != NULL ) {
+                                       ber_dupbv( &bv_entryCSN, &a->a_vals[0] );
+                                       if ( a->a_nvals && !BER_BVISNULL( &a->a_nvals[0] ) ) {
+                                               ber_dupbv( &bv_nentryCSN, &a->a_nvals[0] );
+                                       } else {
+                                               ber_dupbv( &bv_nentryCSN, &a->a_vals[0] );
+                                       }
+                               }
                                a = attr_find( e->e_attrs, slap_schema.si_ad_modifyTimestamp );
                                if ( a != NULL ) {
                                        ber_dupbv( &bv_modifyTimestamp, &a->a_vals[0] );
@@ -577,7 +602,8 @@ lastmod_update( Operation *op, SlapReply *rs )
 
                /* if !bi_entry_get_rw || bi_entry_get_rw failed for any reason... */
                if ( e == NULL ) {
-                       best_guess( op, &bv_modifyTimestamp, &bv_nmodifyTimestamp,
+                       best_guess( op, &bv_entryCSN, &bv_nentryCSN,
+                                       &bv_modifyTimestamp, &bv_nmodifyTimestamp,
                                        &bv_modifiersName, &bv_nmodifiersName );
                }
 
@@ -641,6 +667,19 @@ lastmod_update( Operation *op, SlapReply *rs )
        ch_free( a->a_nvals[0].bv_val );
        a->a_nvals[0] = bv_nmodifyTimestamp;
 
+#if 0
+       fprintf( stderr, "### entryCSN: %s %s\n", bv_nentryCSN.bv_val, bv_entryCSN.bv_val );
+#endif
+
+       a = attr_find( lmi->lmi_e->e_attrs, slap_schema.si_ad_entryCSN );
+       if ( a == NULL ) {
+               goto error_return;
+       } 
+       ch_free( a->a_vals[0].bv_val );
+       a->a_vals[0] = bv_entryCSN;
+       ch_free( a->a_nvals[0].bv_val );
+       a->a_nvals[0] = bv_nentryCSN;
+
        rc = 0;
 
 error_return:;
@@ -654,7 +693,6 @@ lastmod_response( Operation *op, SlapReply *rs )
 {
        slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
        lastmod_info_t          *lmi = (lastmod_info_t *)on->on_bi.bi_private;
-       unsigned int            i;
 
        /* don't record failed operations */
        switch ( rs->sr_err ) {
@@ -676,13 +714,10 @@ lastmod_response( Operation *op, SlapReply *rs )
 
        case LDAP_REQ_EXTENDED:
                /* if write, process */
-               for ( i = 0; write_exop[ i ] != NULL; i++ ) {
-                       if ( ber_bvcmp( write_exop[ i ], &op->oq_extended.rs_reqoid ) == 0 ) {
-                               goto process;
-                       }
-               }
-               /* fall thru */
+               if ( exop_is_write( op ))
+                       break;
 
+               /* fall thru */
        default:
                return SLAP_CB_CONTINUE;
        }
@@ -695,7 +730,6 @@ lastmod_response( Operation *op, SlapReply *rs )
        }
        ldap_pvt_thread_mutex_unlock( &lmi->lmi_entry_mutex );
 
-process:;
        (void)lastmod_update( op, rs );
 
        return SLAP_CB_CONTINUE;
@@ -736,7 +770,7 @@ lastmod_db_init(
                                return -1;
                        }
        
-                       code = at_add(at, &err);
+                       code = at_add(at, 0, NULL, &err);
                        if ( code ) {
                                Debug( LDAP_DEBUG_ANY, "lastmod_init: "
                                        "%s in attributeType '%s'\n",
@@ -779,7 +813,7 @@ lastmod_db_init(
                                return -1;
                        }
 
-                       code = oc_add(oc, 0, &err);
+                       code = oc_add(oc, 0, NULL, &err);
                        if ( code ) {
                                Debug( LDAP_DEBUG_ANY,
                                        "objectClass '%s': %s \"%s\"\n" ,
@@ -859,12 +893,12 @@ lastmod_db_open(
        slap_overinst   *on = (slap_overinst *) be->bd_info;
        lastmod_info_t  *lmi = (lastmod_info_t *)on->on_bi.bi_private;
        char            buf[ 8192 ];
-       struct tm               *tms;
-#ifdef HAVE_GMTIME_R
-       struct tm               tm_buf;
-#endif
        static char             tmbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
 
+       char                    csnbuf[ LDAP_LUTIL_CSNSTR_BUFSIZE ];
+       struct berval           entryCSN;
+       struct berval timestamp;
+
        if ( !SLAP_LASTMOD( be ) ) {
                fprintf( stderr, "set \"lastmod on\" to make this overlay effective\n" );
                return -1;
@@ -873,16 +907,13 @@ lastmod_db_open(
        /*
         * Start
         */
-#ifndef HAVE_GMTIME_R
-       ldap_pvt_thread_mutex_lock( &SLAPD_GLOBAL( gmtime_mutex ));
-       tms = gmtime( &SLAPD_GLOBAL( starttime ));
-#else /* HAVE_GMTIME_R */
-       tms = gmtime_r( &SLAPD_GLOBAL( starttime ), &tm_buf );
-#endif /* HAVE_GMTIME_R */
-       lutil_gentime( tmbuf, sizeof(tmbuf), tms );
-#ifndef HAVE_GMTIME_R
-       ldap_pvt_thread_mutex_unlock( &SLAPD_GLOBAL( gmtime_mutex ));
-#endif
+       timestamp.bv_val = tmbuf;
+       timestamp.bv_len = sizeof(tmbuf);
+       slap_timestamp( &starttime, &timestamp );
+
+       entryCSN.bv_val = csnbuf;
+       entryCSN.bv_len = sizeof( csnbuf );
+       slap_get_csn( NULL, &entryCSN, 0 );
 
        if ( BER_BVISNULL( &lmi->lmi_rdnvalue ) ) {
                ber_str2bv( "Lastmod", 0, 1, &lmi->lmi_rdnvalue );
@@ -899,6 +930,7 @@ lastmod_db_open(
                        "%s: %s\n"
                        "createTimestamp: %s\n"
                        "creatorsName: %s\n"
+                       "entryCSN: %s\n"
                        "modifyTimestamp: %s\n"
                        "modifiersName: %s\n"
                        "hasSubordinates: FALSE\n",
@@ -912,6 +944,7 @@ lastmod_db_open(
                        lastmod_schema.lms_ad_lastmodEnabled->ad_cname.bv_val, lmi->lmi_enabled ? "TRUE" : "FALSE",
                        tmbuf,
                        BER_BVISNULL( &be->be_rootdn ) ? SLAPD_ANONYMOUS : be->be_rootdn.bv_val,
+                       entryCSN.bv_val,
                        tmbuf,
                        BER_BVISNULL( &be->be_rootdn ) ? SLAPD_ANONYMOUS : be->be_rootdn.bv_val );
 
@@ -962,7 +995,7 @@ lastmod_db_destroy(
 static slap_overinst           lastmod;
 
 int
-lastmod_init()
+lastmod_initialize()
 {
        lastmod.on_bi.bi_type = "lastmod";
        lastmod.on_bi.bi_db_init = lastmod_db_init;
@@ -987,7 +1020,7 @@ lastmod_init()
 int
 init_module( int argc, char *argv[] )
 {
-       return lastmod_init();
+       return lastmod_initialize();
 }
 #endif /* SLAPD_OVER_LASTMOD == SLAPD_MOD_DYNAMIC */