summaryrefslogtreecommitdiffstats
path: root/servers/slapd/back-monitor
diff options
context:
space:
mode:
Diffstat (limited to 'servers/slapd/back-monitor')
-rw-r--r--servers/slapd/back-monitor/Makefile.in49
-rw-r--r--servers/slapd/back-monitor/README243
-rw-r--r--servers/slapd/back-monitor/back-monitor.h324
-rw-r--r--servers/slapd/back-monitor/backend.c160
-rw-r--r--servers/slapd/back-monitor/bind.c48
-rw-r--r--servers/slapd/back-monitor/cache.c449
-rw-r--r--servers/slapd/back-monitor/compare.c76
-rw-r--r--servers/slapd/back-monitor/conn.c528
-rw-r--r--servers/slapd/back-monitor/database.c1048
-rw-r--r--servers/slapd/back-monitor/entry.c223
-rw-r--r--servers/slapd/back-monitor/init.c2598
-rw-r--r--servers/slapd/back-monitor/listener.c138
-rw-r--r--servers/slapd/back-monitor/log.c455
-rw-r--r--servers/slapd/back-monitor/modify.c90
-rw-r--r--servers/slapd/back-monitor/operation.c249
-rw-r--r--servers/slapd/back-monitor/operational.c72
-rw-r--r--servers/slapd/back-monitor/overlay.c141
-rw-r--r--servers/slapd/back-monitor/proto-back-monitor.h338
-rw-r--r--servers/slapd/back-monitor/rww.c232
-rw-r--r--servers/slapd/back-monitor/search.c271
-rw-r--r--servers/slapd/back-monitor/sent.c241
-rw-r--r--servers/slapd/back-monitor/thread.c358
-rw-r--r--servers/slapd/back-monitor/time.c247
23 files changed, 8578 insertions, 0 deletions
diff --git a/servers/slapd/back-monitor/Makefile.in b/servers/slapd/back-monitor/Makefile.in
new file mode 100644
index 0000000..40bbb67
--- /dev/null
+++ b/servers/slapd/back-monitor/Makefile.in
@@ -0,0 +1,49 @@
+# Makefile.in for back-monitor
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2018 The OpenLDAP Foundation.
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted only as authorized by the OpenLDAP
+## Public License.
+##
+## A copy of this license is available in the file LICENSE in the
+## top-level directory of the distribution or, alternatively, at
+## <http://www.OpenLDAP.org/license.html>.
+
+SRCS = init.c search.c compare.c modify.c bind.c \
+ operational.c \
+ cache.c entry.c \
+ backend.c database.c thread.c conn.c rww.c log.c \
+ operation.c sent.c listener.c time.c overlay.c
+OBJS = init.lo search.lo compare.lo modify.lo bind.lo \
+ operational.lo \
+ cache.lo entry.lo \
+ backend.lo database.lo thread.lo conn.lo rww.lo log.lo \
+ operation.lo sent.lo listener.lo time.lo overlay.lo
+
+LDAP_INCDIR= ../../../include
+LDAP_LIBDIR= ../../../libraries
+
+BUILD_OPT = "--enable-monitor"
+BUILD_MOD = @BUILD_MONITOR@
+
+mod_DEFS = -DSLAPD_IMPORT
+MOD_DEFS = $(@BUILD_MONITOR@_DEFS)
+
+shared_LDAP_LIBS = $(LDAP_LIBLDAP_R_LA) $(LDAP_LIBLBER_LA)
+NT_LINK_LIBS = -L.. -lslapd $(@BUILD_LIBS_DYNAMIC@_LDAP_LIBS)
+UNIX_LINK_LIBS = $(@BUILD_LIBS_DYNAMIC@_LDAP_LIBS)
+
+LIBBASE = back_monitor
+
+XINCPATH = -I.. -I$(srcdir)/.. -I$(srcdir)/../slapi
+XDEFS = $(MODULES_CPPFLAGS)
+
+all-local-lib: ../.backend
+
+../.backend: lib$(LIBBASE).a
+ @touch $@
+
diff --git a/servers/slapd/back-monitor/README b/servers/slapd/back-monitor/README
new file mode 100644
index 0000000..21d7b86
--- /dev/null
+++ b/servers/slapd/back-monitor/README
@@ -0,0 +1,243 @@
+MONITOR BACKEND
+
+ NAME: back-monitor
+
+ Backend for monitoring the server's activity.
+
+
+
+COMPILE AND CONFIGURATION OPTIONS
+
+It must be explicitly enabled by configuring with
+
+ --enable-monitor
+
+set; then it must be activated by placing in slapd.conf the database
+configure directive
+
+ database monitor
+
+The suffix "cn=Monitor" is implicitly activated (it cannot be given
+as a suffix of the database as usually done for conventional backends).
+Note that the "cn=Monitor" naming context appears in the rootDSE
+in the attribute monitorContext
+
+A bind operation is provided; at present it allows to bind as the
+backend rootdn. As a result, the backend supports the rootdn/rootpw
+directives (only simple bind at present).
+
+
+
+NAMING CONTEXT AND TREE STRUCTURE
+
+The backend naming context is "cn=Monitor"; the first level entries
+represent the monitored subsystems. It is implemented in a modular way,
+to ease the addition of new subsystems.
+
+
+
+SCHEMA
+
+All the subsystems get a default "cn" attribute, represented by the
+subsystem's name, and they all have "top", "monitor" and "extensibleObject"
+objectclasses.
+"extensibleObject" is used, and the "description" attribute
+is used to hold the monitor information of each entry.
+
+
+
+FUNCTIONALITY
+
+Most of the sybsystems contain an additional depth level, represented
+by detailed item monitoring.
+All the entries undergo an update operation, if a related method is
+defined, prior to being returned. Moreover, there's a mechanism to
+allow volatile entries to be defined, and generated on the fly when
+requested. As an instance, the connection statistics are updated
+at each request, while each active connection data is created on the
+fly.
+
+One nice feature of this solution is that granular ACLs can be applied
+to each entry.
+
+
+
+OPERATIONS
+
+The backend currently supports:
+
+ bind
+ compare
+ modify
+ search
+
+
+
+SUBSYSTEMS
+
+Currently some subsystems are partially supported. "Partially"
+means their entries are correctly generated, but sometimes only
+partially useful information is provided.
+
+The subsystems are:
+
+ Backends
+ Connections
+ Databases
+ Listener
+ Log
+ Operations
+ Overlays
+ SASL
+ Statistics
+ Threads
+ Time
+ TLS
+ Read/Write Waiters
+
+
+
+BACKENDS SUBSYSTEMS
+
+The main entry contains the type of backends enabled at compile time;
+the subentries, for each backend, contain the type of the backend.
+It should also contain the modules that have been loaded if dynamic
+backends are enabled.
+
+
+
+CONNECTIONS
+
+The main entry is empty; it should contain some statistics on the number
+of connections.
+Dynamic subentries are created for each open connection, with stats on
+the activity on that connection (the format will be detailed later).
+There are two special subentries that show the number of total and
+current connections respectively.
+
+
+
+DATABASES SUBSYSTEM
+
+The main entry contains the naming context of each configured database;
+the subentries contain, for each database, the type and the naming
+context.
+
+
+
+LISTENER SUBSYSTEM
+
+It contains the description of the devices the server is currently
+listening on
+
+
+
+LOG SUBSYSTEM
+
+It contains the currently active log items. The "Log" subsystem allows
+user modify operations on the "description" attribute, whose values MUST
+be in the list of admittable log switches:
+
+ Trace
+ Packets
+ Args
+ Conns
+ BER
+ Filter
+ Config (useless)
+ ACL
+ Stats
+ Stats2
+ Shell
+ Parse
+ Cache (deprecated)
+ Index
+
+These values can be added, replaced or deleted; they affect what
+messages are sent to the syslog device.
+
+
+
+OPERATIONS SUBSYSTEM
+
+It shows some statistics on the operations performed by the server:
+
+ Initiated
+ Completed
+
+and for each operation type, i.e.:
+
+ Bind
+ Unbind
+ Add
+ Delete
+ Modrdn
+ Modify
+ Compare
+ Search
+ Abandon
+ Extended
+
+
+
+OVERLAYS SUBSYSTEM
+
+The main entry contains the type of overlays available at run-time;
+the subentries, for each overlay, contain the type of the overlay.
+It should also contain the modules that have been loaded if dynamic
+overlays are enabled.
+
+
+
+SASL
+
+Currently empty.
+
+
+
+STATISTICS SUBSYSTEM
+
+It shows some statistics on the data sent by the server:
+
+ Bytes
+ PDU
+ Entries
+ Referrals
+
+
+
+THREADS SUBSYSTEM
+
+It contains the maximum number of threads enabled at startup and the
+current backload.
+
+
+
+TIME SUBSYSTEM
+
+It contains two subentries with the start time and the current time
+of the server.
+
+
+
+TLS
+
+Currently empty.
+
+
+
+READ/WRITE WAITERS SUBSYSTEM
+
+It contains the number of current read waiters.
+
+
+
+NOTES
+
+This document is in a very early stage of maturity and will
+probably be rewritten many times before the monitor backend is released.
+
+
+
+AUTHOR: Pierangelo Masarati <ando@OpenLDAP.org>
+
diff --git a/servers/slapd/back-monitor/back-monitor.h b/servers/slapd/back-monitor/back-monitor.h
new file mode 100644
index 0000000..f8d2e2c
--- /dev/null
+++ b/servers/slapd/back-monitor/back-monitor.h
@@ -0,0 +1,324 @@
+/* back-monitor.h - ldap monitor back-end header file */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2001-2018 The OpenLDAP Foundation.
+ * Portions Copyright 2001-2003 Pierangelo Masarati.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Pierangelo Masarati for inclusion
+ * in OpenLDAP Software.
+ */
+
+#ifndef _BACK_MONITOR_H_
+#define _BACK_MONITOR_H_
+
+#include <ldap_pvt.h>
+#include <ldap_pvt_thread.h>
+#include <avl.h>
+#include <slap.h>
+
+LDAP_BEGIN_DECL
+
+/* define if si_ad_labeledURI is removed from slap_schema */
+#undef MONITOR_DEFINE_LABELEDURI
+
+typedef struct monitor_callback_t {
+ int (*mc_update)( Operation *op, SlapReply *rs, Entry *e, void *priv );
+ /* update callback
+ for user-defined entries */
+ int (*mc_modify)( Operation *op, SlapReply *rs, Entry *e, void *priv );
+ /* modify callback
+ for user-defined entries */
+ int (*mc_free)( Entry *e, void **priv );
+ /* delete callback
+ for user-defined entries */
+ void (*mc_dispose)( void **priv );
+ /* dispose callback
+ to dispose of the callback
+ private data itself */
+ void *mc_private; /* opaque pointer to
+ private data */
+ struct monitor_callback_t *mc_next;
+} monitor_callback_t;
+
+
+typedef struct monitor_entry_t {
+ ldap_pvt_thread_mutex_t mp_mutex; /* entry mutex */
+ Entry *mp_next; /* pointer to next sibling */
+ Entry *mp_children; /* pointer to first child */
+ struct monitor_subsys_t *mp_info; /* subsystem info */
+#define mp_type mp_info->mss_type
+ unsigned long mp_flags; /* flags */
+
+#define MONITOR_F_NONE 0x0000U
+#define MONITOR_F_SUB 0x0001U /* subentry of subsystem */
+#define MONITOR_F_PERSISTENT 0x0010U /* persistent entry */
+#define MONITOR_F_PERSISTENT_CH 0x0020U /* subsystem generates
+ persistent entries */
+#define MONITOR_F_VOLATILE 0x0040U /* volatile entry */
+#define MONITOR_F_VOLATILE_CH 0x0080U /* subsystem generates
+ volatile entries */
+#define MONITOR_F_EXTERNAL 0x0100U /* externally added - don't free */
+/* NOTE: flags with 0xF0000000U mask are reserved for subsystem internals */
+
+ struct monitor_callback_t *mp_cb; /* callback sequence */
+} monitor_entry_t;
+
+struct entry_limbo_t; /* in init.c */
+
+typedef struct monitor_info_t {
+
+ /*
+ * Internal data
+ */
+ Avlnode *mi_cache;
+ ldap_pvt_thread_mutex_t mi_cache_mutex;
+
+ /*
+ * Config parameters
+ */
+ struct berval mi_startTime; /* don't free it! */
+ struct berval mi_creatorsName; /* don't free it! */
+ struct berval mi_ncreatorsName; /* don't free it! */
+
+ /*
+ * Specific schema entities
+ */
+ ObjectClass *mi_oc_monitor;
+ ObjectClass *mi_oc_monitorServer;
+ ObjectClass *mi_oc_monitorContainer;
+ ObjectClass *mi_oc_monitorCounterObject;
+ ObjectClass *mi_oc_monitorOperation;
+ ObjectClass *mi_oc_monitorConnection;
+ ObjectClass *mi_oc_managedObject;
+ ObjectClass *mi_oc_monitoredObject;
+
+ AttributeDescription *mi_ad_monitoredInfo;
+ AttributeDescription *mi_ad_managedInfo;
+ AttributeDescription *mi_ad_monitorCounter;
+ AttributeDescription *mi_ad_monitorOpCompleted;
+ AttributeDescription *mi_ad_monitorOpInitiated;
+ AttributeDescription *mi_ad_monitorConnectionNumber;
+ AttributeDescription *mi_ad_monitorConnectionAuthzDN;
+ AttributeDescription *mi_ad_monitorConnectionLocalAddress;
+ AttributeDescription *mi_ad_monitorConnectionPeerAddress;
+ AttributeDescription *mi_ad_monitorTimestamp;
+ AttributeDescription *mi_ad_monitorOverlay;
+ AttributeDescription *mi_ad_monitorConnectionProtocol;
+ AttributeDescription *mi_ad_monitorConnectionOpsReceived;
+ AttributeDescription *mi_ad_monitorConnectionOpsExecuting;
+ AttributeDescription *mi_ad_monitorConnectionOpsPending;
+ AttributeDescription *mi_ad_monitorConnectionOpsCompleted;
+ AttributeDescription *mi_ad_monitorConnectionGet;
+ AttributeDescription *mi_ad_monitorConnectionRead;
+ AttributeDescription *mi_ad_monitorConnectionWrite;
+ AttributeDescription *mi_ad_monitorConnectionMask;
+ AttributeDescription *mi_ad_monitorConnectionListener;
+ AttributeDescription *mi_ad_monitorConnectionPeerDomain;
+ AttributeDescription *mi_ad_monitorConnectionStartTime;
+ AttributeDescription *mi_ad_monitorConnectionActivityTime;
+ AttributeDescription *mi_ad_monitorIsShadow;
+ AttributeDescription *mi_ad_monitorUpdateRef;
+ AttributeDescription *mi_ad_monitorRuntimeConfig;
+ AttributeDescription *mi_ad_monitorSuperiorDN;
+
+ /*
+ * Generic description attribute
+ */
+ AttributeDescription *mi_ad_readOnly;
+ AttributeDescription *mi_ad_restrictedOperation;
+
+ struct entry_limbo_t *mi_entry_limbo;
+} monitor_info_t;
+
+/*
+ * DNs
+ */
+
+enum {
+ SLAPD_MONITOR_BACKEND = 0,
+ SLAPD_MONITOR_CONN,
+ SLAPD_MONITOR_DATABASE,
+ SLAPD_MONITOR_LISTENER,
+ SLAPD_MONITOR_LOG,
+ SLAPD_MONITOR_OPS,
+ SLAPD_MONITOR_OVERLAY,
+ SLAPD_MONITOR_SASL,
+ SLAPD_MONITOR_SENT,
+ SLAPD_MONITOR_THREAD,
+ SLAPD_MONITOR_TIME,
+ SLAPD_MONITOR_TLS,
+ SLAPD_MONITOR_RWW,
+
+ SLAPD_MONITOR_LAST
+};
+
+#define SLAPD_MONITOR_AT "cn"
+
+#define SLAPD_MONITOR_BACKEND_NAME "Backends"
+#define SLAPD_MONITOR_BACKEND_RDN \
+ SLAPD_MONITOR_AT "=" SLAPD_MONITOR_BACKEND_NAME
+#define SLAPD_MONITOR_BACKEND_DN \
+ SLAPD_MONITOR_BACKEND_RDN "," SLAPD_MONITOR_DN
+
+#define SLAPD_MONITOR_CONN_NAME "Connections"
+#define SLAPD_MONITOR_CONN_RDN \
+ SLAPD_MONITOR_AT "=" SLAPD_MONITOR_CONN_NAME
+#define SLAPD_MONITOR_CONN_DN \
+ SLAPD_MONITOR_CONN_RDN "," SLAPD_MONITOR_DN
+
+#define SLAPD_MONITOR_DATABASE_NAME "Databases"
+#define SLAPD_MONITOR_DATABASE_RDN \
+ SLAPD_MONITOR_AT "=" SLAPD_MONITOR_DATABASE_NAME
+#define SLAPD_MONITOR_DATABASE_DN \
+ SLAPD_MONITOR_DATABASE_RDN "," SLAPD_MONITOR_DN
+
+#define SLAPD_MONITOR_LISTENER_NAME "Listeners"
+#define SLAPD_MONITOR_LISTENER_RDN \
+ SLAPD_MONITOR_AT "=" SLAPD_MONITOR_LISTENER_NAME
+#define SLAPD_MONITOR_LISTENER_DN \
+ SLAPD_MONITOR_LISTENER_RDN "," SLAPD_MONITOR_DN
+
+#define SLAPD_MONITOR_LOG_NAME "Log"
+#define SLAPD_MONITOR_LOG_RDN \
+ SLAPD_MONITOR_AT "=" SLAPD_MONITOR_LOG_NAME
+#define SLAPD_MONITOR_LOG_DN \
+ SLAPD_MONITOR_LOG_RDN "," SLAPD_MONITOR_DN
+
+#define SLAPD_MONITOR_OPS_NAME "Operations"
+#define SLAPD_MONITOR_OPS_RDN \
+ SLAPD_MONITOR_AT "=" SLAPD_MONITOR_OPS_NAME
+#define SLAPD_MONITOR_OPS_DN \
+ SLAPD_MONITOR_OPS_RDN "," SLAPD_MONITOR_DN
+
+#define SLAPD_MONITOR_OVERLAY_NAME "Overlays"
+#define SLAPD_MONITOR_OVERLAY_RDN \
+ SLAPD_MONITOR_AT "=" SLAPD_MONITOR_OVERLAY_NAME
+#define SLAPD_MONITOR_OVERLAY_DN \
+ SLAPD_MONITOR_OVERLAY_RDN "," SLAPD_MONITOR_DN
+
+#define SLAPD_MONITOR_SASL_NAME "SASL"
+#define SLAPD_MONITOR_SASL_RDN \
+ SLAPD_MONITOR_AT "=" SLAPD_MONITOR_SASL_NAME
+#define SLAPD_MONITOR_SASL_DN \
+ SLAPD_MONITOR_SASL_RDN "," SLAPD_MONITOR_DN
+
+#define SLAPD_MONITOR_SENT_NAME "Statistics"
+#define SLAPD_MONITOR_SENT_RDN \
+ SLAPD_MONITOR_AT "=" SLAPD_MONITOR_SENT_NAME
+#define SLAPD_MONITOR_SENT_DN \
+ SLAPD_MONITOR_SENT_RDN "," SLAPD_MONITOR_DN
+
+#define SLAPD_MONITOR_THREAD_NAME "Threads"
+#define SLAPD_MONITOR_THREAD_RDN \
+ SLAPD_MONITOR_AT "=" SLAPD_MONITOR_THREAD_NAME
+#define SLAPD_MONITOR_THREAD_DN \
+ SLAPD_MONITOR_THREAD_RDN "," SLAPD_MONITOR_DN
+
+#define SLAPD_MONITOR_TIME_NAME "Time"
+#define SLAPD_MONITOR_TIME_RDN \
+ SLAPD_MONITOR_AT "=" SLAPD_MONITOR_TIME_NAME
+#define SLAPD_MONITOR_TIME_DN \
+ SLAPD_MONITOR_TIME_RDN "," SLAPD_MONITOR_DN
+
+#define SLAPD_MONITOR_TLS_NAME "TLS"
+#define SLAPD_MONITOR_TLS_RDN \
+ SLAPD_MONITOR_AT "=" SLAPD_MONITOR_TLS_NAME
+#define SLAPD_MONITOR_TLS_DN \
+ SLAPD_MONITOR_TLS_RDN "," SLAPD_MONITOR_DN
+
+#define SLAPD_MONITOR_RWW_NAME "Waiters"
+#define SLAPD_MONITOR_RWW_RDN \
+ SLAPD_MONITOR_AT "=" SLAPD_MONITOR_RWW_NAME
+#define SLAPD_MONITOR_RWW_DN \
+ SLAPD_MONITOR_RWW_RDN "," SLAPD_MONITOR_DN
+
+typedef struct monitor_subsys_t {
+ char *mss_name;
+ struct berval mss_rdn;
+ struct berval mss_dn;
+ struct berval mss_ndn;
+ struct berval mss_desc[ 3 ];
+ int mss_flags;
+#define MONITOR_F_OPENED 0x10000000U
+
+#define MONITOR_HAS_VOLATILE_CH( mp ) \
+ ( ( mp )->mp_flags & MONITOR_F_VOLATILE_CH )
+#define MONITOR_HAS_CHILDREN( mp ) \
+ ( ( mp )->mp_children || MONITOR_HAS_VOLATILE_CH( mp ) )
+
+ /* initialize entry and subentries */
+ int ( *mss_open )( BackendDB *, struct monitor_subsys_t *ms );
+ /* destroy structure */
+ int ( *mss_destroy )( BackendDB *, struct monitor_subsys_t *ms );
+ /* update existing dynamic entry and subentries */
+ int ( *mss_update )( Operation *, SlapReply *, Entry * );
+ /* create new dynamic subentries */
+ int ( *mss_create )( Operation *, SlapReply *,
+ struct berval *ndn, Entry *, Entry ** );
+ /* modify entry and subentries */
+ int ( *mss_modify )( Operation *, SlapReply *, Entry * );
+
+ void *mss_private;
+} monitor_subsys_t;
+
+extern BackendDB *be_monitor;
+
+/* increase this bufsize if entries in string form get too big */
+#define BACKMONITOR_BUFSIZE 8192
+
+typedef int (monitor_cbfunc)( struct berval *ndn, monitor_callback_t *cb,
+ struct berval *base, int scope, struct berval *filter );
+
+typedef int (monitor_cbafunc)( struct berval *ndn, Attribute *a,
+ monitor_callback_t *cb,
+ struct berval *base, int scope, struct berval *filter );
+
+typedef struct monitor_extra_t {
+ int (*is_configured)(void);
+ monitor_subsys_t * (*get_subsys)( const char *name );
+ monitor_subsys_t * (*get_subsys_by_dn)( struct berval *ndn, int sub );
+
+ int (*register_subsys)( monitor_subsys_t *ms );
+ int (*register_backend)( BackendInfo *bi );
+ int (*register_database)( BackendDB *be, struct berval *ndn_out );
+ int (*register_overlay_info)( slap_overinst *on );
+ int (*register_overlay)( BackendDB *be, slap_overinst *on, struct berval *ndn_out );
+ int (*register_entry)( Entry *e, monitor_callback_t *cb,
+ monitor_subsys_t *ms, unsigned long flags );
+ int (*register_entry_parent)( Entry *e, monitor_callback_t *cb,
+ monitor_subsys_t *ms, unsigned long flags,
+ struct berval *base, int scope, struct berval *filter );
+ monitor_cbafunc *register_entry_attrs;
+ monitor_cbfunc *register_entry_callback;
+
+ int (*unregister_entry)( struct berval *ndn );
+ monitor_cbfunc *unregister_entry_parent;
+ monitor_cbafunc *unregister_entry_attrs;
+ monitor_cbfunc *unregister_entry_callback;
+ Entry * (*entry_stub)( struct berval *pdn,
+ struct berval *pndn,
+ struct berval *rdn,
+ ObjectClass *oc,
+ struct berval *create,
+ struct berval *modify );
+ monitor_entry_t * (*entrypriv_create)( void );
+ int (*register_subsys_late)( monitor_subsys_t *ms );
+} monitor_extra_t;
+
+LDAP_END_DECL
+
+#include "proto-back-monitor.h"
+
+#endif /* _back_monitor_h_ */
+
diff --git a/servers/slapd/back-monitor/backend.c b/servers/slapd/back-monitor/backend.c
new file mode 100644
index 0000000..183e0b8
--- /dev/null
+++ b/servers/slapd/back-monitor/backend.c
@@ -0,0 +1,160 @@
+/* backend.c - deals with backend subsystem */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2001-2018 The OpenLDAP Foundation.
+ * Portions Copyright 2001-2003 Pierangelo Masarati.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Pierangelo Masarati for inclusion
+ * in OpenLDAP Software.
+ */
+
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+
+#include "slap.h"
+#include "back-monitor.h"
+
+/*
+ * initializes backend subentries
+ */
+int
+monitor_subsys_backend_init(
+ BackendDB *be,
+ monitor_subsys_t *ms
+)
+{
+ monitor_info_t *mi;
+ Entry *e_backend, **ep;
+ int i;
+ monitor_entry_t *mp;
+ monitor_subsys_t *ms_database;
+ BackendInfo *bi;
+
+ mi = ( monitor_info_t * )be->be_private;
+
+ ms_database = monitor_back_get_subsys( SLAPD_MONITOR_DATABASE_NAME );
+ if ( ms_database == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_backend_init: "
+ "unable to get "
+ "\"" SLAPD_MONITOR_DATABASE_NAME "\" "
+ "subsystem\n",
+ 0, 0, 0 );
+ return -1;
+ }
+
+ if ( monitor_cache_get( mi, &ms->mss_ndn, &e_backend ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_backend_init: "
+ "unable to get entry \"%s\"\n",
+ ms->mss_ndn.bv_val, 0, 0 );
+ return( -1 );
+ }
+
+ mp = ( monitor_entry_t * )e_backend->e_private;
+ mp->mp_children = NULL;
+ ep = &mp->mp_children;
+
+ i = -1;
+ LDAP_STAILQ_FOREACH( bi, &backendInfo, bi_next ) {
+ char buf[ BACKMONITOR_BUFSIZE ];
+ BackendDB *be;
+ struct berval bv;
+ int j;
+ Entry *e;
+
+ i++;
+
+ bv.bv_len = snprintf( buf, sizeof( buf ), "cn=Backend %d", i );
+ bv.bv_val = buf;
+
+ e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, &bv,
+ mi->mi_oc_monitoredObject, NULL, NULL );
+
+ if ( e == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_backend_init: "
+ "unable to create entry \"cn=Backend %d,%s\"\n",
+ i, ms->mss_ndn.bv_val, 0 );
+ return( -1 );
+ }
+
+ ber_str2bv( bi->bi_type, 0, 0, &bv );
+ attr_merge_normalize_one( e, mi->mi_ad_monitoredInfo,
+ &bv, NULL );
+ attr_merge_normalize_one( e_backend, mi->mi_ad_monitoredInfo,
+ &bv, NULL );
+
+ attr_merge_normalize_one( e, mi->mi_ad_monitorRuntimeConfig,
+ bi->bi_cf_ocs == NULL ? (struct berval *)&slap_false_bv :
+ (struct berval *)&slap_true_bv, NULL );
+
+ if ( bi->bi_controls ) {
+ int j;
+
+ for ( j = 0; bi->bi_controls[ j ]; j++ ) {
+ ber_str2bv( bi->bi_controls[ j ], 0, 0, &bv );
+ attr_merge_one( e, slap_schema.si_ad_supportedControl,
+ &bv, &bv );
+ }
+ }
+
+ j = -1;
+ LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) {
+ char buf[ SLAP_LDAPDN_MAXLEN ];
+ struct berval dn;
+
+ j++;
+
+ if ( be->bd_info != bi ) {
+ continue;
+ }
+
+ snprintf( buf, sizeof( buf ), "cn=Database %d,%s",
+ j, ms_database->mss_dn.bv_val );
+
+ ber_str2bv( buf, 0, 0, &dn );
+ attr_merge_normalize_one( e, slap_schema.si_ad_seeAlso,
+ &dn, NULL );
+ }
+
+ mp = monitor_entrypriv_create();
+ if ( mp == NULL ) {
+ return -1;
+ }
+ e->e_private = ( void * )mp;
+ mp->mp_info = ms;
+ mp->mp_flags = ms->mss_flags | MONITOR_F_SUB;
+
+ if ( monitor_cache_add( mi, e ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_backend_init: "
+ "unable to add entry \"cn=Backend %d,%s\"\n",
+ i,
+ ms->mss_ndn.bv_val, 0 );
+ return( -1 );
+ }
+
+ *ep = e;
+ ep = &mp->mp_next;
+ }
+
+ monitor_cache_release( mi, e_backend );
+
+ return( 0 );
+}
+
diff --git a/servers/slapd/back-monitor/bind.c b/servers/slapd/back-monitor/bind.c
new file mode 100644
index 0000000..ce68b47
--- /dev/null
+++ b/servers/slapd/back-monitor/bind.c
@@ -0,0 +1,48 @@
+/* bind.c - monitor backend bind routine */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2001-2018 The OpenLDAP Foundation.
+ * Portions Copyright 2001-2003 Pierangelo Masarati.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Pierangelo Masarati for inclusion
+ * in OpenLDAP Software.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <slap.h>
+#include "back-monitor.h"
+
+/*
+ * At present, only rootdn can bind with simple bind
+ */
+
+int
+monitor_back_bind( Operation *op, SlapReply *rs )
+{
+ Debug(LDAP_DEBUG_ARGS, "==> monitor_back_bind: dn: %s\n",
+ op->o_req_dn.bv_val, 0, 0 );
+
+ if ( be_isroot_pw( op ) ) {
+ return LDAP_SUCCESS;
+ }
+
+ rs->sr_err = LDAP_INVALID_CREDENTIALS;
+ send_ldap_result( op, rs );
+
+ return rs->sr_err;
+}
+
diff --git a/servers/slapd/back-monitor/cache.c b/servers/slapd/back-monitor/cache.c
new file mode 100644
index 0000000..c8b4f1d
--- /dev/null
+++ b/servers/slapd/back-monitor/cache.c
@@ -0,0 +1,449 @@
+/* cache.c - routines to maintain an in-core cache of entries */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2001-2018 The OpenLDAP Foundation.
+ * Portions Copyright 2001-2003 Pierangelo Masarati.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Pierangelo Masarati for inclusion
+ * in OpenLDAP Software.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include "ac/string.h"
+
+#include "slap.h"
+
+#include "back-monitor.h"
+
+/*
+ * The cache maps DNs to Entries.
+ * Each entry, on turn, holds the list of its children in the e_private field.
+ * This is used by search operation to perform onelevel and subtree candidate
+ * selection.
+ */
+typedef struct monitor_cache_t {
+ struct berval mc_ndn;
+ Entry *mc_e;
+} monitor_cache_t;
+
+/*
+ * compares entries based on the dn
+ */
+int
+monitor_cache_cmp(
+ const void *c1,
+ const void *c2 )
+{
+ monitor_cache_t *cc1 = ( monitor_cache_t * )c1;
+ monitor_cache_t *cc2 = ( monitor_cache_t * )c2;
+
+ /*
+ * case sensitive, because the dn MUST be normalized
+ */
+ return ber_bvcmp( &cc1->mc_ndn, &cc2->mc_ndn );
+}
+
+/*
+ * checks for duplicate entries
+ */
+int
+monitor_cache_dup(
+ void *c1,
+ void *c2 )
+{
+ monitor_cache_t *cc1 = ( monitor_cache_t * )c1;
+ monitor_cache_t *cc2 = ( monitor_cache_t * )c2;
+
+ /*
+ * case sensitive, because the dn MUST be normalized
+ */
+ return ber_bvcmp( &cc1->mc_ndn, &cc2->mc_ndn ) == 0 ? -1 : 0;
+}
+
+/*
+ * adds an entry to the cache and inits the mutex
+ */
+int
+monitor_cache_add(
+ monitor_info_t *mi,
+ Entry *e )
+{
+ monitor_cache_t *mc;
+ monitor_entry_t *mp;
+ int rc;
+
+ assert( mi != NULL );
+ assert( e != NULL );
+
+ mp = ( monitor_entry_t *)e->e_private;
+
+ mc = ( monitor_cache_t * )ch_malloc( sizeof( monitor_cache_t ) );
+ mc->mc_ndn = e->e_nname;
+ mc->mc_e = e;
+ ldap_pvt_thread_mutex_lock( &mi->mi_cache_mutex );
+ rc = avl_insert( &mi->mi_cache, ( caddr_t )mc,
+ monitor_cache_cmp, monitor_cache_dup );
+ ldap_pvt_thread_mutex_unlock( &mi->mi_cache_mutex );
+
+ return rc;
+}
+
+/*
+ * locks the entry (no r/w)
+ */
+int
+monitor_cache_lock(
+ Entry *e )
+{
+ monitor_entry_t *mp;
+
+ assert( e != NULL );
+ assert( e->e_private != NULL );
+
+ mp = ( monitor_entry_t * )e->e_private;
+ ldap_pvt_thread_mutex_lock( &mp->mp_mutex );
+
+ return( 0 );
+}
+
+/*
+ * tries to lock the entry (no r/w)
+ */
+int
+monitor_cache_trylock(
+ Entry *e )
+{
+ monitor_entry_t *mp;
+
+ assert( e != NULL );
+ assert( e->e_private != NULL );
+
+ mp = ( monitor_entry_t * )e->e_private;
+ return ldap_pvt_thread_mutex_trylock( &mp->mp_mutex );
+}
+
+/*
+ * gets an entry from the cache based on the normalized dn
+ * with mutex locked
+ */
+int
+monitor_cache_get(
+ monitor_info_t *mi,
+ struct berval *ndn,
+ Entry **ep )
+{
+ monitor_cache_t tmp_mc, *mc;
+
+ assert( mi != NULL );
+ assert( ndn != NULL );
+ assert( ep != NULL );
+
+ *ep = NULL;
+
+ tmp_mc.mc_ndn = *ndn;
+retry:;
+ ldap_pvt_thread_mutex_lock( &mi->mi_cache_mutex );
+ mc = ( monitor_cache_t * )avl_find( mi->mi_cache,
+ ( caddr_t )&tmp_mc, monitor_cache_cmp );
+
+ if ( mc != NULL ) {
+ /* entry is returned with mutex locked */
+ if ( monitor_cache_trylock( mc->mc_e ) ) {
+ ldap_pvt_thread_mutex_unlock( &mi->mi_cache_mutex );
+ ldap_pvt_thread_yield();
+ goto retry;
+ }
+ *ep = mc->mc_e;
+ }
+
+ ldap_pvt_thread_mutex_unlock( &mi->mi_cache_mutex );
+
+ return ( *ep == NULL ? -1 : 0 );
+}
+
+/*
+ * gets an entry from the cache based on the normalized dn
+ * with mutex locked
+ */
+int
+monitor_cache_remove(
+ monitor_info_t *mi,
+ struct berval *ndn,
+ Entry **ep )
+{
+ monitor_cache_t tmp_mc, *mc;
+ struct berval pndn;
+
+ assert( mi != NULL );
+ assert( ndn != NULL );
+ assert( ep != NULL );
+
+ *ep = NULL;
+
+ dnParent( ndn, &pndn );
+
+retry:;
+ ldap_pvt_thread_mutex_lock( &mi->mi_cache_mutex );
+
+ tmp_mc.mc_ndn = *ndn;
+ mc = ( monitor_cache_t * )avl_find( mi->mi_cache,
+ ( caddr_t )&tmp_mc, monitor_cache_cmp );
+
+ if ( mc != NULL ) {
+ monitor_cache_t *pmc;
+
+ if ( monitor_cache_trylock( mc->mc_e ) ) {
+ ldap_pvt_thread_mutex_unlock( &mi->mi_cache_mutex );
+ goto retry;
+ }
+
+ tmp_mc.mc_ndn = pndn;
+ pmc = ( monitor_cache_t * )avl_find( mi->mi_cache,
+ ( caddr_t )&tmp_mc, monitor_cache_cmp );
+ if ( pmc != NULL ) {
+ monitor_entry_t *mp = (monitor_entry_t *)mc->mc_e->e_private,
+ *pmp = (monitor_entry_t *)pmc->mc_e->e_private;
+ Entry **entryp;
+
+ if ( monitor_cache_trylock( pmc->mc_e ) ) {
+ monitor_cache_release( mi, mc->mc_e );
+ ldap_pvt_thread_mutex_unlock( &mi->mi_cache_mutex );
+ goto retry;
+ }
+
+ for ( entryp = &pmp->mp_children; *entryp != NULL; ) {
+ monitor_entry_t *next = (monitor_entry_t *)(*entryp)->e_private;
+ if ( next == mp ) {
+ *entryp = next->mp_next;
+ entryp = NULL;
+ break;
+ }
+
+ entryp = &next->mp_next;
+ }
+
+ if ( entryp != NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_cache_remove(\"%s\"): "
+ "not in parent's list\n",
+ ndn->bv_val, 0, 0 );
+ }
+
+ /* either succeeded, and the entry is no longer
+ * in its parent's list, or failed, and the
+ * entry is neither mucked with nor returned */
+ monitor_cache_release( mi, pmc->mc_e );
+
+ if ( entryp == NULL ) {
+ monitor_cache_t *tmpmc;
+
+ tmp_mc.mc_ndn = *ndn;
+ tmpmc = avl_delete( &mi->mi_cache,
+ ( caddr_t )&tmp_mc, monitor_cache_cmp );
+ assert( tmpmc == mc );
+
+ *ep = mc->mc_e;
+ ch_free( mc );
+ mc = NULL;
+
+ /* NOTE: we destroy the mutex, but otherwise
+ * leave the private data around; specifically,
+ * callbacks need be freed by someone else */
+
+ ldap_pvt_thread_mutex_destroy( &mp->mp_mutex );
+ mp->mp_next = NULL;
+ mp->mp_children = NULL;
+ }
+
+ }
+
+ if ( mc ) {
+ monitor_cache_release( mi, mc->mc_e );
+ }
+ }
+
+ ldap_pvt_thread_mutex_unlock( &mi->mi_cache_mutex );
+
+ return ( *ep == NULL ? -1 : 0 );
+}
+
+/*
+ * If the entry exists in cache, it is returned in locked status;
+ * otherwise, if the parent exists, if it may generate volatile
+ * descendants an attempt to generate the required entry is
+ * performed and, if successful, the entry is returned
+ */
+int
+monitor_cache_dn2entry(
+ Operation *op,
+ SlapReply *rs,
+ struct berval *ndn,
+ Entry **ep,
+ Entry **matched )
+{
+ monitor_info_t *mi = (monitor_info_t *)op->o_bd->be_private;
+ int rc;
+ struct berval p_ndn = BER_BVNULL;
+ Entry *e_parent;
+ monitor_entry_t *mp;
+
+ assert( mi != NULL );
+ assert( ndn != NULL );
+ assert( ep != NULL );
+ assert( matched != NULL );
+
+ *matched = NULL;
+
+ if ( !dnIsSuffix( ndn, &op->o_bd->be_nsuffix[ 0 ] ) ) {
+ return( -1 );
+ }
+
+ rc = monitor_cache_get( mi, ndn, ep );
+ if ( !rc && *ep != NULL ) {
+ return( 0 );
+ }
+
+ /* try with parent/ancestors */
+ if ( BER_BVISNULL( ndn ) ) {
+ BER_BVSTR( &p_ndn, "" );
+
+ } else {
+ dnParent( ndn, &p_ndn );
+ }
+
+ rc = monitor_cache_dn2entry( op, rs, &p_ndn, &e_parent, matched );
+ if ( rc || e_parent == NULL ) {
+ return( -1 );
+ }
+
+ mp = ( monitor_entry_t * )e_parent->e_private;
+ rc = -1;
+ if ( mp->mp_flags & MONITOR_F_VOLATILE_CH ) {
+ /* parent entry generates volatile children */
+ rc = monitor_entry_create( op, rs, ndn, e_parent, ep );
+ }
+
+ if ( !rc ) {
+ monitor_cache_lock( *ep );
+ monitor_cache_release( mi, e_parent );
+
+ } else {
+ *matched = e_parent;
+ }
+
+ return( rc );
+}
+
+/*
+ * releases the lock of the entry; if it is marked as volatile, it is
+ * destroyed.
+ */
+int
+monitor_cache_release(
+ monitor_info_t *mi,
+ Entry *e )
+{
+ monitor_entry_t *mp;
+
+ assert( mi != NULL );
+ assert( e != NULL );
+ assert( e->e_private != NULL );
+
+ mp = ( monitor_entry_t * )e->e_private;
+
+ if ( mp->mp_flags & MONITOR_F_VOLATILE ) {
+ monitor_cache_t *mc, tmp_mc;
+
+ /* volatile entries do not return to cache */
+ ldap_pvt_thread_mutex_lock( &mi->mi_cache_mutex );
+ tmp_mc.mc_ndn = e->e_nname;
+ mc = avl_delete( &mi->mi_cache,
+ ( caddr_t )&tmp_mc, monitor_cache_cmp );
+ ldap_pvt_thread_mutex_unlock( &mi->mi_cache_mutex );
+ if ( mc != NULL ) {
+ ch_free( mc );
+ }
+
+ ldap_pvt_thread_mutex_unlock( &mp->mp_mutex );
+ ldap_pvt_thread_mutex_destroy( &mp->mp_mutex );
+ ch_free( mp );
+ e->e_private = NULL;
+ entry_free( e );
+
+ return( 0 );
+ }
+
+ ldap_pvt_thread_mutex_unlock( &mp->mp_mutex );
+
+ return( 0 );
+}
+
+static void
+monitor_entry_destroy( void *v_mc )
+{
+ monitor_cache_t *mc = (monitor_cache_t *)v_mc;
+
+ if ( mc->mc_e != NULL ) {
+ monitor_entry_t *mp;
+
+ assert( mc->mc_e->e_private != NULL );
+
+ mp = ( monitor_entry_t * )mc->mc_e->e_private;
+
+ if ( mp->mp_cb ) {
+ monitor_callback_t *cb;
+
+ for ( cb = mp->mp_cb; cb != NULL; ) {
+ monitor_callback_t *next = cb->mc_next;
+
+ if ( cb->mc_free ) {
+ (void)cb->mc_free( mc->mc_e, &cb->mc_private );
+ }
+ ch_free( mp->mp_cb );
+
+ cb = next;
+ }
+ }
+
+ ldap_pvt_thread_mutex_destroy( &mp->mp_mutex );
+
+ ch_free( mp );
+ mc->mc_e->e_private = NULL;
+ entry_free( mc->mc_e );
+ }
+
+ ch_free( mc );
+}
+
+int
+monitor_cache_destroy(
+ monitor_info_t *mi )
+{
+ if ( mi->mi_cache ) {
+ avl_free( mi->mi_cache, monitor_entry_destroy );
+ }
+
+ return 0;
+}
+
+int monitor_back_release(
+ Operation *op,
+ Entry *e,
+ int rw )
+{
+ monitor_info_t *mi = ( monitor_info_t * )op->o_bd->be_private;
+ return monitor_cache_release( mi, e );
+}
diff --git a/servers/slapd/back-monitor/compare.c b/servers/slapd/back-monitor/compare.c
new file mode 100644
index 0000000..c6f53da
--- /dev/null
+++ b/servers/slapd/back-monitor/compare.c
@@ -0,0 +1,76 @@
+/* compare.c - monitor backend compare routine */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2001-2018 The OpenLDAP Foundation.
+ * Portions Copyright 2001-2003 Pierangelo Masarati.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Pierangelo Masarati for inclusion
+ * in OpenLDAP Software.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <slap.h>
+#include "back-monitor.h"
+
+int
+monitor_back_compare( Operation *op, SlapReply *rs )
+{
+ monitor_info_t *mi = ( monitor_info_t * ) op->o_bd->be_private;
+ Entry *e, *matched = NULL;
+ int rc;
+
+ /* get entry with reader lock */
+ monitor_cache_dn2entry( op, rs, &op->o_req_ndn, &e, &matched );
+ if ( e == NULL ) {
+ rs->sr_err = LDAP_NO_SUCH_OBJECT;
+ if ( matched ) {
+ if ( !access_allowed_mask( op, matched,
+ slap_schema.si_ad_entry,
+ NULL, ACL_DISCLOSE, NULL, NULL ) )
+ {
+ /* do nothing */ ;
+ } else {
+ rs->sr_matched = matched->e_dn;
+ }
+ }
+ send_ldap_result( op, rs );
+ if ( matched ) {
+ monitor_cache_release( mi, matched );
+ rs->sr_matched = NULL;
+ }
+
+ return rs->sr_err;
+ }
+
+ monitor_entry_update( op, rs, e );
+ rs->sr_err = slap_compare_entry( op, e, op->orc_ava );
+ rc = rs->sr_err;
+ switch ( rc ) {
+ case LDAP_COMPARE_FALSE:
+ case LDAP_COMPARE_TRUE:
+ rc = LDAP_SUCCESS;
+ break;
+ }
+
+ send_ldap_result( op, rs );
+ rs->sr_err = rc;
+
+ monitor_cache_release( mi, e );
+
+ return rs->sr_err;
+}
+
diff --git a/servers/slapd/back-monitor/conn.c b/servers/slapd/back-monitor/conn.c
new file mode 100644
index 0000000..aeb398b
--- /dev/null
+++ b/servers/slapd/back-monitor/conn.c
@@ -0,0 +1,528 @@
+/* conn.c - deal with connection subsystem */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2001-2018 The OpenLDAP Foundation.
+ * Portions Copyright 2001-2003 Pierangelo Masarati.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Pierangelo Masarati for inclusion
+ * in OpenLDAP Software.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+
+#include "slap.h"
+#include "lutil.h"
+#include "back-monitor.h"
+
+static int
+monitor_subsys_conn_update(
+ Operation *op,
+ SlapReply *rs,
+ Entry *e );
+
+static int
+monitor_subsys_conn_create(
+ Operation *op,
+ SlapReply *rs,
+ struct berval *ndn,
+ Entry *e_parent,
+ Entry **ep );
+
+int
+monitor_subsys_conn_init(
+ BackendDB *be,
+ monitor_subsys_t *ms )
+{
+ monitor_info_t *mi;
+ Entry *e, **ep, *e_conn;
+ monitor_entry_t *mp;
+ char buf[ BACKMONITOR_BUFSIZE ];
+ struct berval bv;
+
+ assert( be != NULL );
+
+ ms->mss_update = monitor_subsys_conn_update;
+ ms->mss_create = monitor_subsys_conn_create;
+
+ mi = ( monitor_info_t * )be->be_private;
+
+ if ( monitor_cache_get( mi, &ms->mss_ndn, &e_conn ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_conn_init: "
+ "unable to get entry \"%s\"\n",
+ ms->mss_ndn.bv_val, 0, 0 );
+ return( -1 );
+ }
+
+ mp = ( monitor_entry_t * )e_conn->e_private;
+ mp->mp_children = NULL;
+ ep = &mp->mp_children;
+
+ /*
+ * Max file descriptors
+ */
+ BER_BVSTR( &bv, "cn=Max File Descriptors" );
+ e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, &bv,
+ mi->mi_oc_monitorCounterObject, NULL, NULL );
+
+ if ( e == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_conn_init: "
+ "unable to create entry \"%s,%s\"\n",
+ bv.bv_val, ms->mss_ndn.bv_val, 0 );
+ return( -1 );
+ }
+
+ if ( dtblsize ) {
+ bv.bv_val = buf;
+ bv.bv_len = snprintf( buf, sizeof( buf ), "%d", dtblsize );
+
+ } else {
+ BER_BVSTR( &bv, "0" );
+ }
+ attr_merge_one( e, mi->mi_ad_monitorCounter, &bv, NULL );
+
+ mp = monitor_entrypriv_create();
+ if ( mp == NULL ) {
+ return -1;
+ }
+ e->e_private = ( void * )mp;
+ mp->mp_info = ms;
+ mp->mp_flags = ms->mss_flags \
+ | MONITOR_F_SUB | MONITOR_F_PERSISTENT;
+ mp->mp_flags &= ~MONITOR_F_VOLATILE_CH;
+
+ if ( monitor_cache_add( mi, e ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_conn_init: "
+ "unable to add entry \"cn=Total,%s\"\n",
+ ms->mss_ndn.bv_val, 0, 0 );
+ return( -1 );
+ }
+
+ *ep = e;
+ ep = &mp->mp_next;
+
+ /*
+ * Total conns
+ */
+ BER_BVSTR( &bv, "cn=Total" );
+ e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, &bv,
+ mi->mi_oc_monitorCounterObject, NULL, NULL );
+
+ if ( e == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_conn_init: "
+ "unable to create entry \"cn=Total,%s\"\n",
+ ms->mss_ndn.bv_val, 0, 0 );
+ return( -1 );
+ }
+
+ BER_BVSTR( &bv, "-1" );
+ attr_merge_one( e, mi->mi_ad_monitorCounter, &bv, NULL );
+
+ mp = monitor_entrypriv_create();
+ if ( mp == NULL ) {
+ return -1;
+ }
+ e->e_private = ( void * )mp;
+ mp->mp_info = ms;
+ mp->mp_flags = ms->mss_flags \
+ | MONITOR_F_SUB | MONITOR_F_PERSISTENT;
+ mp->mp_flags &= ~MONITOR_F_VOLATILE_CH;
+
+ if ( monitor_cache_add( mi, e ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_conn_init: "
+ "unable to add entry \"cn=Total,%s\"\n",
+ ms->mss_ndn.bv_val, 0, 0 );
+ return( -1 );
+ }
+
+ *ep = e;
+ ep = &mp->mp_next;
+
+ /*
+ * Current conns
+ */
+ BER_BVSTR( &bv, "cn=Current" );
+ e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, &bv,
+ mi->mi_oc_monitorCounterObject, NULL, NULL );
+
+ if ( e == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_conn_init: "
+ "unable to create entry \"cn=Current,%s\"\n",
+ ms->mss_ndn.bv_val, 0, 0 );
+ return( -1 );
+ }
+
+ BER_BVSTR( &bv, "0" );
+ attr_merge_one( e, mi->mi_ad_monitorCounter, &bv, NULL );
+
+ mp = monitor_entrypriv_create();
+ if ( mp == NULL ) {
+ return -1;
+ }
+ e->e_private = ( void * )mp;
+ mp->mp_info = ms;
+ mp->mp_flags = ms->mss_flags \
+ | MONITOR_F_SUB | MONITOR_F_PERSISTENT;
+ mp->mp_flags &= ~MONITOR_F_VOLATILE_CH;
+
+ if ( monitor_cache_add( mi, e ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_conn_init: "
+ "unable to add entry \"cn=Current,%s\"\n",
+ ms->mss_ndn.bv_val, 0, 0 );
+ return( -1 );
+ }
+
+ *ep = e;
+ ep = &mp->mp_next;
+
+ monitor_cache_release( mi, e_conn );
+
+ return( 0 );
+}
+
+static int
+monitor_subsys_conn_update(
+ Operation *op,
+ SlapReply *rs,
+ Entry *e )
+{
+ monitor_info_t *mi = ( monitor_info_t * )op->o_bd->be_private;
+
+ long n = -1;
+ static struct berval total_bv = BER_BVC( "cn=total" ),
+ current_bv = BER_BVC( "cn=current" );
+ struct berval rdn;
+
+ assert( mi != NULL );
+ assert( e != NULL );
+
+ dnRdn( &e->e_nname, &rdn );
+
+ if ( dn_match( &rdn, &total_bv ) ) {
+ n = connections_nextid();
+
+ } else if ( dn_match( &rdn, &current_bv ) ) {
+ Connection *c;
+ ber_socket_t connindex;
+
+ for ( n = 0, c = connection_first( &connindex );
+ c != NULL;
+ n++, c = connection_next( c, &connindex ) )
+ {
+ /* No Op */ ;
+ }
+ connection_done( c );
+ }
+
+ if ( n != -1 ) {
+ Attribute *a;
+ char buf[LDAP_PVT_INTTYPE_CHARS(long)];
+ ber_len_t len;
+
+ a = attr_find( e->e_attrs, mi->mi_ad_monitorCounter );
+ if ( a == NULL ) {
+ return( -1 );
+ }
+
+ snprintf( buf, sizeof( buf ), "%ld", n );
+ len = strlen( buf );
+ if ( len > a->a_vals[ 0 ].bv_len ) {
+ a->a_vals[ 0 ].bv_val = ber_memrealloc( a->a_vals[ 0 ].bv_val, len + 1 );
+ }
+ a->a_vals[ 0 ].bv_len = len;
+ AC_MEMCPY( a->a_vals[ 0 ].bv_val, buf, len + 1 );
+
+ /* FIXME: touch modifyTimestamp? */
+ }
+
+ return SLAP_CB_CONTINUE;
+}
+
+static int
+conn_create(
+ monitor_info_t *mi,
+ Connection *c,
+ Entry **ep,
+ monitor_subsys_t *ms )
+{
+ monitor_entry_t *mp;
+ struct tm tm;
+ char buf[ BACKMONITOR_BUFSIZE ];
+ char buf2[ LDAP_LUTIL_GENTIME_BUFSIZE ];
+ char buf3[ LDAP_LUTIL_GENTIME_BUFSIZE ];
+
+ struct berval bv, ctmbv, mtmbv;
+ struct berval bv_unknown= BER_BVC("unknown");
+
+ Entry *e;
+
+ assert( c != NULL );
+ assert( ep != NULL );
+
+ ldap_pvt_gmtime( &c->c_starttime, &tm );
+
+ ctmbv.bv_len = lutil_gentime( buf2, sizeof( buf2 ), &tm );
+ ctmbv.bv_val = buf2;
+
+ ldap_pvt_gmtime( &c->c_activitytime, &tm );
+ mtmbv.bv_len = lutil_gentime( buf3, sizeof( buf3 ), &tm );
+ mtmbv.bv_val = buf3;
+
+ bv.bv_len = snprintf( buf, sizeof( buf ),
+ "cn=Connection %ld", c->c_connid );
+ bv.bv_val = buf;
+ e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, &bv,
+ mi->mi_oc_monitorConnection, &ctmbv, &mtmbv );
+
+ if ( e == NULL) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_conn_create: "
+ "unable to create entry "
+ "\"cn=Connection %ld,%s\"\n",
+ c->c_connid,
+ ms->mss_dn.bv_val, 0 );
+ return( -1 );
+ }
+
+#ifdef MONITOR_LEGACY_CONN
+ /* NOTE: this will disappear, as the exploded data
+ * has been moved to dedicated attributes */
+ bv.bv_len = snprintf( buf, sizeof( buf ),
+ "%ld "
+ ": %ld "
+ ": %ld/%ld/%ld/%ld "
+ ": %ld/%ld/%ld "
+ ": %s%s%s%s%s%s "
+ ": %s "
+ ": %s "
+ ": %s "
+ ": %s "
+ ": %s "
+ ": %s "
+ ": %s",
+ c->c_connid,
+ (long) c->c_protocol,
+ c->c_n_ops_received, c->c_n_ops_executing,
+ c->c_n_ops_pending, c->c_n_ops_completed,
+
+ /* add low-level counters here */
+ c->c_n_get, c->c_n_read, c->c_n_write,
+
+ c->c_currentber ? "r" : "",
+ c->c_writewaiter ? "w" : "",
+ LDAP_STAILQ_EMPTY( &c->c_ops ) ? "" : "x",
+ LDAP_STAILQ_EMPTY( &c->c_pending_ops ) ? "" : "p",
+ connection_state2str( c->c_conn_state ),
+ c->c_sasl_bind_in_progress ? "S" : "",
+
+ c->c_dn.bv_len ? c->c_dn.bv_val : SLAPD_ANONYMOUS,
+
+ c->c_listener_url.bv_val,
+ BER_BVISNULL( &c->c_peer_domain )
+ ? "" : c->c_peer_domain.bv_val,
+ BER_BVISNULL( &c->c_peer_name )
+ ? "" : c->c_peer_name.bv_val,
+ c->c_sock_name.bv_val,
+
+ buf2,
+ buf3 );
+ attr_merge_normalize_one( e, mi->mi_ad_monitoredInfo, &bv, NULL );
+#endif /* MONITOR_LEGACY_CONN */
+
+ bv.bv_len = snprintf( buf, sizeof( buf ), "%lu", c->c_connid );
+ attr_merge_one( e, mi->mi_ad_monitorConnectionNumber, &bv, NULL );
+
+ bv.bv_len = snprintf( buf, sizeof( buf ), "%ld", (long) c->c_protocol );
+ attr_merge_normalize_one( e, mi->mi_ad_monitorConnectionProtocol, &bv, NULL );
+
+ bv.bv_len = snprintf( buf, sizeof( buf ), "%ld", c->c_n_ops_received );
+ attr_merge_one( e, mi->mi_ad_monitorConnectionOpsReceived, &bv, NULL );
+
+ bv.bv_len = snprintf( buf, sizeof( buf ), "%ld", c->c_n_ops_executing );
+ attr_merge_one( e, mi->mi_ad_monitorConnectionOpsExecuting, &bv, NULL );
+
+ bv.bv_len = snprintf( buf, sizeof( buf ), "%ld", c->c_n_ops_pending );
+ attr_merge_one( e, mi->mi_ad_monitorConnectionOpsPending, &bv, NULL );
+
+ bv.bv_len = snprintf( buf, sizeof( buf ), "%ld", c->c_n_ops_completed );
+ attr_merge_one( e, mi->mi_ad_monitorConnectionOpsCompleted, &bv, NULL );
+
+ bv.bv_len = snprintf( buf, sizeof( buf ), "%ld", c->c_n_get );
+ attr_merge_one( e, mi->mi_ad_monitorConnectionGet, &bv, NULL );
+
+ bv.bv_len = snprintf( buf, sizeof( buf ), "%ld", c->c_n_read );
+ attr_merge_one( e, mi->mi_ad_monitorConnectionRead, &bv, NULL );
+
+ bv.bv_len = snprintf( buf, sizeof( buf ), "%ld", c->c_n_write );
+ attr_merge_one( e, mi->mi_ad_monitorConnectionWrite, &bv, NULL );
+
+ bv.bv_len = snprintf( buf, sizeof( buf ), "%s%s%s%s%s%s",
+ c->c_currentber ? "r" : "",
+ c->c_writewaiter ? "w" : "",
+ LDAP_STAILQ_EMPTY( &c->c_ops ) ? "" : "x",
+ LDAP_STAILQ_EMPTY( &c->c_pending_ops ) ? "" : "p",
+ connection_state2str( c->c_conn_state ),
+ c->c_sasl_bind_in_progress ? "S" : "" );
+ attr_merge_normalize_one( e, mi->mi_ad_monitorConnectionMask, &bv, NULL );
+
+ attr_merge_one( e, mi->mi_ad_monitorConnectionAuthzDN,
+ &c->c_dn, &c->c_ndn );
+
+ /* NOTE: client connections leave the c_peer_* fields NULL */
+ assert( !BER_BVISNULL( &c->c_listener_url ) );
+ attr_merge_normalize_one( e, mi->mi_ad_monitorConnectionListener,
+ &c->c_listener_url, NULL );
+
+ attr_merge_normalize_one( e, mi->mi_ad_monitorConnectionPeerDomain,
+ BER_BVISNULL( &c->c_peer_domain ) ? &bv_unknown : &c->c_peer_domain,
+ NULL );
+
+ attr_merge_normalize_one( e, mi->mi_ad_monitorConnectionPeerAddress,
+ BER_BVISNULL( &c->c_peer_name ) ? &bv_unknown : &c->c_peer_name,
+ NULL );
+
+ assert( !BER_BVISNULL( &c->c_sock_name ) );
+ attr_merge_normalize_one( e, mi->mi_ad_monitorConnectionLocalAddress,
+ &c->c_sock_name, NULL );
+
+ attr_merge_normalize_one( e, mi->mi_ad_monitorConnectionStartTime, &ctmbv, NULL );
+
+ attr_merge_normalize_one( e, mi->mi_ad_monitorConnectionActivityTime, &mtmbv, NULL );
+
+ mp = monitor_entrypriv_create();
+ if ( mp == NULL ) {
+ return LDAP_OTHER;
+ }
+ e->e_private = ( void * )mp;
+ mp->mp_info = ms;
+ mp->mp_flags = MONITOR_F_SUB | MONITOR_F_VOLATILE;
+
+ *ep = e;
+
+ return SLAP_CB_CONTINUE;
+}
+
+static int
+monitor_subsys_conn_create(
+ Operation *op,
+ SlapReply *rs,
+ struct berval *ndn,
+ Entry *e_parent,
+ Entry **ep )
+{
+ monitor_info_t *mi = ( monitor_info_t * )op->o_bd->be_private;
+
+ int rc = SLAP_CB_CONTINUE;
+ monitor_subsys_t *ms;
+
+ assert( mi != NULL );
+ assert( e_parent != NULL );
+ assert( ep != NULL );
+
+ ms = (( monitor_entry_t *)e_parent->e_private)->mp_info;
+
+ *ep = NULL;
+
+ if ( ndn == NULL ) {
+ Connection *c;
+ ber_socket_t connindex;
+ Entry *e = NULL,
+ *e_tmp = NULL;
+
+ /* create all the children of e_parent */
+ for ( c = connection_first( &connindex );
+ c != NULL;
+ c = connection_next( c, &connindex ) )
+ {
+ monitor_entry_t *mp;
+
+ if ( conn_create( mi, c, &e, ms ) != SLAP_CB_CONTINUE
+ || e == NULL )
+ {
+ for ( ; e_tmp != NULL; ) {
+ mp = ( monitor_entry_t * )e_tmp->e_private;
+ e = mp->mp_next;
+
+ ch_free( mp );
+ e_tmp->e_private = NULL;
+ entry_free( e_tmp );
+
+ e_tmp = e;
+ }
+ rc = rs->sr_err = LDAP_OTHER;
+ break;
+ }
+ mp = ( monitor_entry_t * )e->e_private;
+ mp->mp_next = e_tmp;
+ e_tmp = e;
+ }
+ connection_done( c );
+ *ep = e;
+
+ } else {
+ Connection *c;
+ ber_socket_t connindex;
+ unsigned long connid;
+ char *next = NULL;
+ static struct berval nconn_bv = BER_BVC( "cn=connection " );
+
+ rc = LDAP_NO_SUCH_OBJECT;
+
+ /* create exactly the required entry;
+ * the normalized DN must start with "cn=connection ",
+ * followed by the connection id, followed by
+ * the RDN separator "," */
+ if ( ndn->bv_len <= nconn_bv.bv_len
+ || strncmp( ndn->bv_val, nconn_bv.bv_val, nconn_bv.bv_len ) != 0 )
+ {
+ return -1;
+ }
+
+ connid = strtol( &ndn->bv_val[ nconn_bv.bv_len ], &next, 10 );
+ if ( next[ 0 ] != ',' ) {
+ return ( rs->sr_err = LDAP_OTHER );
+ }
+
+ for ( c = connection_first( &connindex );
+ c != NULL;
+ c = connection_next( c, &connindex ) )
+ {
+ if ( c->c_connid == connid ) {
+ rc = conn_create( mi, c, ep, ms );
+ if ( rc != SLAP_CB_CONTINUE ) {
+ rs->sr_err = rc;
+
+ } else if ( *ep == NULL ) {
+ rc = rs->sr_err = LDAP_OTHER;
+ }
+
+ break;
+ }
+ }
+
+ connection_done( c );
+ }
+
+ return rc;
+}
+
diff --git a/servers/slapd/back-monitor/database.c b/servers/slapd/back-monitor/database.c
new file mode 100644
index 0000000..fc6ad1b
--- /dev/null
+++ b/servers/slapd/back-monitor/database.c
@@ -0,0 +1,1048 @@
+/* database.c - deals with database subsystem */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2001-2018 The OpenLDAP Foundation.
+ * Portions Copyright 2001-2003 Pierangelo Masarati.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Pierangelo Masarati for inclusion
+ * in OpenLDAP Software.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+#include <ac/unistd.h>
+
+#include "slap.h"
+#include "back-monitor.h"
+
+#if defined(LDAP_SLAPI)
+#include "slapi.h"
+static int monitor_back_add_plugin( monitor_info_t *mi, Backend *be, Entry *e );
+#endif /* defined(LDAP_SLAPI) */
+
+static int
+monitor_subsys_database_modify(
+ Operation *op,
+ SlapReply *rs,
+ Entry *e );
+
+static struct restricted_ops_t {
+ struct berval op;
+ unsigned int tag;
+} restricted_ops[] = {
+ { BER_BVC( "add" ), SLAP_RESTRICT_OP_ADD },
+ { BER_BVC( "bind" ), SLAP_RESTRICT_OP_BIND },
+ { BER_BVC( "compare" ), SLAP_RESTRICT_OP_COMPARE },
+ { BER_BVC( "delete" ), SLAP_RESTRICT_OP_DELETE },
+ { BER_BVC( "extended" ), SLAP_RESTRICT_OP_EXTENDED },
+ { BER_BVC( "modify" ), SLAP_RESTRICT_OP_MODIFY },
+ { BER_BVC( "rename" ), SLAP_RESTRICT_OP_RENAME },
+ { BER_BVC( "search" ), SLAP_RESTRICT_OP_SEARCH },
+ { BER_BVNULL, 0 }
+}, restricted_exops[] = {
+ { BER_BVC( LDAP_EXOP_START_TLS ), SLAP_RESTRICT_EXOP_START_TLS },
+ { BER_BVC( LDAP_EXOP_MODIFY_PASSWD ), SLAP_RESTRICT_EXOP_MODIFY_PASSWD },
+ { BER_BVC( LDAP_EXOP_WHO_AM_I ), SLAP_RESTRICT_EXOP_WHOAMI },
+ { BER_BVC( LDAP_EXOP_CANCEL ), SLAP_RESTRICT_EXOP_CANCEL },
+ { BER_BVNULL, 0 }
+};
+
+static int
+init_readOnly( monitor_info_t *mi, Entry *e, slap_mask_t restrictops )
+{
+ struct berval *tf = ( ( restrictops & SLAP_RESTRICT_OP_MASK ) == SLAP_RESTRICT_OP_WRITES ) ?
+ (struct berval *)&slap_true_bv : (struct berval *)&slap_false_bv;
+
+ return attr_merge_one( e, mi->mi_ad_readOnly, tf, NULL );
+}
+
+static int
+init_restrictedOperation( monitor_info_t *mi, Entry *e, slap_mask_t restrictops )
+{
+ int i, rc;
+
+ for ( i = 0; restricted_ops[ i ].op.bv_val; i++ ) {
+ if ( restrictops & restricted_ops[ i ].tag ) {
+ rc = attr_merge_one( e, mi->mi_ad_restrictedOperation,
+ &restricted_ops[ i ].op,
+ &restricted_ops[ i ].op );
+ if ( rc ) {
+ return rc;
+ }
+ }
+ }
+
+ for ( i = 0; restricted_exops[ i ].op.bv_val; i++ ) {
+ if ( restrictops & restricted_exops[ i ].tag ) {
+ rc = attr_merge_one( e, mi->mi_ad_restrictedOperation,
+ &restricted_exops[ i ].op,
+ &restricted_exops[ i ].op );
+ if ( rc ) {
+ return rc;
+ }
+ }
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int
+monitor_subsys_overlay_init_one(
+ monitor_info_t *mi,
+ BackendDB *be,
+ monitor_subsys_t *ms,
+ monitor_subsys_t *ms_overlay,
+ slap_overinst *on,
+ Entry *e_database,
+ Entry **ep_overlay )
+{
+ char buf[ BACKMONITOR_BUFSIZE ];
+ int j, o;
+ Entry *e_overlay;
+ slap_overinst *on2;
+ slap_overinfo *oi = NULL;
+ BackendInfo *bi;
+ monitor_entry_t *mp_overlay;
+ struct berval bv;
+
+ assert( overlay_is_over( be ) );
+
+ oi = (slap_overinfo *)be->bd_info->bi_private;
+ bi = oi->oi_orig;
+
+ /* find the overlay number, o */
+ for ( o = 0, on2 = oi->oi_list; on2 && on2 != on; on2 = on2->on_next, o++ )
+ ;
+
+ if ( on2 == NULL ) {
+ return -1;
+ }
+
+ /* find the overlay type number, j */
+ for ( on2 = overlay_next( NULL ), j = 0; on2; on2 = overlay_next( on2 ), j++ ) {
+ if ( on2->on_bi.bi_type == on->on_bi.bi_type ) {
+ break;
+ }
+ }
+ assert( on2 != NULL );
+
+ bv.bv_len = snprintf( buf, sizeof( buf ), "cn=Overlay %d", o );
+ bv.bv_val = buf;
+
+ e_overlay = monitor_entry_stub( &e_database->e_name, &e_database->e_nname, &bv,
+ mi->mi_oc_monitoredObject, NULL, NULL );
+
+ if ( e_overlay == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_overlay_init_one: "
+ "unable to create entry "
+ "\"cn=Overlay %d,%s\"\n",
+ o, e_database->e_name.bv_val, 0 );
+ return( -1 );
+ }
+ ber_str2bv( on->on_bi.bi_type, 0, 0, &bv );
+ attr_merge_normalize_one( e_overlay, mi->mi_ad_monitoredInfo, &bv, NULL );
+
+ bv.bv_len = snprintf( buf, sizeof( buf ), "cn=Overlay %d,%s",
+ j, ms_overlay->mss_dn.bv_val );
+ bv.bv_val = buf;
+ attr_merge_normalize_one( e_overlay, slap_schema.si_ad_seeAlso,
+ &bv, NULL );
+
+ if ( SLAP_MONITOR( be ) ) {
+ attr_merge( e_overlay, slap_schema.si_ad_monitorContext,
+ be->be_suffix, be->be_nsuffix );
+
+ } else {
+ attr_merge( e_overlay, slap_schema.si_ad_namingContexts,
+ be->be_suffix, NULL );
+ }
+
+ mp_overlay = monitor_entrypriv_create();
+ if ( mp_overlay == NULL ) {
+ return -1;
+ }
+ e_overlay->e_private = ( void * )mp_overlay;
+ mp_overlay->mp_info = ms;
+ mp_overlay->mp_flags = ms->mss_flags | MONITOR_F_SUB;
+
+ if ( monitor_cache_add( mi, e_overlay ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_overlay_init_one: "
+ "unable to add entry "
+ "\"cn=Overlay %d,%s\"\n",
+ o, e_database->e_name.bv_val, 0 );
+ return -1;
+ }
+
+ *ep_overlay = e_overlay;
+ ep_overlay = &mp_overlay->mp_next;
+
+ return 0;
+}
+
+static int
+monitor_subsys_database_init_one(
+ monitor_info_t *mi,
+ BackendDB *be,
+ monitor_subsys_t *ms,
+ monitor_subsys_t *ms_backend,
+ monitor_subsys_t *ms_overlay,
+ struct berval *rdn,
+ Entry *e_database,
+ Entry ***epp )
+{
+ char buf[ BACKMONITOR_BUFSIZE ];
+ int j;
+ slap_overinfo *oi = NULL;
+ BackendInfo *bi, *bi2;
+ Entry *e;
+ monitor_entry_t *mp;
+ char *rdnval = strchr( rdn->bv_val, '=' ) + 1;
+ struct berval bv;
+
+ bi = be->bd_info;
+
+ if ( overlay_is_over( be ) ) {
+ oi = (slap_overinfo *)be->bd_info->bi_private;
+ bi = oi->oi_orig;
+ }
+
+ e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, rdn,
+ mi->mi_oc_monitoredObject, NULL, NULL );
+
+ if ( e == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_database_init_one: "
+ "unable to create entry \"%s,%s\"\n",
+ rdn->bv_val, ms->mss_dn.bv_val, 0 );
+ return( -1 );
+ }
+
+ ber_str2bv( bi->bi_type, 0, 0, &bv );
+ attr_merge_normalize_one( e, mi->mi_ad_monitoredInfo, &bv, NULL );
+ attr_merge_one( e, mi->mi_ad_monitorIsShadow,
+ SLAP_SHADOW( be ) ? (struct berval *)&slap_true_bv :
+ (struct berval *)&slap_false_bv, NULL );
+
+ if ( SLAP_MONITOR( be ) ) {
+ attr_merge( e, slap_schema.si_ad_monitorContext,
+ be->be_suffix, be->be_nsuffix );
+ attr_merge( e_database, slap_schema.si_ad_monitorContext,
+ be->be_suffix, be->be_nsuffix );
+
+ } else {
+ if ( be->be_suffix == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_database_init_one: "
+ "missing suffix for %s\n",
+ rdnval, 0, 0 );
+ } else {
+ attr_merge( e, slap_schema.si_ad_namingContexts,
+ be->be_suffix, NULL );
+ attr_merge( e_database, slap_schema.si_ad_namingContexts,
+ be->be_suffix, NULL );
+ }
+
+ if ( SLAP_GLUE_SUBORDINATE( be ) ) {
+ BackendDB *sup_be = select_backend( &be->be_nsuffix[ 0 ], 1 );
+ if ( sup_be == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_database_init: "
+ "unable to get superior for %s\n",
+ be->be_suffix[ 0 ].bv_val, 0, 0 );
+
+ } else {
+ attr_merge( e, mi->mi_ad_monitorSuperiorDN,
+ sup_be->be_suffix, sup_be->be_nsuffix );
+ }
+ }
+ }
+
+ (void)init_readOnly( mi, e, be->be_restrictops );
+ (void)init_restrictedOperation( mi, e, be->be_restrictops );
+
+ if ( SLAP_SHADOW( be ) && be->be_update_refs ) {
+ attr_merge_normalize( e, mi->mi_ad_monitorUpdateRef,
+ be->be_update_refs, NULL );
+ }
+
+ if ( oi != NULL ) {
+ slap_overinst *on = oi->oi_list,
+ *on1 = on;
+
+ for ( ; on; on = on->on_next ) {
+ slap_overinst *on2;
+
+ for ( on2 = on1; on2 != on; on2 = on2->on_next ) {
+ if ( on2->on_bi.bi_type == on->on_bi.bi_type ) {
+ break;
+ }
+ }
+
+ if ( on2 != on ) {
+ break;
+ }
+
+ ber_str2bv( on->on_bi.bi_type, 0, 0, &bv );
+ attr_merge_normalize_one( e, mi->mi_ad_monitorOverlay,
+ &bv, NULL );
+
+ /* find the overlay number, j */
+ for ( on2 = overlay_next( NULL ), j = 0; on2; on2 = overlay_next( on2 ), j++ ) {
+ if ( on2->on_bi.bi_type == on->on_bi.bi_type ) {
+ break;
+ }
+ }
+ assert( on2 != NULL );
+
+ snprintf( buf, sizeof( buf ),
+ "cn=Overlay %d,%s",
+ j, ms_overlay->mss_dn.bv_val );
+ ber_str2bv( buf, 0, 0, &bv );
+ attr_merge_normalize_one( e,
+ slap_schema.si_ad_seeAlso,
+ &bv, NULL );
+ }
+ }
+
+ j = -1;
+ LDAP_STAILQ_FOREACH( bi2, &backendInfo, bi_next ) {
+ j++;
+ if ( bi2->bi_type == bi->bi_type ) {
+ snprintf( buf, sizeof( buf ),
+ "cn=Backend %d,%s",
+ j, ms_backend->mss_dn.bv_val );
+ bv.bv_val = buf;
+ bv.bv_len = strlen( buf );
+ attr_merge_normalize_one( e,
+ slap_schema.si_ad_seeAlso,
+ &bv, NULL );
+ break;
+ }
+ }
+ /* we must find it! */
+ assert( j >= 0 );
+
+ mp = monitor_entrypriv_create();
+ if ( mp == NULL ) {
+ return -1;
+ }
+ e->e_private = ( void * )mp;
+ mp->mp_info = ms;
+ mp->mp_flags = ms->mss_flags
+ | MONITOR_F_SUB;
+
+ if ( monitor_cache_add( mi, e ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_database_init_one: "
+ "unable to add entry \"%s,%s\"\n",
+ rdn->bv_val, ms->mss_dn.bv_val, 0 );
+ return( -1 );
+ }
+
+#if defined(LDAP_SLAPI)
+ monitor_back_add_plugin( mi, be, e );
+#endif /* defined(LDAP_SLAPI) */
+
+ if ( oi != NULL ) {
+ Entry **ep_overlay = &mp->mp_children;
+ slap_overinst *on = oi->oi_list;
+
+ for ( ; on; on = on->on_next ) {
+ monitor_subsys_overlay_init_one( mi, be,
+ ms, ms_overlay, on, e, ep_overlay );
+ }
+ }
+
+ **epp = e;
+ *epp = &mp->mp_next;
+
+ return 0;
+}
+
+static int
+monitor_back_register_database_and_overlay(
+ BackendDB *be,
+ struct slap_overinst *on,
+ struct berval *ndn_out )
+{
+ monitor_info_t *mi;
+ Entry *e_database, **ep;
+ int i, rc;
+ monitor_entry_t *mp;
+ monitor_subsys_t *ms_backend,
+ *ms_database,
+ *ms_overlay;
+ struct berval bv;
+ char buf[ BACKMONITOR_BUFSIZE ];
+
+ assert( be_monitor != NULL );
+
+ if ( !monitor_subsys_is_opened() ) {
+ if ( on ) {
+ return monitor_back_register_overlay_limbo( be, on, ndn_out );
+
+ } else {
+ return monitor_back_register_database_limbo( be, ndn_out );
+ }
+ }
+
+ mi = ( monitor_info_t * )be_monitor->be_private;
+
+ ms_backend = monitor_back_get_subsys( SLAPD_MONITOR_BACKEND_NAME );
+ if ( ms_backend == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_register_database: "
+ "unable to get "
+ "\"" SLAPD_MONITOR_BACKEND_NAME "\" "
+ "subsystem\n",
+ 0, 0, 0 );
+ return -1;
+ }
+
+ ms_database = monitor_back_get_subsys( SLAPD_MONITOR_DATABASE_NAME );
+ if ( ms_database == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_register_database: "
+ "unable to get "
+ "\"" SLAPD_MONITOR_DATABASE_NAME "\" "
+ "subsystem\n",
+ 0, 0, 0 );
+ return -1;
+ }
+
+ ms_overlay = monitor_back_get_subsys( SLAPD_MONITOR_OVERLAY_NAME );
+ if ( ms_overlay == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_register_database: "
+ "unable to get "
+ "\"" SLAPD_MONITOR_OVERLAY_NAME "\" "
+ "subsystem\n",
+ 0, 0, 0 );
+ return -1;
+ }
+
+ if ( monitor_cache_get( mi, &ms_database->mss_ndn, &e_database ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_database_init: "
+ "unable to get entry \"%s\"\n",
+ ms_database->mss_ndn.bv_val, 0, 0 );
+ return( -1 );
+ }
+
+ mp = ( monitor_entry_t * )e_database->e_private;
+ for ( i = -1, ep = &mp->mp_children; *ep; i++ ) {
+ Attribute *a;
+
+ a = attr_find( (*ep)->e_attrs, slap_schema.si_ad_namingContexts );
+ if ( a ) {
+ int j, k;
+
+ /* FIXME: RFC 4512 defines namingContexts without an
+ * equality matching rule, making comparisons
+ * like this one tricky. We use a_vals and
+ * be_suffix instead for now.
+ */
+ for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); j++ ) {
+ for ( k = 0; !BER_BVISNULL( &be->be_suffix[ k ] ); k++ ) {
+ if ( dn_match( &a->a_vals[ j ],
+ &be->be_suffix[ k ] ) ) {
+ rc = 0;
+ goto done;
+ }
+ }
+ }
+ }
+
+ mp = ( monitor_entry_t * )(*ep)->e_private;
+
+ assert( mp != NULL );
+ ep = &mp->mp_next;
+ }
+
+ bv.bv_val = buf;
+ bv.bv_len = snprintf( buf, sizeof( buf ), "cn=Database %d", i );
+ if ( bv.bv_len >= sizeof( buf ) ) {
+ rc = -1;
+ goto done;
+ }
+
+ rc = monitor_subsys_database_init_one( mi, be,
+ ms_database, ms_backend, ms_overlay, &bv, e_database, &ep );
+ if ( rc != 0 ) {
+ goto done;
+ }
+ /* database_init_one advanced ep past where we want.
+ * But it stored the entry we want in mp->mp_next.
+ */
+ ep = &mp->mp_next;
+
+done:;
+ monitor_cache_release( mi, e_database );
+ if ( rc == 0 && ndn_out && ep && *ep ) {
+ if ( on ) {
+ Entry *e_ov;
+ struct berval ov_type;
+
+ ber_str2bv( on->on_bi.bi_type, 0, 0, &ov_type );
+
+ mp = ( monitor_entry_t * ) (*ep)->e_private;
+ for ( e_ov = mp->mp_children; e_ov; ) {
+ Attribute *a = attr_find( e_ov->e_attrs, mi->mi_ad_monitoredInfo );
+
+ if ( a != NULL && bvmatch( &a->a_nvals[ 0 ], &ov_type ) ) {
+ *ndn_out = e_ov->e_nname;
+ break;
+ }
+
+ mp = ( monitor_entry_t * ) e_ov->e_private;
+ e_ov = mp->mp_next;
+ }
+
+ } else {
+ *ndn_out = (*ep)->e_nname;
+ }
+ }
+
+ return rc;
+}
+
+int
+monitor_back_register_database(
+ BackendDB *be,
+ struct berval *ndn_out )
+{
+ return monitor_back_register_database_and_overlay( be, NULL, ndn_out );
+}
+
+int
+monitor_back_register_overlay(
+ BackendDB *be,
+ struct slap_overinst *on,
+ struct berval *ndn_out )
+{
+ return monitor_back_register_database_and_overlay( be, on, ndn_out );
+}
+
+int
+monitor_subsys_database_init(
+ BackendDB *be,
+ monitor_subsys_t *ms )
+{
+ monitor_info_t *mi;
+ Entry *e_database, **ep;
+ int i, rc;
+ monitor_entry_t *mp;
+ monitor_subsys_t *ms_backend,
+ *ms_overlay;
+ struct berval bv;
+
+ assert( be != NULL );
+
+ ms->mss_modify = monitor_subsys_database_modify;
+
+ mi = ( monitor_info_t * )be->be_private;
+
+ ms_backend = monitor_back_get_subsys( SLAPD_MONITOR_BACKEND_NAME );
+ if ( ms_backend == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_database_init: "
+ "unable to get "
+ "\"" SLAPD_MONITOR_BACKEND_NAME "\" "
+ "subsystem\n",
+ 0, 0, 0 );
+ return -1;
+ }
+
+ ms_overlay = monitor_back_get_subsys( SLAPD_MONITOR_OVERLAY_NAME );
+ if ( ms_overlay == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_database_init: "
+ "unable to get "
+ "\"" SLAPD_MONITOR_OVERLAY_NAME "\" "
+ "subsystem\n",
+ 0, 0, 0 );
+ return -1;
+ }
+
+ if ( monitor_cache_get( mi, &ms->mss_ndn, &e_database ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_database_init: "
+ "unable to get entry \"%s\"\n",
+ ms->mss_ndn.bv_val, 0, 0 );
+ return( -1 );
+ }
+
+ (void)init_readOnly( mi, e_database, frontendDB->be_restrictops );
+ (void)init_restrictedOperation( mi, e_database, frontendDB->be_restrictops );
+
+ mp = ( monitor_entry_t * )e_database->e_private;
+ mp->mp_children = NULL;
+ ep = &mp->mp_children;
+
+ BER_BVSTR( &bv, "cn=Frontend" );
+ rc = monitor_subsys_database_init_one( mi, frontendDB,
+ ms, ms_backend, ms_overlay, &bv, e_database, &ep );
+ if ( rc != 0 ) {
+ return rc;
+ }
+
+ i = -1;
+ LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) {
+ char buf[ BACKMONITOR_BUFSIZE ];
+
+ bv.bv_val = buf;
+ bv.bv_len = snprintf( buf, sizeof( buf ), "cn=Database %d", ++i );
+ if ( bv.bv_len >= sizeof( buf ) ) {
+ return -1;
+ }
+
+ rc = monitor_subsys_database_init_one( mi, be,
+ ms, ms_backend, ms_overlay, &bv, e_database, &ep );
+ if ( rc != 0 ) {
+ return rc;
+ }
+ }
+
+ monitor_cache_release( mi, e_database );
+
+ return( 0 );
+}
+
+/*
+ * v: array of values
+ * cur: must not contain the tags corresponding to the values in v
+ * delta: will contain the tags corresponding to the values in v
+ */
+static int
+value_mask( BerVarray v, slap_mask_t cur, slap_mask_t *delta )
+{
+ for ( ; !BER_BVISNULL( v ); v++ ) {
+ struct restricted_ops_t *rops;
+ int i;
+
+ if ( OID_LEADCHAR( v->bv_val[ 0 ] ) ) {
+ rops = restricted_exops;
+
+ } else {
+ rops = restricted_ops;
+ }
+
+ for ( i = 0; !BER_BVISNULL( &rops[ i ].op ); i++ ) {
+ if ( ber_bvstrcasecmp( v, &rops[ i ].op ) != 0 ) {
+ continue;
+ }
+
+ if ( rops[ i ].tag & *delta ) {
+ return LDAP_OTHER;
+ }
+
+ if ( rops[ i ].tag & cur ) {
+ return LDAP_OTHER;
+ }
+
+ cur |= rops[ i ].tag;
+ *delta |= rops[ i ].tag;
+
+ break;
+ }
+
+ if ( BER_BVISNULL( &rops[ i ].op ) ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int
+monitor_subsys_database_modify(
+ Operation *op,
+ SlapReply *rs,
+ Entry *e )
+{
+ monitor_info_t *mi = (monitor_info_t *)op->o_bd->be_private;
+ int rc = LDAP_OTHER;
+ Attribute *save_attrs, *a;
+ Modifications *ml;
+ Backend *be;
+ int ro_gotval = 1, i, n;
+ slap_mask_t rp_add = 0, rp_delete = 0, rp_cur;
+ struct berval *tf;
+
+ i = sscanf( e->e_nname.bv_val, "cn=database %d,", &n );
+ if ( i != 1 ) {
+ return SLAP_CB_CONTINUE;
+ }
+
+ if ( n < 0 || n >= nBackendDB ) {
+ rs->sr_text = "invalid database index";
+ return ( rs->sr_err = LDAP_NO_SUCH_OBJECT );
+ }
+
+ LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) {
+ if ( n == 0 ) {
+ break;
+ }
+ n--;
+ }
+ /* do not allow some changes on back-monitor (needs work)... */
+ if ( SLAP_MONITOR( be ) ) {
+ rs->sr_text = "no modifications allowed to monitor database entry";
+ return ( rs->sr_err = LDAP_UNWILLING_TO_PERFORM );
+ }
+
+ rp_cur = be->be_restrictops;
+
+ save_attrs = e->e_attrs;
+ e->e_attrs = attrs_dup( e->e_attrs );
+
+ for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
+ Modification *mod = &ml->sml_mod;
+
+ if ( mod->sm_desc == mi->mi_ad_readOnly ) {
+ int val = -1;
+
+ if ( mod->sm_values ) {
+ if ( !BER_BVISNULL( &mod->sm_values[ 1 ] ) ) {
+ rs->sr_text = "attempting to modify multiple values of single-valued attribute";
+ rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
+ goto done;
+ }
+
+ if ( bvmatch( &slap_true_bv, mod->sm_values )) {
+ val = 1;
+
+ } else if ( bvmatch( &slap_false_bv, mod->sm_values )) {
+ val = 0;
+
+ } else {
+ assert( 0 );
+ rc = rs->sr_err = LDAP_INVALID_SYNTAX;
+ goto done;
+ }
+ }
+
+ switch ( mod->sm_op ) {
+ case LDAP_MOD_DELETE:
+ if ( ro_gotval < 1 ) {
+ rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
+ goto done;
+ }
+ ro_gotval--;
+
+ if ( val == 0 && ( rp_cur & SLAP_RESTRICT_OP_WRITES ) == SLAP_RESTRICT_OP_WRITES ) {
+ rc = rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE;
+ goto done;
+ }
+
+ if ( val == 1 && ( rp_cur & SLAP_RESTRICT_OP_WRITES ) != SLAP_RESTRICT_OP_WRITES ) {
+ rc = rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE;
+ goto done;
+ }
+
+ break;
+
+ case LDAP_MOD_REPLACE:
+ ro_gotval = 0;
+ /* fall thru */
+
+ case LDAP_MOD_ADD:
+ if ( ro_gotval > 0 ) {
+ rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
+ goto done;
+ }
+ ro_gotval++;
+
+ if ( val == 1 ) {
+ rp_add |= (~rp_cur) & SLAP_RESTRICT_OP_WRITES;
+ rp_cur |= SLAP_RESTRICT_OP_WRITES;
+ rp_delete &= ~SLAP_RESTRICT_OP_WRITES;
+
+ } else if ( val == 0 ) {
+ rp_delete |= rp_cur & SLAP_RESTRICT_OP_WRITES;
+ rp_cur &= ~SLAP_RESTRICT_OP_WRITES;
+ rp_add &= ~SLAP_RESTRICT_OP_WRITES;
+ }
+ break;
+
+ default:
+ rc = rs->sr_err = LDAP_OTHER;
+ goto done;
+ }
+
+ } else if ( mod->sm_desc == mi->mi_ad_restrictedOperation ) {
+ slap_mask_t mask = 0;
+
+ switch ( mod->sm_op ) {
+ case LDAP_MOD_DELETE:
+ if ( mod->sm_values == NULL ) {
+ rp_delete = rp_cur;
+ rp_cur = 0;
+ rp_add = 0;
+ break;
+ }
+ rc = value_mask( mod->sm_values, ~rp_cur, &mask );
+ if ( rc == LDAP_SUCCESS ) {
+ rp_delete |= mask;
+ rp_add &= ~mask;
+ rp_cur &= ~mask;
+
+ } else if ( rc == LDAP_OTHER ) {
+ rc = LDAP_NO_SUCH_ATTRIBUTE;
+ }
+ break;
+
+ case LDAP_MOD_REPLACE:
+ rp_delete = rp_cur;
+ rp_cur = 0;
+ rp_add = 0;
+ /* fall thru */
+
+ case LDAP_MOD_ADD:
+ rc = value_mask( mod->sm_values, rp_cur, &mask );
+ if ( rc == LDAP_SUCCESS ) {
+ rp_add |= mask;
+ rp_cur |= mask;
+ rp_delete &= ~mask;
+
+ } else if ( rc == LDAP_OTHER ) {
+ rc = rs->sr_err = LDAP_TYPE_OR_VALUE_EXISTS;
+ }
+ break;
+
+ default:
+ rc = rs->sr_err = LDAP_OTHER;
+ break;
+ }
+
+ if ( rc != LDAP_SUCCESS ) {
+ goto done;
+ }
+
+ } else if ( is_at_operational( mod->sm_desc->ad_type )) {
+ /* accept all operational attributes */
+ attr_delete( &e->e_attrs, mod->sm_desc );
+ rc = attr_merge( e, mod->sm_desc, mod->sm_values,
+ mod->sm_nvalues );
+ if ( rc ) {
+ rc = rs->sr_err = LDAP_OTHER;
+ break;
+ }
+
+ } else {
+ rc = rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
+ break;
+ }
+ }
+
+ /* sanity checks: */
+ if ( ro_gotval < 1 ) {
+ rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
+ goto done;
+ }
+
+ if ( ( rp_cur & SLAP_RESTRICT_OP_EXTENDED ) && ( rp_cur & SLAP_RESTRICT_EXOP_MASK ) ) {
+ rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
+ goto done;
+ }
+
+ if ( rp_delete & rp_add ) {
+ rc = rs->sr_err = LDAP_OTHER;
+ goto done;
+ }
+
+ /* check current value of readOnly */
+ if ( ( rp_cur & SLAP_RESTRICT_OP_WRITES ) == SLAP_RESTRICT_OP_WRITES ) {
+ tf = (struct berval *)&slap_true_bv;
+
+ } else {
+ tf = (struct berval *)&slap_false_bv;
+ }
+
+ a = attr_find( e->e_attrs, mi->mi_ad_readOnly );
+ if ( a == NULL ) {
+ rc = LDAP_OTHER;
+ goto done;
+ }
+
+ if ( !bvmatch( &a->a_vals[ 0 ], tf ) ) {
+ attr_delete( &e->e_attrs, mi->mi_ad_readOnly );
+ rc = attr_merge_one( e, mi->mi_ad_readOnly, tf, tf );
+ }
+
+ if ( rc == LDAP_SUCCESS ) {
+ if ( rp_delete ) {
+ if ( rp_delete == be->be_restrictops ) {
+ attr_delete( &e->e_attrs, mi->mi_ad_restrictedOperation );
+
+ } else {
+ a = attr_find( e->e_attrs, mi->mi_ad_restrictedOperation );
+ if ( a == NULL ) {
+ rc = rs->sr_err = LDAP_OTHER;
+ goto done;
+ }
+
+ for ( i = 0; !BER_BVISNULL( &restricted_ops[ i ].op ); i++ ) {
+ if ( rp_delete & restricted_ops[ i ].tag ) {
+ int j;
+
+ for ( j = 0; !BER_BVISNULL( &a->a_nvals[ j ] ); j++ ) {
+ int k;
+
+ if ( !bvmatch( &a->a_nvals[ j ], &restricted_ops[ i ].op ) ) {
+ continue;
+ }
+
+ ch_free( a->a_vals[ j ].bv_val );
+ ch_free( a->a_nvals[ j ].bv_val );
+
+ for ( k = j + 1; !BER_BVISNULL( &a->a_nvals[ k ] ); k++ ) {
+ a->a_vals[ k - 1 ] = a->a_vals[ k ];
+ a->a_nvals[ k - 1 ] = a->a_nvals[ k ];
+ }
+
+ BER_BVZERO( &a->a_vals[ k - 1 ] );
+ BER_BVZERO( &a->a_nvals[ k - 1 ] );
+ a->a_numvals--;
+ }
+ }
+ }
+
+ for ( i = 0; !BER_BVISNULL( &restricted_exops[ i ].op ); i++ ) {
+ if ( rp_delete & restricted_exops[ i ].tag ) {
+ int j;
+
+ for ( j = 0; !BER_BVISNULL( &a->a_nvals[ j ] ); j++ ) {
+ int k;
+
+ if ( !bvmatch( &a->a_nvals[ j ], &restricted_exops[ i ].op ) ) {
+ continue;
+ }
+
+ ch_free( a->a_vals[ j ].bv_val );
+ ch_free( a->a_nvals[ j ].bv_val );
+
+ for ( k = j + 1; !BER_BVISNULL( &a->a_nvals[ k ] ); k++ ) {
+ a->a_vals[ k - 1 ] = a->a_vals[ k ];
+ a->a_nvals[ k - 1 ] = a->a_nvals[ k ];
+ }
+
+ BER_BVZERO( &a->a_vals[ k - 1 ] );
+ BER_BVZERO( &a->a_nvals[ k - 1 ] );
+ a->a_numvals--;
+ }
+ }
+ }
+
+ if ( a->a_vals == NULL ) {
+ assert( a->a_numvals == 0 );
+
+ attr_delete( &e->e_attrs, mi->mi_ad_restrictedOperation );
+ }
+ }
+ }
+
+ if ( rp_add ) {
+ for ( i = 0; !BER_BVISNULL( &restricted_ops[ i ].op ); i++ ) {
+ if ( rp_add & restricted_ops[ i ].tag ) {
+ attr_merge_one( e, mi->mi_ad_restrictedOperation,
+ &restricted_ops[ i ].op,
+ &restricted_ops[ i ].op );
+ }
+ }
+
+ for ( i = 0; !BER_BVISNULL( &restricted_exops[ i ].op ); i++ ) {
+ if ( rp_add & restricted_exops[ i ].tag ) {
+ attr_merge_one( e, mi->mi_ad_restrictedOperation,
+ &restricted_exops[ i ].op,
+ &restricted_exops[ i ].op );
+ }
+ }
+ }
+ }
+
+ be->be_restrictops = rp_cur;
+
+done:;
+ if ( rc == LDAP_SUCCESS ) {
+ attrs_free( save_attrs );
+ rc = SLAP_CB_CONTINUE;
+
+ } else {
+ Attribute *tmp = e->e_attrs;
+ e->e_attrs = save_attrs;
+ attrs_free( tmp );
+ }
+ return rc;
+}
+
+#if defined(LDAP_SLAPI)
+static int
+monitor_back_add_plugin( monitor_info_t *mi, Backend *be, Entry *e_database )
+{
+ Slapi_PBlock *pCurrentPB;
+ int i, rc = LDAP_SUCCESS;
+
+ if ( slapi_int_pblock_get_first( be, &pCurrentPB ) != LDAP_SUCCESS ) {
+ /*
+ * LDAP_OTHER is returned if no plugins are installed
+ */
+ rc = LDAP_OTHER;
+ goto done;
+ }
+
+ i = 0;
+ do {
+ Slapi_PluginDesc *srchdesc;
+ char buf[ BACKMONITOR_BUFSIZE ];
+ struct berval bv;
+
+ rc = slapi_pblock_get( pCurrentPB, SLAPI_PLUGIN_DESCRIPTION,
+ &srchdesc );
+ if ( rc != LDAP_SUCCESS ) {
+ goto done;
+ }
+ if ( srchdesc ) {
+ snprintf( buf, sizeof(buf),
+ "plugin %d name: %s; "
+ "vendor: %s; "
+ "version: %s; "
+ "description: %s",
+ i,
+ srchdesc->spd_id,
+ srchdesc->spd_vendor,
+ srchdesc->spd_version,
+ srchdesc->spd_description );
+ } else {
+ snprintf( buf, sizeof(buf),
+ "plugin %d name: <no description available>", i );
+ }
+
+ ber_str2bv( buf, 0, 0, &bv );
+ attr_merge_normalize_one( e_database,
+ mi->mi_ad_monitoredInfo, &bv, NULL );
+
+ i++;
+
+ } while ( ( slapi_int_pblock_get_next( &pCurrentPB ) == LDAP_SUCCESS )
+ && ( pCurrentPB != NULL ) );
+
+done:
+ return rc;
+}
+#endif /* defined(LDAP_SLAPI) */
diff --git a/servers/slapd/back-monitor/entry.c b/servers/slapd/back-monitor/entry.c
new file mode 100644
index 0000000..1faf935
--- /dev/null
+++ b/servers/slapd/back-monitor/entry.c
@@ -0,0 +1,223 @@
+/* entry.c - monitor backend entry handling routines */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2001-2018 The OpenLDAP Foundation.
+ * Portions Copyright 2001-2003 Pierangelo Masarati.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Pierangelo Masarati for inclusion
+ * in OpenLDAP Software.
+ */
+
+#include "portable.h"
+
+#include <slap.h>
+#include "back-monitor.h"
+
+int
+monitor_entry_update(
+ Operation *op,
+ SlapReply *rs,
+ Entry *e
+)
+{
+ monitor_info_t *mi = ( monitor_info_t * )op->o_bd->be_private;
+ monitor_entry_t *mp;
+
+ int rc = SLAP_CB_CONTINUE;
+
+ assert( mi != NULL );
+ assert( e != NULL );
+ assert( e->e_private != NULL );
+
+ mp = ( monitor_entry_t * )e->e_private;
+
+ if ( mp->mp_cb ) {
+ struct monitor_callback_t *mc;
+
+ for ( mc = mp->mp_cb; mc; mc = mc->mc_next ) {
+ if ( mc->mc_update ) {
+ rc = mc->mc_update( op, rs, e, mc->mc_private );
+ if ( rc != SLAP_CB_CONTINUE ) {
+ break;
+ }
+ }
+ }
+ }
+
+ if ( rc == SLAP_CB_CONTINUE && mp->mp_info && mp->mp_info->mss_update ) {
+ rc = mp->mp_info->mss_update( op, rs, e );
+ }
+
+ if ( rc == SLAP_CB_CONTINUE ) {
+ rc = LDAP_SUCCESS;
+ }
+
+ return rc;
+}
+
+int
+monitor_entry_create(
+ Operation *op,
+ SlapReply *rs,
+ struct berval *ndn,
+ Entry *e_parent,
+ Entry **ep )
+{
+ monitor_info_t *mi = ( monitor_info_t * )op->o_bd->be_private;
+ monitor_entry_t *mp;
+
+ int rc = SLAP_CB_CONTINUE;
+
+ assert( mi != NULL );
+ assert( e_parent != NULL );
+ assert( e_parent->e_private != NULL );
+ assert( ep != NULL );
+
+ mp = ( monitor_entry_t * )e_parent->e_private;
+
+ if ( mp->mp_info && mp->mp_info->mss_create ) {
+ rc = mp->mp_info->mss_create( op, rs, ndn, e_parent, ep );
+ }
+
+ if ( rc == SLAP_CB_CONTINUE ) {
+ rc = LDAP_SUCCESS;
+ }
+
+ return rc;
+}
+
+int
+monitor_entry_modify(
+ Operation *op,
+ SlapReply *rs,
+ Entry *e
+)
+{
+ monitor_info_t *mi = ( monitor_info_t * )op->o_bd->be_private;
+ monitor_entry_t *mp;
+
+ int rc = SLAP_CB_CONTINUE;
+
+ assert( mi != NULL );
+ assert( e != NULL );
+ assert( e->e_private != NULL );
+
+ mp = ( monitor_entry_t * )e->e_private;
+
+ if ( mp->mp_cb ) {
+ struct monitor_callback_t *mc;
+
+ for ( mc = mp->mp_cb; mc; mc = mc->mc_next ) {
+ if ( mc->mc_modify ) {
+ rc = mc->mc_modify( op, rs, e, mc->mc_private );
+ if ( rc != SLAP_CB_CONTINUE ) {
+ break;
+ }
+ }
+ }
+ }
+
+ if ( rc == SLAP_CB_CONTINUE && mp->mp_info && mp->mp_info->mss_modify ) {
+ rc = mp->mp_info->mss_modify( op, rs, e );
+ }
+
+ if ( rc == SLAP_CB_CONTINUE ) {
+ rc = LDAP_SUCCESS;
+ }
+
+ return rc;
+}
+
+int
+monitor_entry_test_flags(
+ monitor_entry_t *mp,
+ int cond
+)
+{
+ assert( mp != NULL );
+
+ return( ( mp->mp_flags & cond ) || ( mp->mp_info->mss_flags & cond ) );
+}
+
+monitor_entry_t *
+monitor_back_entrypriv_create( void )
+{
+ monitor_entry_t *mp;
+
+ mp = ( monitor_entry_t * )ch_calloc( sizeof( monitor_entry_t ), 1 );
+
+ mp->mp_next = NULL;
+ mp->mp_children = NULL;
+ mp->mp_info = NULL;
+ mp->mp_flags = MONITOR_F_NONE;
+ mp->mp_cb = NULL;
+
+ ldap_pvt_thread_mutex_init( &mp->mp_mutex );
+
+ return mp;
+}
+
+Entry *
+monitor_entry_stub(
+ struct berval *pdn,
+ struct berval *pndn,
+ struct berval *rdn,
+ ObjectClass *oc,
+ struct berval *create,
+ struct berval *modify
+)
+{
+ monitor_info_t *mi;
+ AttributeDescription *nad = NULL;
+ Entry *e;
+ struct berval nat;
+ char *ptr;
+ const char *text;
+ int rc;
+
+ mi = ( monitor_info_t * )be_monitor->be_private;
+
+ nat = *rdn;
+ ptr = strchr( nat.bv_val, '=' );
+ nat.bv_len = ptr - nat.bv_val;
+ rc = slap_bv2ad( &nat, &nad, &text );
+ if ( rc )
+ return NULL;
+
+ e = entry_alloc();
+ if ( e ) {
+ struct berval nrdn;
+
+ rdnNormalize( 0, NULL, NULL, rdn, &nrdn, NULL );
+ build_new_dn( &e->e_name, pdn, rdn, NULL );
+ build_new_dn( &e->e_nname, pndn, &nrdn, NULL );
+ ber_memfree( nrdn.bv_val );
+ nat.bv_val = ptr + 1;
+ nat.bv_len = rdn->bv_len - ( nat.bv_val - rdn->bv_val );
+ attr_merge_normalize_one( e, slap_schema.si_ad_objectClass,
+ &oc->soc_cname, NULL );
+ attr_merge_normalize_one( e, slap_schema.si_ad_structuralObjectClass,
+ &oc->soc_cname, NULL );
+ attr_merge_normalize_one( e, nad, &nat, NULL );
+ attr_merge_one( e, slap_schema.si_ad_creatorsName, &mi->mi_creatorsName,
+ &mi->mi_ncreatorsName );
+ attr_merge_one( e, slap_schema.si_ad_modifiersName, &mi->mi_creatorsName,
+ &mi->mi_ncreatorsName );
+ attr_merge_normalize_one( e, slap_schema.si_ad_createTimestamp,
+ create ? create : &mi->mi_startTime, NULL );
+ attr_merge_normalize_one( e, slap_schema.si_ad_modifyTimestamp,
+ modify ? modify : &mi->mi_startTime, NULL );
+ }
+ return e;
+}
diff --git a/servers/slapd/back-monitor/init.c b/servers/slapd/back-monitor/init.c
new file mode 100644
index 0000000..bb4c419
--- /dev/null
+++ b/servers/slapd/back-monitor/init.c
@@ -0,0 +1,2598 @@
+/* init.c - initialize monitor backend */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2001-2018 The OpenLDAP Foundation.
+ * Portions Copyright 2001-2003 Pierangelo Masarati.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Pierangelo Masarati for inclusion
+ * in OpenLDAP Software.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+
+#include <lutil.h>
+#include "slap.h"
+#include "config.h"
+#include "lber_pvt.h"
+#include "back-monitor.h"
+
+#include "config.h"
+
+#undef INTEGRATE_CORE_SCHEMA
+
+/*
+ * used by many functions to add description to entries
+ *
+ * WARNING: be_monitor may change as new databases are added,
+ * so it should not be used outside monitor_back_db_init()
+ * until monitor_back_db_open is called.
+ */
+BackendDB *be_monitor;
+
+static struct monitor_subsys_t **monitor_subsys;
+static int monitor_subsys_opened;
+static monitor_info_t monitor_info;
+static const monitor_extra_t monitor_extra = {
+ monitor_back_is_configured,
+ monitor_back_get_subsys,
+ monitor_back_get_subsys_by_dn,
+
+ monitor_back_register_subsys,
+ monitor_back_register_backend,
+ monitor_back_register_database,
+ monitor_back_register_overlay_info,
+ monitor_back_register_overlay,
+ monitor_back_register_entry,
+ monitor_back_register_entry_parent,
+ monitor_back_register_entry_attrs,
+ monitor_back_register_entry_callback,
+
+ monitor_back_unregister_entry,
+ monitor_back_unregister_entry_parent,
+ monitor_back_unregister_entry_attrs,
+ monitor_back_unregister_entry_callback,
+
+ monitor_back_entry_stub,
+ monitor_back_entrypriv_create,
+ monitor_back_register_subsys_late
+};
+
+
+/*
+ * subsystem data
+ *
+ * the known subsystems are added to the subsystems
+ * array at backend initialization; other subsystems
+ * may be added by calling monitor_back_register_subsys()
+ * before the database is opened (e.g. by other backends
+ * or by overlays or modules).
+ */
+static struct monitor_subsys_t known_monitor_subsys[] = {
+ {
+ SLAPD_MONITOR_BACKEND_NAME,
+ BER_BVNULL, BER_BVNULL, BER_BVNULL,
+ { BER_BVC( "This subsystem contains information about available backends." ),
+ BER_BVNULL },
+ MONITOR_F_PERSISTENT_CH,
+ monitor_subsys_backend_init,
+ NULL, /* destroy */
+ NULL, /* update */
+ NULL, /* create */
+ NULL /* modify */
+ }, {
+ SLAPD_MONITOR_CONN_NAME,
+ BER_BVNULL, BER_BVNULL, BER_BVNULL,
+ { BER_BVC( "This subsystem contains information about connections." ),
+ BER_BVNULL },
+ MONITOR_F_VOLATILE_CH,
+ monitor_subsys_conn_init,
+ NULL, /* destroy */
+ NULL, /* update */
+ NULL, /* create */
+ NULL /* modify */
+ }, {
+ SLAPD_MONITOR_DATABASE_NAME,
+ BER_BVNULL, BER_BVNULL, BER_BVNULL,
+ { BER_BVC( "This subsystem contains information about configured databases." ),
+ BER_BVNULL },
+ MONITOR_F_PERSISTENT_CH,
+ monitor_subsys_database_init,
+ NULL, /* destroy */
+ NULL, /* update */
+ NULL, /* create */
+ NULL /* modify */
+ }, {
+ SLAPD_MONITOR_LISTENER_NAME,
+ BER_BVNULL, BER_BVNULL, BER_BVNULL,
+ { BER_BVC( "This subsystem contains information about active listeners." ),
+ BER_BVNULL },
+ MONITOR_F_PERSISTENT_CH,
+ monitor_subsys_listener_init,
+ NULL, /* destroy */
+ NULL, /* update */
+ NULL, /* create */
+ NULL /* modify */
+ }, {
+ SLAPD_MONITOR_LOG_NAME,
+ BER_BVNULL, BER_BVNULL, BER_BVNULL,
+ { BER_BVC( "This subsystem contains information about logging." ),
+ BER_BVC( "Set the attribute \"managedInfo\" to the desired log levels." ),
+ BER_BVNULL },
+ MONITOR_F_NONE,
+ monitor_subsys_log_init,
+ NULL, /* destroy */
+ NULL, /* update */
+ NULL, /* create */
+ NULL, /* modify */
+ }, {
+ SLAPD_MONITOR_OPS_NAME,
+ BER_BVNULL, BER_BVNULL, BER_BVNULL,
+ { BER_BVC( "This subsystem contains information about performed operations." ),
+ BER_BVNULL },
+ MONITOR_F_PERSISTENT_CH,
+ monitor_subsys_ops_init,
+ NULL, /* destroy */
+ NULL, /* update */
+ NULL, /* create */
+ NULL, /* modify */
+ }, {
+ SLAPD_MONITOR_OVERLAY_NAME,
+ BER_BVNULL, BER_BVNULL, BER_BVNULL,
+ { BER_BVC( "This subsystem contains information about available overlays." ),
+ BER_BVNULL },
+ MONITOR_F_PERSISTENT_CH,
+ monitor_subsys_overlay_init,
+ NULL, /* destroy */
+ NULL, /* update */
+ NULL, /* create */
+ NULL, /* modify */
+ }, {
+ SLAPD_MONITOR_SASL_NAME,
+ BER_BVNULL, BER_BVNULL, BER_BVNULL,
+ { BER_BVC( "This subsystem contains information about SASL." ),
+ BER_BVNULL },
+ MONITOR_F_NONE,
+ NULL, /* init */
+ NULL, /* destroy */
+ NULL, /* update */
+ NULL, /* create */
+ NULL /* modify */
+ }, {
+ SLAPD_MONITOR_SENT_NAME,
+ BER_BVNULL, BER_BVNULL, BER_BVNULL,
+ { BER_BVC( "This subsystem contains statistics." ),
+ BER_BVNULL },
+ MONITOR_F_PERSISTENT_CH,
+ monitor_subsys_sent_init,
+ NULL, /* destroy */
+ NULL, /* update */
+ NULL, /* create */
+ NULL, /* modify */
+ }, {
+ SLAPD_MONITOR_THREAD_NAME,
+ BER_BVNULL, BER_BVNULL, BER_BVNULL,
+ { BER_BVC( "This subsystem contains information about threads." ),
+ BER_BVNULL },
+ MONITOR_F_PERSISTENT_CH,
+ monitor_subsys_thread_init,
+ NULL, /* destroy */
+ NULL, /* update */
+ NULL, /* create */
+ NULL /* modify */
+ }, {
+ SLAPD_MONITOR_TIME_NAME,
+ BER_BVNULL, BER_BVNULL, BER_BVNULL,
+ { BER_BVC( "This subsystem contains information about time." ),
+ BER_BVNULL },
+ MONITOR_F_PERSISTENT_CH,
+ monitor_subsys_time_init,
+ NULL, /* destroy */
+ NULL, /* update */
+ NULL, /* create */
+ NULL, /* modify */
+ }, {
+ SLAPD_MONITOR_TLS_NAME,
+ BER_BVNULL, BER_BVNULL, BER_BVNULL,
+ { BER_BVC( "This subsystem contains information about TLS." ),
+ BER_BVNULL },
+ MONITOR_F_NONE,
+ NULL, /* init */
+ NULL, /* destroy */
+ NULL, /* update */
+ NULL, /* create */
+ NULL /* modify */
+ }, {
+ SLAPD_MONITOR_RWW_NAME,
+ BER_BVNULL, BER_BVNULL, BER_BVNULL,
+ { BER_BVC( "This subsystem contains information about read/write waiters." ),
+ BER_BVNULL },
+ MONITOR_F_PERSISTENT_CH,
+ monitor_subsys_rww_init,
+ NULL, /* destroy */
+ NULL, /* update */
+ NULL, /* create */
+ NULL /* modify */
+ }, { NULL }
+};
+
+int
+monitor_subsys_is_opened( void )
+{
+ return monitor_subsys_opened;
+}
+
+int
+monitor_back_register_subsys(
+ monitor_subsys_t *ms )
+{
+ int i = 0;
+
+ if ( monitor_subsys ) {
+ for ( ; monitor_subsys[ i ] != NULL; i++ )
+ /* just count'em */ ;
+ }
+
+ monitor_subsys = ch_realloc( monitor_subsys,
+ ( 2 + i ) * sizeof( monitor_subsys_t * ) );
+
+ if ( monitor_subsys == NULL ) {
+ return -1;
+ }
+
+ monitor_subsys[ i ] = ms;
+ monitor_subsys[ i + 1 ] = NULL;
+
+ /* if a subsystem is registered __AFTER__ subsystem
+ * initialization (depending on the sequence the databases
+ * are listed in slapd.conf), init it */
+ if ( monitor_subsys_is_opened() ) {
+
+ /* FIXME: this should only be possible
+ * if be_monitor is already initialized */
+ assert( be_monitor != NULL );
+
+ if ( ms->mss_open && ( *ms->mss_open )( be_monitor, ms ) ) {
+ return -1;
+ }
+
+ ms->mss_flags |= MONITOR_F_OPENED;
+ }
+
+ return 0;
+}
+
+enum {
+ LIMBO_ENTRY,
+ LIMBO_ENTRY_PARENT,
+ LIMBO_ATTRS,
+ LIMBO_CB,
+ LIMBO_BACKEND,
+ LIMBO_DATABASE,
+ LIMBO_OVERLAY_INFO,
+ LIMBO_OVERLAY,
+ LIMBO_SUBSYS,
+
+ LIMBO_LAST
+};
+
+typedef struct entry_limbo_t {
+ int el_type;
+ BackendInfo *el_bi;
+ BackendDB *el_be;
+ slap_overinst *el_on;
+ Entry *el_e;
+ Attribute *el_a;
+ struct berval *el_ndn;
+ struct berval el_nbase;
+ int el_scope;
+ struct berval el_filter;
+ monitor_callback_t *el_cb;
+ monitor_subsys_t *el_mss;
+ unsigned long el_flags;
+ struct entry_limbo_t *el_next;
+} entry_limbo_t;
+
+int
+monitor_back_is_configured( void )
+{
+ return be_monitor != NULL;
+}
+
+int
+monitor_back_register_subsys_late(
+ monitor_subsys_t *ms )
+{
+ entry_limbo_t **elpp, el = { 0 };
+ monitor_info_t *mi;
+
+ if ( be_monitor == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_register_subsys_late: "
+ "monitor database not configured.\n",
+ 0, 0, 0 );
+ return -1;
+ }
+
+ /* everyting is ready, can register already */
+ if ( monitor_subsys_is_opened() ) {
+ return monitor_back_register_subsys( ms );
+ }
+
+ mi = ( monitor_info_t * )be_monitor->be_private;
+
+
+ el.el_type = LIMBO_SUBSYS;
+
+ el.el_mss = ms;
+
+ for ( elpp = &mi->mi_entry_limbo;
+ *elpp;
+ elpp = &(*elpp)->el_next )
+ /* go to last */;
+
+ *elpp = (entry_limbo_t *)ch_malloc( sizeof( entry_limbo_t ) );
+
+ el.el_next = NULL;
+ **elpp = el;
+
+ return 0;
+}
+
+int
+monitor_back_register_backend(
+ BackendInfo *bi )
+{
+ return -1;
+}
+
+int
+monitor_back_register_overlay_info(
+ slap_overinst *on )
+{
+ return -1;
+}
+
+int
+monitor_back_register_backend_limbo(
+ BackendInfo *bi )
+{
+ return -1;
+}
+
+int
+monitor_back_register_database_limbo(
+ BackendDB *be,
+ struct berval *ndn_out )
+{
+ entry_limbo_t **elpp, el = { 0 };
+ monitor_info_t *mi;
+
+ if ( be_monitor == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_register_database_limbo: "
+ "monitor database not configured.\n",
+ 0, 0, 0 );
+ return -1;
+ }
+
+ mi = ( monitor_info_t * )be_monitor->be_private;
+
+
+ el.el_type = LIMBO_DATABASE;
+
+ el.el_be = be->bd_self;
+ el.el_ndn = ndn_out;
+
+ for ( elpp = &mi->mi_entry_limbo;
+ *elpp;
+ elpp = &(*elpp)->el_next )
+ /* go to last */;
+
+ *elpp = (entry_limbo_t *)ch_malloc( sizeof( entry_limbo_t ) );
+
+ el.el_next = NULL;
+ **elpp = el;
+
+ return 0;
+}
+
+int
+monitor_back_register_overlay_info_limbo(
+ slap_overinst *on )
+{
+ return -1;
+}
+
+int
+monitor_back_register_overlay_limbo(
+ BackendDB *be,
+ struct slap_overinst *on,
+ struct berval *ndn_out )
+{
+ entry_limbo_t **elpp, el = { 0 };
+ monitor_info_t *mi;
+
+ if ( be_monitor == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_register_overlay_limbo: "
+ "monitor database not configured.\n",
+ 0, 0, 0 );
+ return -1;
+ }
+
+ mi = ( monitor_info_t * )be_monitor->be_private;
+
+
+ el.el_type = LIMBO_OVERLAY;
+
+ el.el_be = be->bd_self;
+ el.el_on = on;
+ el.el_ndn = ndn_out;
+
+ for ( elpp = &mi->mi_entry_limbo;
+ *elpp;
+ elpp = &(*elpp)->el_next )
+ /* go to last */;
+
+ *elpp = (entry_limbo_t *)ch_malloc( sizeof( entry_limbo_t ) );
+
+ el.el_next = NULL;
+ **elpp = el;
+
+ return 0;
+}
+
+int
+monitor_back_register_entry(
+ Entry *e,
+ monitor_callback_t *cb,
+ monitor_subsys_t *mss,
+ unsigned long flags )
+{
+ monitor_info_t *mi;
+
+ if ( be_monitor == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_register_entry(\"%s\"): "
+ "monitor database not configured.\n",
+ e->e_name.bv_val, 0, 0 );
+ return -1;
+ }
+
+ mi = ( monitor_info_t * )be_monitor->be_private;
+
+ assert( mi != NULL );
+ assert( e != NULL );
+ assert( e->e_private == NULL );
+
+ if ( monitor_subsys_is_opened() ) {
+ Entry *e_parent = NULL,
+ *e_new = NULL,
+ **ep = NULL;
+ struct berval pdn = BER_BVNULL;
+ monitor_entry_t *mp = NULL,
+ *mp_parent = NULL;
+ int rc = 0;
+
+ if ( monitor_cache_get( mi, &e->e_nname, &e_parent ) == 0 ) {
+ /* entry exists */
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_register_entry(\"%s\"): "
+ "entry exists\n",
+ e->e_name.bv_val, 0, 0 );
+ monitor_cache_release( mi, e_parent );
+ return -1;
+ }
+
+ dnParent( &e->e_nname, &pdn );
+ if ( monitor_cache_get( mi, &pdn, &e_parent ) != 0 ) {
+ /* parent does not exist */
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_register_entry(\"%s\"): "
+ "parent \"%s\" not found\n",
+ e->e_name.bv_val, pdn.bv_val, 0 );
+ return -1;
+ }
+
+ assert( e_parent->e_private != NULL );
+ mp_parent = ( monitor_entry_t * )e_parent->e_private;
+
+ if ( mp_parent->mp_flags & MONITOR_F_VOLATILE ) {
+ /* entry is volatile; cannot append children */
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_register_entry(\"%s\"): "
+ "parent \"%s\" is volatile\n",
+ e->e_name.bv_val, e_parent->e_name.bv_val, 0 );
+ rc = -1;
+ goto done;
+ }
+
+ mp = monitor_entrypriv_create();
+ if ( mp == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_register_entry(\"%s\"): "
+ "monitor_entrypriv_create() failed\n",
+ e->e_name.bv_val, 0, 0 );
+ rc = -1;
+ goto done;
+ }
+
+ e_new = entry_dup( e );
+ if ( e_new == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_register_entry(\"%s\"): "
+ "entry_dup() failed\n",
+ e->e_name.bv_val, 0, 0 );
+ rc = -1;
+ goto done;
+ }
+
+ e_new->e_private = ( void * )mp;
+ if ( mss != NULL ) {
+ mp->mp_info = mss;
+ mp->mp_flags = flags;
+
+ } else {
+ mp->mp_info = mp_parent->mp_info;
+ mp->mp_flags = mp_parent->mp_flags | MONITOR_F_SUB;
+ }
+ mp->mp_cb = cb;
+
+ ep = &mp_parent->mp_children;
+ for ( ; *ep; ) {
+ mp_parent = ( monitor_entry_t * )(*ep)->e_private;
+ ep = &mp_parent->mp_next;
+ }
+ *ep = e_new;
+
+ if ( monitor_cache_add( mi, e_new ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_register_entry(\"%s\"): "
+ "unable to add entry\n",
+ e->e_name.bv_val, 0, 0 );
+ rc = -1;
+ goto done;
+ }
+
+done:;
+ if ( rc ) {
+ if ( mp ) {
+ ch_free( mp );
+ }
+ if ( e_new ) {
+ e_new->e_private = NULL;
+ entry_free( e_new );
+ }
+ }
+
+ if ( e_parent ) {
+ monitor_cache_release( mi, e_parent );
+ }
+
+ } else {
+ entry_limbo_t **elpp, el = { 0 };
+
+ el.el_type = LIMBO_ENTRY;
+
+ el.el_e = entry_dup( e );
+ if ( el.el_e == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_register_entry(\"%s\"): "
+ "entry_dup() failed\n",
+ e->e_name.bv_val, 0, 0 );
+ return -1;
+ }
+
+ el.el_cb = cb;
+ el.el_mss = mss;
+ el.el_flags = flags;
+
+ for ( elpp = &mi->mi_entry_limbo;
+ *elpp;
+ elpp = &(*elpp)->el_next )
+ /* go to last */;
+
+ *elpp = (entry_limbo_t *)ch_malloc( sizeof( entry_limbo_t ) );
+ if ( *elpp == NULL ) {
+ el.el_e->e_private = NULL;
+ entry_free( el.el_e );
+ return -1;
+ }
+
+ el.el_next = NULL;
+ **elpp = el;
+ }
+
+ return 0;
+}
+
+int
+monitor_back_register_entry_parent(
+ Entry *e,
+ monitor_callback_t *cb,
+ monitor_subsys_t *mss,
+ unsigned long flags,
+ struct berval *nbase,
+ int scope,
+ struct berval *filter )
+{
+ monitor_info_t *mi;
+ struct berval ndn = BER_BVNULL;
+
+ if ( be_monitor == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_register_entry_parent(base=\"%s\" scope=%s filter=\"%s\"): "
+ "monitor database not configured.\n",
+ BER_BVISNULL( nbase ) ? "" : nbase->bv_val,
+ ldap_pvt_scope2str( scope ),
+ BER_BVISNULL( filter ) ? "" : filter->bv_val );
+ return -1;
+ }
+
+ mi = ( monitor_info_t * )be_monitor->be_private;
+
+ assert( mi != NULL );
+ assert( e != NULL );
+ assert( e->e_private == NULL );
+
+ if ( BER_BVISNULL( filter ) ) {
+ /* need a filter */
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_register_entry_parent(\"\"): "
+ "need a valid filter\n",
+ 0, 0, 0 );
+ return -1;
+ }
+
+ if ( monitor_subsys_is_opened() ) {
+ Entry *e_parent = NULL,
+ *e_new = NULL,
+ **ep = NULL;
+ struct berval e_name = BER_BVNULL,
+ e_nname = BER_BVNULL;
+ monitor_entry_t *mp = NULL,
+ *mp_parent = NULL;
+ int rc = 0;
+
+ if ( monitor_search2ndn( nbase, scope, filter, &ndn ) ) {
+ /* entry does not exist */
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_register_entry_parent(\"\"): "
+ "base=\"%s\" scope=%s filter=\"%s\": "
+ "unable to find entry\n",
+ nbase->bv_val ? nbase->bv_val : "\"\"",
+ ldap_pvt_scope2str( scope ),
+ filter->bv_val );
+ return -1;
+ }
+
+ if ( monitor_cache_get( mi, &ndn, &e_parent ) != 0 ) {
+ /* entry does not exist */
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_register_entry_parent(\"%s\"): "
+ "parent entry does not exist\n",
+ ndn.bv_val, 0, 0 );
+ rc = -1;
+ goto done;
+ }
+
+ assert( e_parent->e_private != NULL );
+ mp_parent = ( monitor_entry_t * )e_parent->e_private;
+
+ if ( mp_parent->mp_flags & MONITOR_F_VOLATILE ) {
+ /* entry is volatile; cannot append callback */
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_register_entry_parent(\"%s\"): "
+ "entry is volatile\n",
+ e_parent->e_name.bv_val, 0, 0 );
+ rc = -1;
+ goto done;
+ }
+
+ build_new_dn( &e_name, &e_parent->e_name, &e->e_name, NULL );
+ build_new_dn( &e_nname, &e_parent->e_nname, &e->e_nname, NULL );
+
+ if ( monitor_cache_get( mi, &e_nname, &e_new ) == 0 ) {
+ /* entry already exists */
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_register_entry_parent(\"%s\"): "
+ "entry already exists\n",
+ e_name.bv_val, 0, 0 );
+ monitor_cache_release( mi, e_new );
+ e_new = NULL;
+ rc = -1;
+ goto done;
+ }
+
+ mp = monitor_entrypriv_create();
+ if ( mp == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_register_entry_parent(\"%s\"): "
+ "monitor_entrypriv_create() failed\n",
+ e->e_name.bv_val, 0, 0 );
+ rc = -1;
+ goto done;
+ }
+
+ e_new = entry_dup( e );
+ if ( e_new == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_register_entry(\"%s\"): "
+ "entry_dup() failed\n",
+ e->e_name.bv_val, 0, 0 );
+ rc = -1;
+ goto done;
+ }
+ ch_free( e_new->e_name.bv_val );
+ ch_free( e_new->e_nname.bv_val );
+ e_new->e_name = e_name;
+ e_new->e_nname = e_nname;
+
+ e_new->e_private = ( void * )mp;
+ if ( mss != NULL ) {
+ mp->mp_info = mss;
+ mp->mp_flags = flags;
+
+ } else {
+ mp->mp_info = mp_parent->mp_info;
+ mp->mp_flags = mp_parent->mp_flags | MONITOR_F_SUB;
+ }
+ mp->mp_cb = cb;
+
+ ep = &mp_parent->mp_children;
+ for ( ; *ep; ) {
+ mp_parent = ( monitor_entry_t * )(*ep)->e_private;
+ ep = &mp_parent->mp_next;
+ }
+ *ep = e_new;
+
+ if ( monitor_cache_add( mi, e_new ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_register_entry(\"%s\"): "
+ "unable to add entry\n",
+ e->e_name.bv_val, 0, 0 );
+ rc = -1;
+ goto done;
+ }
+
+done:;
+ if ( !BER_BVISNULL( &ndn ) ) {
+ ch_free( ndn.bv_val );
+ }
+
+ if ( rc ) {
+ if ( mp ) {
+ ch_free( mp );
+ }
+ if ( e_new ) {
+ e_new->e_private = NULL;
+ entry_free( e_new );
+ }
+ }
+
+ if ( e_parent ) {
+ monitor_cache_release( mi, e_parent );
+ }
+
+ } else {
+ entry_limbo_t **elpp = NULL, el = { 0 };
+
+ el.el_type = LIMBO_ENTRY_PARENT;
+
+ el.el_e = entry_dup( e );
+ if ( el.el_e == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_register_entry(\"%s\"): "
+ "entry_dup() failed\n",
+ e->e_name.bv_val, 0, 0 );
+ goto done_limbo;
+ }
+
+ if ( !BER_BVISNULL( nbase ) ) {
+ ber_dupbv( &el.el_nbase, nbase );
+ }
+
+ el.el_scope = scope;
+ if ( !BER_BVISNULL( filter ) ) {
+ ber_dupbv( &el.el_filter, filter );
+ }
+
+ el.el_cb = cb;
+ el.el_mss = mss;
+ el.el_flags = flags;
+
+ for ( elpp = &mi->mi_entry_limbo;
+ *elpp;
+ elpp = &(*elpp)->el_next )
+ /* go to last */;
+
+ *elpp = (entry_limbo_t *)ch_malloc( sizeof( entry_limbo_t ) );
+ if ( *elpp == NULL ) {
+ goto done_limbo;
+ }
+
+done_limbo:;
+ if ( *elpp != NULL ) {
+ el.el_next = NULL;
+ **elpp = el;
+
+ } else {
+ if ( !BER_BVISNULL( &el.el_filter ) ) {
+ ch_free( el.el_filter.bv_val );
+ }
+ if ( !BER_BVISNULL( &el.el_nbase ) ) {
+ ch_free( el.el_nbase.bv_val );
+ }
+ entry_free( el.el_e );
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int
+monitor_search2ndn_cb( Operation *op, SlapReply *rs )
+{
+ if ( rs->sr_type == REP_SEARCH ) {
+ struct berval *ndn = op->o_callback->sc_private;
+
+ if ( !BER_BVISNULL( ndn ) ) {
+ rs->sr_err = LDAP_SIZELIMIT_EXCEEDED;
+ ch_free( ndn->bv_val );
+ BER_BVZERO( ndn );
+ return rs->sr_err;
+ }
+
+ ber_dupbv( ndn, &rs->sr_entry->e_nname );
+ }
+
+ return 0;
+}
+
+int
+monitor_search2ndn(
+ struct berval *nbase,
+ int scope,
+ struct berval *filter,
+ struct berval *ndn )
+{
+ Connection conn = { 0 };
+ OperationBuffer opbuf;
+ Operation *op;
+ void *thrctx;
+ SlapReply rs = { REP_RESULT };
+ slap_callback cb = { NULL, monitor_search2ndn_cb, NULL, NULL };
+ int rc;
+
+ BER_BVZERO( ndn );
+
+ if ( be_monitor == NULL ) {
+ return -1;
+ }
+
+ thrctx = ldap_pvt_thread_pool_context();
+ connection_fake_init2( &conn, &opbuf, thrctx, 0 );
+ op = &opbuf.ob_op;
+
+ op->o_tag = LDAP_REQ_SEARCH;
+
+ /* use global malloc for now */
+ if ( op->o_tmpmemctx ) {
+ op->o_tmpmemctx = NULL;
+ }
+ op->o_tmpmfuncs = &ch_mfuncs;
+
+ op->o_bd = be_monitor;
+ if ( nbase == NULL || BER_BVISNULL( nbase ) ) {
+ ber_dupbv_x( &op->o_req_dn, &op->o_bd->be_suffix[ 0 ],
+ op->o_tmpmemctx );
+ ber_dupbv_x( &op->o_req_ndn, &op->o_bd->be_nsuffix[ 0 ],
+ op->o_tmpmemctx );
+
+ } else {
+ if ( dnPrettyNormal( NULL, nbase, &op->o_req_dn, &op->o_req_ndn,
+ op->o_tmpmemctx ) ) {
+ return -1;
+ }
+ }
+
+ op->o_callback = &cb;
+ cb.sc_private = (void *)ndn;
+
+ op->ors_scope = scope;
+ op->ors_filter = str2filter_x( op, filter->bv_val );
+ if ( op->ors_filter == NULL ) {
+ rc = LDAP_OTHER;
+ goto cleanup;
+ }
+ ber_dupbv_x( &op->ors_filterstr, filter, op->o_tmpmemctx );
+ op->ors_attrs = slap_anlist_no_attrs;
+ op->ors_attrsonly = 0;
+ op->ors_tlimit = SLAP_NO_LIMIT;
+ op->ors_slimit = 1;
+ op->ors_limit = NULL;
+ op->ors_deref = LDAP_DEREF_NEVER;
+
+ op->o_nocaching = 1;
+ op->o_managedsait = SLAP_CONTROL_NONCRITICAL;
+
+ op->o_dn = be_monitor->be_rootdn;
+ op->o_ndn = be_monitor->be_rootndn;
+
+ rc = op->o_bd->be_search( op, &rs );
+
+cleanup:;
+ if ( op->ors_filter != NULL ) {
+ filter_free_x( op, op->ors_filter, 1 );
+ }
+ if ( !BER_BVISNULL( &op->ors_filterstr ) ) {
+ op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
+ }
+ if ( !BER_BVISNULL( &op->o_req_dn ) ) {
+ op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx );
+ }
+ if ( !BER_BVISNULL( &op->o_req_ndn ) ) {
+ op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx );
+ }
+
+ if ( rc != 0 ) {
+ return rc;
+ }
+
+ switch ( rs.sr_err ) {
+ case LDAP_SUCCESS:
+ if ( BER_BVISNULL( ndn ) ) {
+ rc = -1;
+ }
+ break;
+
+ case LDAP_SIZELIMIT_EXCEEDED:
+ default:
+ if ( !BER_BVISNULL( ndn ) ) {
+ ber_memfree( ndn->bv_val );
+ BER_BVZERO( ndn );
+ }
+ rc = -1;
+ break;
+ }
+
+ return rc;
+}
+
+int
+monitor_back_register_entry_attrs(
+ struct berval *ndn_in,
+ Attribute *a,
+ monitor_callback_t *cb,
+ struct berval *nbase,
+ int scope,
+ struct berval *filter )
+{
+ monitor_info_t *mi;
+ struct berval ndn = BER_BVNULL;
+ char *fname = ( a == NULL ? "callback" : "attrs" );
+ struct berval empty_bv = BER_BVC("");
+
+ if ( nbase == NULL ) nbase = &empty_bv;
+ if ( filter == NULL ) filter = &empty_bv;
+
+ if ( be_monitor == NULL ) {
+ char buf[ SLAP_TEXT_BUFLEN ];
+
+ snprintf( buf, sizeof( buf ),
+ "monitor_back_register_entry_%s(base=\"%s\" scope=%s filter=\"%s\"): "
+ "monitor database not configured.\n",
+ fname,
+ BER_BVISNULL( nbase ) ? "" : nbase->bv_val,
+ ldap_pvt_scope2str( scope ),
+ BER_BVISNULL( filter ) ? "" : filter->bv_val );
+ Debug( LDAP_DEBUG_ANY, "%s\n", buf, 0, 0 );
+
+ return -1;
+ }
+
+ mi = ( monitor_info_t * )be_monitor->be_private;
+
+ assert( mi != NULL );
+
+ if ( ndn_in != NULL ) {
+ ndn = *ndn_in;
+ }
+
+ if ( a == NULL && cb == NULL ) {
+ /* nothing to do */
+ return -1;
+ }
+
+ if ( ( ndn_in == NULL || BER_BVISNULL( &ndn ) )
+ && BER_BVISNULL( filter ) )
+ {
+ /* need a filter */
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_register_entry_%s(\"\"): "
+ "need a valid filter\n",
+ fname, 0, 0 );
+ return -1;
+ }
+
+ if ( monitor_subsys_is_opened() ) {
+ Entry *e = NULL;
+ Attribute **atp = NULL;
+ monitor_entry_t *mp = NULL;
+ monitor_callback_t **mcp = NULL;
+ int rc = 0;
+ int freeit = 0;
+
+ if ( BER_BVISNULL( &ndn ) ) {
+ if ( monitor_search2ndn( nbase, scope, filter, &ndn ) ) {
+ char buf[ SLAP_TEXT_BUFLEN ];
+
+ snprintf( buf, sizeof( buf ),
+ "monitor_back_register_entry_%s(\"\"): "
+ "base=\"%s\" scope=%s filter=\"%s\": "
+ "unable to find entry\n",
+ fname,
+ nbase->bv_val ? nbase->bv_val : "\"\"",
+ ldap_pvt_scope2str( scope ),
+ filter->bv_val );
+
+ /* entry does not exist */
+ Debug( LDAP_DEBUG_ANY, "%s\n", buf, 0, 0 );
+ return -1;
+ }
+
+ freeit = 1;
+ }
+
+ if ( monitor_cache_get( mi, &ndn, &e ) != 0 ) {
+ /* entry does not exist */
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_register_entry_%s(\"%s\"): "
+ "entry does not exist\n",
+ fname, ndn.bv_val, 0 );
+ rc = -1;
+ goto done;
+ }
+
+ assert( e->e_private != NULL );
+ mp = ( monitor_entry_t * )e->e_private;
+
+ if ( mp->mp_flags & MONITOR_F_VOLATILE ) {
+ /* entry is volatile; cannot append callback */
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_register_entry_%s(\"%s\"): "
+ "entry is volatile\n",
+ fname, e->e_name.bv_val, 0 );
+ rc = -1;
+ goto done;
+ }
+
+ if ( a ) {
+ for ( atp = &e->e_attrs; *atp; atp = &(*atp)->a_next )
+ /* just get to last */ ;
+
+ for ( ; a != NULL; a = a->a_next ) {
+ assert( a->a_desc != NULL );
+ assert( a->a_vals != NULL );
+
+ if ( attr_find( e->e_attrs, a->a_desc ) ) {
+ attr_merge( e, a->a_desc, a->a_vals,
+ a->a_nvals == a->a_vals ? NULL : a->a_nvals );
+
+ } else {
+ *atp = attr_dup( a );
+ if ( *atp == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_register_entry_%s(\"%s\"): "
+ "attr_dup() failed\n",
+ fname, e->e_name.bv_val, 0 );
+ rc = -1;
+ goto done;
+ }
+ atp = &(*atp)->a_next;
+ }
+ }
+ }
+
+ if ( cb ) {
+ for ( mcp = &mp->mp_cb; *mcp; mcp = &(*mcp)->mc_next )
+ /* go to tail */ ;
+
+ /* NOTE: we do not clear cb->mc_next, so this function
+ * can be used to append a list of callbacks */
+ (*mcp) = cb;
+ }
+
+done:;
+ if ( rc ) {
+ if ( atp && *atp ) {
+ attrs_free( *atp );
+ *atp = NULL;
+ }
+ }
+
+ if ( freeit ) {
+ ber_memfree( ndn.bv_val );
+ }
+
+ if ( e ) {
+ monitor_cache_release( mi, e );
+ }
+
+ } else {
+ entry_limbo_t **elpp, el = { 0 };
+
+ el.el_type = LIMBO_ATTRS;
+ el.el_ndn = ndn_in;
+ if ( !BER_BVISNULL( nbase ) ) {
+ ber_dupbv( &el.el_nbase, nbase);
+ }
+ el.el_scope = scope;
+ if ( !BER_BVISNULL( filter ) ) {
+ ber_dupbv( &el.el_filter, filter );
+ }
+
+ el.el_a = attrs_dup( a );
+ el.el_cb = cb;
+
+ for ( elpp = &mi->mi_entry_limbo;
+ *elpp;
+ elpp = &(*elpp)->el_next )
+ /* go to last */;
+
+ *elpp = (entry_limbo_t *)ch_malloc( sizeof( entry_limbo_t ) );
+ if ( *elpp == NULL ) {
+ if ( !BER_BVISNULL( &el.el_filter ) ) {
+ ch_free( el.el_filter.bv_val );
+ }
+ if ( el.el_a != NULL ) {
+ attrs_free( el.el_a );
+ }
+ if ( !BER_BVISNULL( &el.el_nbase ) ) {
+ ch_free( &el.el_nbase.bv_val );
+ }
+ return -1;
+ }
+
+ el.el_next = NULL;
+ **elpp = el;
+ }
+
+ return 0;
+}
+
+int
+monitor_back_register_entry_callback(
+ struct berval *ndn,
+ monitor_callback_t *cb,
+ struct berval *nbase,
+ int scope,
+ struct berval *filter )
+{
+ return monitor_back_register_entry_attrs( ndn, NULL, cb,
+ nbase, scope, filter );
+}
+
+/*
+ * TODO: add corresponding calls to remove installed callbacks, entries
+ * and so, in case the entity that installed them is removed (e.g. a
+ * database, via back-config)
+ */
+int
+monitor_back_unregister_entry(
+ struct berval *ndn )
+{
+ monitor_info_t *mi;
+
+ if ( be_monitor == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_unregister_entry(\"%s\"): "
+ "monitor database not configured.\n",
+ ndn->bv_val, 0, 0 );
+
+ return -1;
+ }
+
+ /* entry will be regularly freed, and resources released
+ * according to callbacks */
+ if ( slapd_shutdown ) {
+ return 0;
+ }
+
+ mi = ( monitor_info_t * )be_monitor->be_private;
+
+ assert( mi != NULL );
+
+ if ( monitor_subsys_is_opened() ) {
+ Entry *e = NULL;
+ monitor_entry_t *mp = NULL;
+ monitor_callback_t *cb = NULL;
+
+ if ( monitor_cache_remove( mi, ndn, &e ) != 0 ) {
+ /* entry does not exist */
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_unregister_entry(\"%s\"): "
+ "entry removal failed.\n",
+ ndn->bv_val, 0, 0 );
+ return -1;
+ }
+
+ mp = (monitor_entry_t *)e->e_private;
+ assert( mp != NULL );
+
+ for ( cb = mp->mp_cb; cb != NULL; ) {
+ monitor_callback_t *next = cb->mc_next;
+
+ if ( cb->mc_free ) {
+ (void)cb->mc_free( e, &cb->mc_private );
+ }
+ ch_free( cb );
+
+ cb = next;
+ }
+
+ ch_free( mp );
+ e->e_private = NULL;
+ entry_free( e );
+
+ } else {
+ entry_limbo_t **elpp;
+
+ for ( elpp = &mi->mi_entry_limbo;
+ *elpp;
+ elpp = &(*elpp)->el_next )
+ {
+ entry_limbo_t *elp = *elpp;
+
+ if ( elp->el_type == LIMBO_ENTRY
+ && dn_match( ndn, &elp->el_e->e_nname ) )
+ {
+ monitor_callback_t *cb, *next;
+
+ for ( cb = elp->el_cb; cb; cb = next ) {
+ /* FIXME: call callbacks? */
+ next = cb->mc_next;
+ if ( cb->mc_dispose ) {
+ cb->mc_dispose( &cb->mc_private );
+ }
+ ch_free( cb );
+ }
+ assert( elp->el_e != NULL );
+ elp->el_e->e_private = NULL;
+ entry_free( elp->el_e );
+ *elpp = elp->el_next;
+ ch_free( elp );
+ elpp = NULL;
+ break;
+ }
+ }
+
+ if ( elpp != NULL ) {
+ /* not found! where did it go? */
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int
+monitor_back_unregister_entry_parent(
+ struct berval *nrdn,
+ monitor_callback_t *target_cb,
+ struct berval *nbase,
+ int scope,
+ struct berval *filter )
+{
+ monitor_info_t *mi;
+ struct berval ndn = BER_BVNULL;
+
+ if ( be_monitor == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_unregister_entry_parent(base=\"%s\" scope=%s filter=\"%s\"): "
+ "monitor database not configured.\n",
+ BER_BVISNULL( nbase ) ? "" : nbase->bv_val,
+ ldap_pvt_scope2str( scope ),
+ BER_BVISNULL( filter ) ? "" : filter->bv_val );
+
+ return -1;
+ }
+
+ /* entry will be regularly freed, and resources released
+ * according to callbacks */
+ if ( slapd_shutdown ) {
+ return 0;
+ }
+
+ mi = ( monitor_info_t * )be_monitor->be_private;
+
+ assert( mi != NULL );
+
+ if ( ( nrdn == NULL || BER_BVISNULL( nrdn ) )
+ && BER_BVISNULL( filter ) )
+ {
+ /* need a filter */
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_unregister_entry_parent(\"\"): "
+ "need a valid filter\n",
+ 0, 0, 0 );
+ return -1;
+ }
+
+ if ( monitor_subsys_is_opened() ) {
+ Entry *e = NULL;
+ monitor_entry_t *mp = NULL;
+
+ if ( monitor_search2ndn( nbase, scope, filter, &ndn ) ) {
+ /* entry does not exist */
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_unregister_entry_parent(\"\"): "
+ "base=\"%s\" scope=%s filter=\"%s\": "
+ "unable to find entry\n",
+ nbase->bv_val ? nbase->bv_val : "\"\"",
+ ldap_pvt_scope2str( scope ),
+ filter->bv_val );
+ return -1;
+ }
+
+ if ( monitor_cache_remove( mi, &ndn, &e ) != 0 ) {
+ /* entry does not exist */
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_unregister_entry(\"%s\"): "
+ "entry removal failed.\n",
+ ndn.bv_val, 0, 0 );
+ ber_memfree( ndn.bv_val );
+ return -1;
+ }
+ ber_memfree( ndn.bv_val );
+
+ mp = (monitor_entry_t *)e->e_private;
+ assert( mp != NULL );
+
+ if ( target_cb != NULL ) {
+ monitor_callback_t **cbp;
+
+ for ( cbp = &mp->mp_cb; *cbp != NULL; cbp = &(*cbp)->mc_next ) {
+ if ( *cbp == target_cb ) {
+ if ( (*cbp)->mc_free ) {
+ (void)(*cbp)->mc_free( e, &(*cbp)->mc_private );
+ }
+ *cbp = (*cbp)->mc_next;
+ ch_free( target_cb );
+ break;
+ }
+ }
+ }
+
+
+ ch_free( mp );
+ e->e_private = NULL;
+ entry_free( e );
+
+ } else {
+ entry_limbo_t **elpp;
+
+ for ( elpp = &mi->mi_entry_limbo;
+ *elpp;
+ elpp = &(*elpp)->el_next )
+ {
+ entry_limbo_t *elp = *elpp;
+
+ if ( elp->el_type == LIMBO_ENTRY_PARENT
+ && dn_match( nrdn, &elp->el_e->e_nname )
+ && dn_match( nbase, &elp->el_nbase )
+ && scope == elp->el_scope
+ && bvmatch( filter, &elp->el_filter ) )
+ {
+ monitor_callback_t *cb, *next;
+
+ for ( cb = elp->el_cb; cb; cb = next ) {
+ /* FIXME: call callbacks? */
+ next = cb->mc_next;
+ if ( cb->mc_dispose ) {
+ cb->mc_dispose( &cb->mc_private );
+ }
+ ch_free( cb );
+ }
+ assert( elp->el_e != NULL );
+ elp->el_e->e_private = NULL;
+ entry_free( elp->el_e );
+ if ( !BER_BVISNULL( &elp->el_nbase ) ) {
+ ch_free( elp->el_nbase.bv_val );
+ }
+ if ( !BER_BVISNULL( &elp->el_filter ) ) {
+ ch_free( elp->el_filter.bv_val );
+ }
+ *elpp = elp->el_next;
+ ch_free( elp );
+ elpp = NULL;
+ break;
+ }
+ }
+
+ if ( elpp != NULL ) {
+ /* not found! where did it go? */
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int
+monitor_back_unregister_entry_attrs(
+ struct berval *ndn_in,
+ Attribute *target_a,
+ monitor_callback_t *target_cb,
+ struct berval *nbase,
+ int scope,
+ struct berval *filter )
+{
+ monitor_info_t *mi;
+ struct berval ndn = BER_BVNULL;
+ char *fname = ( target_a == NULL ? "callback" : "attrs" );
+
+ if ( be_monitor == NULL ) {
+ char buf[ SLAP_TEXT_BUFLEN ];
+
+ snprintf( buf, sizeof( buf ),
+ "monitor_back_unregister_entry_%s(base=\"%s\" scope=%s filter=\"%s\"): "
+ "monitor database not configured.\n",
+ fname,
+ BER_BVISNULL( nbase ) ? "" : nbase->bv_val,
+ ldap_pvt_scope2str( scope ),
+ BER_BVISNULL( filter ) ? "" : filter->bv_val );
+ Debug( LDAP_DEBUG_ANY, "%s\n", buf, 0, 0 );
+
+ return -1;
+ }
+
+ /* entry will be regularly freed, and resources released
+ * according to callbacks */
+ if ( slapd_shutdown ) {
+ return 0;
+ }
+
+ mi = ( monitor_info_t * )be_monitor->be_private;
+
+ assert( mi != NULL );
+
+ if ( ndn_in != NULL ) {
+ ndn = *ndn_in;
+ }
+
+ if ( target_a == NULL && target_cb == NULL ) {
+ /* nothing to do */
+ return -1;
+ }
+
+ if ( ( ndn_in == NULL || BER_BVISNULL( &ndn ) )
+ && BER_BVISNULL( filter ) )
+ {
+ /* need a filter */
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_unregister_entry_%s(\"\"): "
+ "need a valid filter\n",
+ fname, 0, 0 );
+ return -1;
+ }
+
+ if ( monitor_subsys_is_opened() ) {
+ Entry *e = NULL;
+ monitor_entry_t *mp = NULL;
+ int freeit = 0;
+
+ if ( BER_BVISNULL( &ndn ) ) {
+ if ( monitor_search2ndn( nbase, scope, filter, &ndn ) ) {
+ char buf[ SLAP_TEXT_BUFLEN ];
+
+ snprintf( buf, sizeof( buf ),
+ "monitor_back_unregister_entry_%s(\"\"): "
+ "base=\"%s\" scope=%d filter=\"%s\": "
+ "unable to find entry\n",
+ fname,
+ nbase->bv_val ? nbase->bv_val : "\"\"",
+ scope, filter->bv_val );
+
+ /* entry does not exist */
+ Debug( LDAP_DEBUG_ANY, "%s\n", buf, 0, 0 );
+ return -1;
+ }
+
+ freeit = 1;
+ }
+
+ if ( monitor_cache_get( mi, &ndn, &e ) != 0 ) {
+ /* entry does not exist */
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_unregister_entry(\"%s\"): "
+ "entry removal failed.\n",
+ ndn.bv_val, 0, 0 );
+ return -1;
+ }
+
+ mp = (monitor_entry_t *)e->e_private;
+ assert( mp != NULL );
+
+ if ( target_cb != NULL ) {
+ monitor_callback_t **cbp;
+
+ for ( cbp = &mp->mp_cb; *cbp != NULL; cbp = &(*cbp)->mc_next ) {
+ if ( *cbp == target_cb ) {
+ if ( (*cbp)->mc_free ) {
+ (void)(*cbp)->mc_free( e, &(*cbp)->mc_private );
+ }
+ *cbp = (*cbp)->mc_next;
+ ch_free( target_cb );
+ break;
+ }
+ }
+ }
+
+ if ( target_a != NULL ) {
+ Attribute *a;
+
+ for ( a = target_a; a != NULL; a = a->a_next ) {
+ Modification mod = { 0 };
+ const char *text;
+ char textbuf[ SLAP_TEXT_BUFLEN ];
+
+ mod.sm_op = LDAP_MOD_DELETE;
+ mod.sm_desc = a->a_desc;
+ mod.sm_values = a->a_vals;
+ mod.sm_nvalues = a->a_nvals;
+
+ (void)modify_delete_values( e, &mod, 1,
+ &text, textbuf, sizeof( textbuf ) );
+ }
+ }
+
+ if ( freeit ) {
+ ber_memfree( ndn.bv_val );
+ }
+
+ monitor_cache_release( mi, e );
+
+ } else {
+ entry_limbo_t **elpp;
+
+ for ( elpp = &mi->mi_entry_limbo;
+ *elpp;
+ elpp = &(*elpp)->el_next )
+ {
+ entry_limbo_t *elp = *elpp;
+
+ if ( elp->el_type == LIMBO_ATTRS
+ && dn_match( nbase, &elp->el_nbase )
+ && scope == elp->el_scope
+ && bvmatch( filter, &elp->el_filter ) )
+ {
+ monitor_callback_t *cb, *next;
+
+ for ( cb = elp->el_cb; cb; cb = next ) {
+ /* FIXME: call callbacks? */
+ next = cb->mc_next;
+ if ( cb->mc_dispose ) {
+ cb->mc_dispose( &cb->mc_private );
+ }
+ ch_free( cb );
+ }
+ assert( elp->el_e == NULL );
+ if ( elp->el_a != NULL ) {
+ attrs_free( elp->el_a );
+ }
+ if ( !BER_BVISNULL( &elp->el_nbase ) ) {
+ ch_free( elp->el_nbase.bv_val );
+ }
+ if ( !BER_BVISNULL( &elp->el_filter ) ) {
+ ch_free( elp->el_filter.bv_val );
+ }
+ *elpp = elp->el_next;
+ ch_free( elp );
+ elpp = NULL;
+ break;
+ }
+ }
+
+ if ( elpp != NULL ) {
+ /* not found! where did it go? */
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int
+monitor_back_unregister_entry_callback(
+ struct berval *ndn,
+ monitor_callback_t *cb,
+ struct berval *nbase,
+ int scope,
+ struct berval *filter )
+{
+ /* TODO: lookup entry (by ndn, if not NULL, and/or by callback);
+ * unregister the callback; if a is not null, unregister the
+ * given attrs. In any case, call cb->cb_free */
+ return monitor_back_unregister_entry_attrs( ndn,
+ NULL, cb, nbase, scope, filter );
+}
+
+monitor_subsys_t *
+monitor_back_get_subsys( const char *name )
+{
+ if ( monitor_subsys != NULL ) {
+ int i;
+
+ for ( i = 0; monitor_subsys[ i ] != NULL; i++ ) {
+ if ( strcasecmp( monitor_subsys[ i ]->mss_name, name ) == 0 ) {
+ return monitor_subsys[ i ];
+ }
+ }
+ }
+
+ return NULL;
+}
+
+monitor_subsys_t *
+monitor_back_get_subsys_by_dn(
+ struct berval *ndn,
+ int sub )
+{
+ if ( monitor_subsys != NULL ) {
+ int i;
+
+ if ( sub ) {
+ for ( i = 0; monitor_subsys[ i ] != NULL; i++ ) {
+ if ( dnIsSuffix( ndn, &monitor_subsys[ i ]->mss_ndn ) ) {
+ return monitor_subsys[ i ];
+ }
+ }
+
+ } else {
+ for ( i = 0; monitor_subsys[ i ] != NULL; i++ ) {
+ if ( dn_match( ndn, &monitor_subsys[ i ]->mss_ndn ) ) {
+ return monitor_subsys[ i ];
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+int
+monitor_back_initialize(
+ BackendInfo *bi )
+{
+ static char *controls[] = {
+ LDAP_CONTROL_MANAGEDSAIT,
+ NULL
+ };
+
+ static ConfigTable monitorcfg[] = {
+ { NULL, NULL, 0, 0, 0, ARG_IGNORED,
+ NULL, NULL, NULL, NULL }
+ };
+
+ static ConfigOCs monitorocs[] = {
+ { "( OLcfgDbOc:4.1 "
+ "NAME 'olcMonitorConfig' "
+ "DESC 'Monitor backend configuration' "
+ "SUP olcDatabaseConfig "
+ ")",
+ Cft_Database, monitorcfg },
+ { NULL, 0, NULL }
+ };
+
+ struct m_s {
+ char *schema;
+ slap_mask_t flags;
+ int offset;
+ } moc[] = {
+ { "( 1.3.6.1.4.1.4203.666.3.16.1 "
+ "NAME 'monitor' "
+ "DESC 'OpenLDAP system monitoring' "
+ "SUP top STRUCTURAL "
+ "MUST cn "
+ "MAY ( "
+ "description "
+ "$ seeAlso "
+ "$ labeledURI "
+ "$ monitoredInfo "
+ "$ managedInfo "
+ "$ monitorOverlay "
+ ") )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
+ offsetof(monitor_info_t, mi_oc_monitor) },
+ { "( 1.3.6.1.4.1.4203.666.3.16.2 "
+ "NAME 'monitorServer' "
+ "DESC 'Server monitoring root entry' "
+ "SUP monitor STRUCTURAL )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
+ offsetof(monitor_info_t, mi_oc_monitorServer) },
+ { "( 1.3.6.1.4.1.4203.666.3.16.3 "
+ "NAME 'monitorContainer' "
+ "DESC 'monitor container class' "
+ "SUP monitor STRUCTURAL )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
+ offsetof(monitor_info_t, mi_oc_monitorContainer) },
+ { "( 1.3.6.1.4.1.4203.666.3.16.4 "
+ "NAME 'monitorCounterObject' "
+ "DESC 'monitor counter class' "
+ "SUP monitor STRUCTURAL )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
+ offsetof(monitor_info_t, mi_oc_monitorCounterObject) },
+ { "( 1.3.6.1.4.1.4203.666.3.16.5 "
+ "NAME 'monitorOperation' "
+ "DESC 'monitor operation class' "
+ "SUP monitor STRUCTURAL )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
+ offsetof(monitor_info_t, mi_oc_monitorOperation) },
+ { "( 1.3.6.1.4.1.4203.666.3.16.6 "
+ "NAME 'monitorConnection' "
+ "DESC 'monitor connection class' "
+ "SUP monitor STRUCTURAL )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
+ offsetof(monitor_info_t, mi_oc_monitorConnection) },
+ { "( 1.3.6.1.4.1.4203.666.3.16.7 "
+ "NAME 'managedObject' "
+ "DESC 'monitor managed entity class' "
+ "SUP monitor STRUCTURAL )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
+ offsetof(monitor_info_t, mi_oc_managedObject) },
+ { "( 1.3.6.1.4.1.4203.666.3.16.8 "
+ "NAME 'monitoredObject' "
+ "DESC 'monitor monitored entity class' "
+ "SUP monitor STRUCTURAL )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
+ offsetof(monitor_info_t, mi_oc_monitoredObject) },
+ { NULL, 0, -1 }
+ }, mat[] = {
+ { "( 1.3.6.1.4.1.4203.666.1.55.1 "
+ "NAME 'monitoredInfo' "
+ "DESC 'monitored info' "
+ /* "SUP name " */
+ "EQUALITY caseIgnoreMatch "
+ "SUBSTR caseIgnoreSubstringsMatch "
+ "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} "
+ "NO-USER-MODIFICATION "
+ "USAGE dSAOperation )", SLAP_AT_HIDE,
+ offsetof(monitor_info_t, mi_ad_monitoredInfo) },
+ { "( 1.3.6.1.4.1.4203.666.1.55.2 "
+ "NAME 'managedInfo' "
+ "DESC 'monitor managed info' "
+ "SUP name )", SLAP_AT_HIDE,
+ offsetof(monitor_info_t, mi_ad_managedInfo) },
+ { "( 1.3.6.1.4.1.4203.666.1.55.3 "
+ "NAME 'monitorCounter' "
+ "DESC 'monitor counter' "
+ "EQUALITY integerMatch "
+ "ORDERING integerOrderingMatch "
+ "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
+ "NO-USER-MODIFICATION "
+ "USAGE dSAOperation )", SLAP_AT_HIDE,
+ offsetof(monitor_info_t, mi_ad_monitorCounter) },
+ { "( 1.3.6.1.4.1.4203.666.1.55.4 "
+ "NAME 'monitorOpCompleted' "
+ "DESC 'monitor completed operations' "
+ "SUP monitorCounter "
+ "NO-USER-MODIFICATION "
+ "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
+ offsetof(monitor_info_t, mi_ad_monitorOpCompleted) },
+ { "( 1.3.6.1.4.1.4203.666.1.55.5 "
+ "NAME 'monitorOpInitiated' "
+ "DESC 'monitor initiated operations' "
+ "SUP monitorCounter "
+ "NO-USER-MODIFICATION "
+ "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
+ offsetof(monitor_info_t, mi_ad_monitorOpInitiated) },
+ { "( 1.3.6.1.4.1.4203.666.1.55.6 "
+ "NAME 'monitorConnectionNumber' "
+ "DESC 'monitor connection number' "
+ "SUP monitorCounter "
+ "NO-USER-MODIFICATION "
+ "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
+ offsetof(monitor_info_t, mi_ad_monitorConnectionNumber) },
+ { "( 1.3.6.1.4.1.4203.666.1.55.7 "
+ "NAME 'monitorConnectionAuthzDN' "
+ "DESC 'monitor connection authorization DN' "
+ /* "SUP distinguishedName " */
+ "EQUALITY distinguishedNameMatch "
+ "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 "
+ "NO-USER-MODIFICATION "
+ "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
+ offsetof(monitor_info_t, mi_ad_monitorConnectionAuthzDN) },
+ { "( 1.3.6.1.4.1.4203.666.1.55.8 "
+ "NAME 'monitorConnectionLocalAddress' "
+ "DESC 'monitor connection local address' "
+ "SUP monitoredInfo "
+ "NO-USER-MODIFICATION "
+ "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
+ offsetof(monitor_info_t, mi_ad_monitorConnectionLocalAddress) },
+ { "( 1.3.6.1.4.1.4203.666.1.55.9 "
+ "NAME 'monitorConnectionPeerAddress' "
+ "DESC 'monitor connection peer address' "
+ "SUP monitoredInfo "
+ "NO-USER-MODIFICATION "
+ "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
+ offsetof(monitor_info_t, mi_ad_monitorConnectionPeerAddress) },
+ { "( 1.3.6.1.4.1.4203.666.1.55.10 "
+ "NAME 'monitorTimestamp' "
+ "DESC 'monitor timestamp' "
+ "EQUALITY generalizedTimeMatch "
+ "ORDERING generalizedTimeOrderingMatch "
+ "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
+ "SINGLE-VALUE "
+ "NO-USER-MODIFICATION "
+ "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
+ offsetof(monitor_info_t, mi_ad_monitorTimestamp) },
+ { "( 1.3.6.1.4.1.4203.666.1.55.11 "
+ "NAME 'monitorOverlay' "
+ "DESC 'name of overlays defined for a given database' "
+ "SUP monitoredInfo "
+ "NO-USER-MODIFICATION "
+ "USAGE dSAOperation )", SLAP_AT_HIDE,
+ offsetof(monitor_info_t, mi_ad_monitorOverlay) },
+ { "( 1.3.6.1.4.1.4203.666.1.55.12 "
+ "NAME 'readOnly' "
+ "DESC 'read/write status of a given database' "
+ "EQUALITY booleanMatch "
+ "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 "
+ "SINGLE-VALUE "
+ "USAGE dSAOperation )", SLAP_AT_HIDE,
+ offsetof(monitor_info_t, mi_ad_readOnly) },
+ { "( 1.3.6.1.4.1.4203.666.1.55.13 "
+ "NAME 'restrictedOperation' "
+ "DESC 'name of restricted operation for a given database' "
+ "SUP managedInfo )", SLAP_AT_HIDE,
+ offsetof(monitor_info_t, mi_ad_restrictedOperation ) },
+ { "( 1.3.6.1.4.1.4203.666.1.55.14 "
+ "NAME 'monitorConnectionProtocol' "
+ "DESC 'monitor connection protocol' "
+ "SUP monitoredInfo "
+ "NO-USER-MODIFICATION "
+ "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
+ offsetof(monitor_info_t, mi_ad_monitorConnectionProtocol) },
+ { "( 1.3.6.1.4.1.4203.666.1.55.15 "
+ "NAME 'monitorConnectionOpsReceived' "
+ "DESC 'monitor number of operations received by the connection' "
+ "SUP monitorCounter "
+ "NO-USER-MODIFICATION "
+ "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
+ offsetof(monitor_info_t, mi_ad_monitorConnectionOpsReceived) },
+ { "( 1.3.6.1.4.1.4203.666.1.55.16 "
+ "NAME 'monitorConnectionOpsExecuting' "
+ "DESC 'monitor number of operations in execution within the connection' "
+ "SUP monitorCounter "
+ "NO-USER-MODIFICATION "
+ "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
+ offsetof(monitor_info_t, mi_ad_monitorConnectionOpsExecuting) },
+ { "( 1.3.6.1.4.1.4203.666.1.55.17 "
+ "NAME 'monitorConnectionOpsPending' "
+ "DESC 'monitor number of pending operations within the connection' "
+ "SUP monitorCounter "
+ "NO-USER-MODIFICATION "
+ "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
+ offsetof(monitor_info_t, mi_ad_monitorConnectionOpsPending) },
+ { "( 1.3.6.1.4.1.4203.666.1.55.18 "
+ "NAME 'monitorConnectionOpsCompleted' "
+ "DESC 'monitor number of operations completed within the connection' "
+ "SUP monitorCounter "
+ "NO-USER-MODIFICATION "
+ "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
+ offsetof(monitor_info_t, mi_ad_monitorConnectionOpsCompleted) },
+ { "( 1.3.6.1.4.1.4203.666.1.55.19 "
+ "NAME 'monitorConnectionGet' "
+ "DESC 'number of times connection_get() was called so far' "
+ "SUP monitorCounter "
+ "NO-USER-MODIFICATION "
+ "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
+ offsetof(monitor_info_t, mi_ad_monitorConnectionGet) },
+ { "( 1.3.6.1.4.1.4203.666.1.55.20 "
+ "NAME 'monitorConnectionRead' "
+ "DESC 'number of times connection_read() was called so far' "
+ "SUP monitorCounter "
+ "NO-USER-MODIFICATION "
+ "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
+ offsetof(monitor_info_t, mi_ad_monitorConnectionRead) },
+ { "( 1.3.6.1.4.1.4203.666.1.55.21 "
+ "NAME 'monitorConnectionWrite' "
+ "DESC 'number of times connection_write() was called so far' "
+ "SUP monitorCounter "
+ "NO-USER-MODIFICATION "
+ "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
+ offsetof(monitor_info_t, mi_ad_monitorConnectionWrite) },
+ { "( 1.3.6.1.4.1.4203.666.1.55.22 "
+ "NAME 'monitorConnectionMask' "
+ "DESC 'monitor connection mask' "
+ "SUP monitoredInfo "
+ "NO-USER-MODIFICATION "
+ "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
+ offsetof(monitor_info_t, mi_ad_monitorConnectionMask) },
+ { "( 1.3.6.1.4.1.4203.666.1.55.23 "
+ "NAME 'monitorConnectionListener' "
+ "DESC 'monitor connection listener' "
+ "SUP monitoredInfo "
+ "NO-USER-MODIFICATION "
+ "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
+ offsetof(monitor_info_t, mi_ad_monitorConnectionListener) },
+ { "( 1.3.6.1.4.1.4203.666.1.55.24 "
+ "NAME 'monitorConnectionPeerDomain' "
+ "DESC 'monitor connection peer domain' "
+ "SUP monitoredInfo "
+ "NO-USER-MODIFICATION "
+ "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
+ offsetof(monitor_info_t, mi_ad_monitorConnectionPeerDomain) },
+ { "( 1.3.6.1.4.1.4203.666.1.55.25 "
+ "NAME 'monitorConnectionStartTime' "
+ "DESC 'monitor connection start time' "
+ "SUP monitorTimestamp "
+ "SINGLE-VALUE "
+ "NO-USER-MODIFICATION "
+ "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
+ offsetof(monitor_info_t, mi_ad_monitorConnectionStartTime) },
+ { "( 1.3.6.1.4.1.4203.666.1.55.26 "
+ "NAME 'monitorConnectionActivityTime' "
+ "DESC 'monitor connection activity time' "
+ "SUP monitorTimestamp "
+ "SINGLE-VALUE "
+ "NO-USER-MODIFICATION "
+ "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
+ offsetof(monitor_info_t, mi_ad_monitorConnectionActivityTime) },
+ { "( 1.3.6.1.4.1.4203.666.1.55.27 "
+ "NAME 'monitorIsShadow' "
+ "DESC 'TRUE if the database is shadow' "
+ "EQUALITY booleanMatch "
+ "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 "
+ "SINGLE-VALUE "
+ "USAGE dSAOperation )", SLAP_AT_HIDE,
+ offsetof(monitor_info_t, mi_ad_monitorIsShadow) },
+ { "( 1.3.6.1.4.1.4203.666.1.55.28 "
+ "NAME 'monitorUpdateRef' "
+ "DESC 'update referral for shadow databases' "
+ "SUP monitoredInfo "
+ "SINGLE-VALUE "
+ "USAGE dSAOperation )", SLAP_AT_HIDE,
+ offsetof(monitor_info_t, mi_ad_monitorUpdateRef) },
+ { "( 1.3.6.1.4.1.4203.666.1.55.29 "
+ "NAME 'monitorRuntimeConfig' "
+ "DESC 'TRUE if component allows runtime configuration' "
+ "EQUALITY booleanMatch "
+ "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 "
+ "SINGLE-VALUE "
+ "USAGE dSAOperation )", SLAP_AT_HIDE,
+ offsetof(monitor_info_t, mi_ad_monitorRuntimeConfig) },
+ { "( 1.3.6.1.4.1.4203.666.1.55.30 "
+ "NAME 'monitorSuperiorDN' "
+ "DESC 'monitor superior DN' "
+ /* "SUP distinguishedName " */
+ "EQUALITY distinguishedNameMatch "
+ "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 "
+ "NO-USER-MODIFICATION "
+ "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
+ offsetof(monitor_info_t, mi_ad_monitorSuperiorDN) },
+ { NULL, 0, -1 }
+ };
+
+ static struct {
+ char *name;
+ char *oid;
+ } s_oid[] = {
+ { "olmAttributes", "1.3.6.1.4.1.4203.666.1.55" },
+ { "olmSubSystemAttributes", "olmAttributes:0" },
+ { "olmGenericAttributes", "olmSubSystemAttributes:0" },
+ { "olmDatabaseAttributes", "olmSubSystemAttributes:1" },
+
+ /* for example, back-bdb specific attrs
+ * are in "olmDatabaseAttributes:1"
+ *
+ * NOTE: developers, please record here OID assignments
+ * for other modules */
+
+ { "olmObjectClasses", "1.3.6.1.4.1.4203.666.3.16" },
+ { "olmSubSystemObjectClasses", "olmObjectClasses:0" },
+ { "olmGenericObjectClasses", "olmSubSystemObjectClasses:0" },
+ { "olmDatabaseObjectClasses", "olmSubSystemObjectClasses:1" },
+
+ /* for example, back-bdb specific objectClasses
+ * are in "olmDatabaseObjectClasses:1"
+ *
+ * NOTE: developers, please record here OID assignments
+ * for other modules */
+
+ { NULL }
+ };
+
+ int i, rc;
+ monitor_info_t *mi = &monitor_info;
+ ConfigArgs c;
+ char *argv[ 3 ];
+
+ argv[ 0 ] = "monitor";
+ c.argv = argv;
+ c.argc = 3;
+ c.fname = argv[0];
+
+ for ( i = 0; s_oid[ i ].name; i++ ) {
+ argv[ 1 ] = s_oid[ i ].name;
+ argv[ 2 ] = s_oid[ i ].oid;
+
+ if ( parse_oidm( &c, 0, NULL ) != 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_initialize: unable to add "
+ "objectIdentifier \"%s=%s\"\n",
+ s_oid[ i ].name, s_oid[ i ].oid, 0 );
+ return 1;
+ }
+ }
+
+ /* schema integration */
+ for ( i = 0; mat[ i ].schema; i++ ) {
+ int code;
+ AttributeDescription **ad =
+ ((AttributeDescription **)&(((char *)mi)[ mat[ i ].offset ]));
+
+ *ad = NULL;
+ code = register_at( mat[ i ].schema, ad, 0 );
+
+ if ( code ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_db_init: register_at failed\n", 0, 0, 0 );
+ return -1;
+ }
+ (*ad)->ad_type->sat_flags |= mat[ i ].flags;
+ }
+
+ for ( i = 0; moc[ i ].schema; i++ ) {
+ int code;
+ ObjectClass **Oc =
+ ((ObjectClass **)&(((char *)mi)[ moc[ i ].offset ]));
+
+ code = register_oc( moc[ i ].schema, Oc, 0 );
+ if ( code ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_back_db_init: register_oc failed\n", 0, 0, 0 );
+ return -1;
+ }
+ (*Oc)->soc_flags |= moc[ i ].flags;
+ }
+
+ bi->bi_controls = controls;
+
+ bi->bi_init = 0;
+ bi->bi_open = 0;
+ bi->bi_config = monitor_back_config;
+ bi->bi_close = 0;
+ bi->bi_destroy = 0;
+
+ bi->bi_db_init = monitor_back_db_init;
+#if 0
+ bi->bi_db_config = monitor_back_db_config;
+#endif
+ bi->bi_db_open = monitor_back_db_open;
+ bi->bi_db_close = 0;
+ bi->bi_db_destroy = monitor_back_db_destroy;
+
+ bi->bi_op_bind = monitor_back_bind;
+ bi->bi_op_unbind = 0;
+ bi->bi_op_search = monitor_back_search;
+ bi->bi_op_compare = monitor_back_compare;
+ bi->bi_op_modify = monitor_back_modify;
+ bi->bi_op_modrdn = 0;
+ bi->bi_op_add = 0;
+ bi->bi_op_delete = 0;
+ bi->bi_op_abandon = 0;
+
+ bi->bi_extended = 0;
+
+ bi->bi_entry_release_rw = monitor_back_release;
+ bi->bi_chk_referrals = 0;
+ bi->bi_operational = monitor_back_operational;
+
+ /*
+ * hooks for slap tools
+ */
+ bi->bi_tool_entry_open = 0;
+ bi->bi_tool_entry_close = 0;
+ bi->bi_tool_entry_first = 0;
+ bi->bi_tool_entry_first_x = 0;
+ bi->bi_tool_entry_next = 0;
+ bi->bi_tool_entry_get = 0;
+ bi->bi_tool_entry_put = 0;
+ bi->bi_tool_entry_reindex = 0;
+ bi->bi_tool_sync = 0;
+ bi->bi_tool_dn2id_get = 0;
+ bi->bi_tool_entry_modify = 0;
+
+ bi->bi_connection_init = 0;
+ bi->bi_connection_destroy = 0;
+
+ bi->bi_extra = (void *)&monitor_extra;
+
+ /*
+ * configuration objectClasses (fake)
+ */
+ bi->bi_cf_ocs = monitorocs;
+
+ rc = config_register_schema( monitorcfg, monitorocs );
+ if ( rc ) {
+ return rc;
+ }
+
+ return 0;
+}
+
+int
+monitor_back_db_init(
+ BackendDB *be,
+ ConfigReply *c)
+{
+ int rc;
+ struct berval dn = BER_BVC( SLAPD_MONITOR_DN ),
+ pdn,
+ ndn;
+ BackendDB *be2;
+
+ monitor_subsys_t *ms;
+
+ /*
+ * database monitor can be defined once only
+ */
+ if ( be_monitor != NULL ) {
+ if (c) {
+ snprintf(c->msg, sizeof(c->msg),"only one monitor database allowed");
+ }
+ return( -1 );
+ }
+ be_monitor = be;
+
+ /*
+ * register subsys
+ */
+ for ( ms = known_monitor_subsys; ms->mss_name != NULL; ms++ ) {
+ if ( monitor_back_register_subsys( ms ) ) {
+ return -1;
+ }
+ }
+
+ /* indicate system schema supported */
+ SLAP_BFLAGS(be) |= SLAP_BFLAG_MONITOR;
+
+ rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn, NULL );
+ if( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_ANY,
+ "unable to normalize/pretty monitor DN \"%s\" (%d)\n",
+ dn.bv_val, rc, 0 );
+ return -1;
+ }
+
+ ber_bvarray_add( &be->be_suffix, &pdn );
+ ber_bvarray_add( &be->be_nsuffix, &ndn );
+
+ /* NOTE: only one monitor database is allowed,
+ * so we use static storage */
+ ldap_pvt_thread_mutex_init( &monitor_info.mi_cache_mutex );
+
+ be->be_private = &monitor_info;
+
+ be2 = select_backend( &ndn, 0 );
+ if ( be2 != be ) {
+ char *type = be2->bd_info->bi_type;
+
+ if ( overlay_is_over( be2 ) ) {
+ slap_overinfo *oi = (slap_overinfo *)be2->bd_info->bi_private;
+ type = oi->oi_orig->bi_type;
+ }
+
+ if (c) {
+ snprintf(c->msg, sizeof(c->msg),
+ "\"monitor\" database serving namingContext \"%s\" "
+ "is hidden by \"%s\" database serving namingContext \"%s\".\n",
+ pdn.bv_val, type, be2->be_nsuffix[ 0 ].bv_val );
+ }
+ return -1;
+ }
+
+ return 0;
+}
+
+static void
+monitor_back_destroy_limbo_entry(
+ entry_limbo_t *el,
+ int dispose )
+{
+ if ( el->el_e ) {
+ entry_free( el->el_e );
+ }
+ if ( el->el_a ) {
+ attrs_free( el->el_a );
+ }
+ if ( !BER_BVISNULL( &el->el_nbase ) ) {
+ ber_memfree( el->el_nbase.bv_val );
+ }
+ if ( !BER_BVISNULL( &el->el_filter ) ) {
+ ber_memfree( el->el_filter.bv_val );
+ }
+
+ /* NOTE: callbacks are not copied; so only free them
+ * if disposing of */
+ if ( el->el_cb && dispose != 0 ) {
+ monitor_callback_t *next;
+
+ for ( ; el->el_cb; el->el_cb = next ) {
+ next = el->el_cb->mc_next;
+ if ( el->el_cb->mc_dispose ) {
+ el->el_cb->mc_dispose( &el->el_cb->mc_private );
+ }
+ ch_free( el->el_cb );
+ }
+ }
+
+ ch_free( el );
+}
+
+int
+monitor_back_db_open(
+ BackendDB *be,
+ ConfigReply *cr)
+{
+ monitor_info_t *mi = (monitor_info_t *)be->be_private;
+ struct monitor_subsys_t **ms;
+ Entry *e, **ep, *root;
+ monitor_entry_t *mp;
+ int i;
+ struct berval bv, rdn = BER_BVC(SLAPD_MONITOR_DN);
+ struct tm tms;
+ static char tmbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
+ struct berval desc[] = {
+ BER_BVC("This subtree contains monitoring/managing objects."),
+ BER_BVC("This object contains information about this server."),
+ BER_BVC("Most of the information is held in operational"
+ " attributes, which must be explicitly requested."),
+ BER_BVNULL };
+
+ int retcode = 0;
+
+ assert( be_monitor != NULL );
+ if ( be != be_monitor ) {
+ be_monitor = be;
+ }
+
+ /*
+ * Start
+ */
+ ldap_pvt_gmtime( &starttime, &tms );
+ lutil_gentime( tmbuf, sizeof(tmbuf), &tms );
+
+ mi->mi_startTime.bv_val = tmbuf;
+ mi->mi_startTime.bv_len = strlen( tmbuf );
+
+ if ( BER_BVISEMPTY( &be->be_rootdn ) ) {
+ BER_BVSTR( &mi->mi_creatorsName, SLAPD_ANONYMOUS );
+ BER_BVSTR( &mi->mi_ncreatorsName, SLAPD_ANONYMOUS );
+ } else {
+ mi->mi_creatorsName = be->be_rootdn;
+ mi->mi_ncreatorsName = be->be_rootndn;
+ }
+
+ /*
+ * creates the "cn=Monitor" entry
+ */
+ e = monitor_entry_stub( NULL, NULL, &rdn, mi->mi_oc_monitorServer,
+ NULL, NULL );
+
+ if ( e == NULL) {
+ Debug( LDAP_DEBUG_ANY,
+ "unable to create \"%s\" entry\n",
+ SLAPD_MONITOR_DN, 0, 0 );
+ return( -1 );
+ }
+
+ attr_merge_normalize( e, slap_schema.si_ad_description, desc, NULL );
+
+ bv.bv_val = strchr( (char *) Versionstr, '$' );
+ if ( bv.bv_val != NULL ) {
+ char *end;
+
+ bv.bv_val++;
+ for ( ; bv.bv_val[ 0 ] == ' '; bv.bv_val++ )
+ ;
+
+ end = strchr( bv.bv_val, '$' );
+ if ( end != NULL ) {
+ end--;
+
+ for ( ; end > bv.bv_val && end[ 0 ] == ' '; end-- )
+ ;
+
+ end++;
+
+ bv.bv_len = end - bv.bv_val;
+
+ } else {
+ bv.bv_len = strlen( bv.bv_val );
+ }
+
+ if ( attr_merge_normalize_one( e, mi->mi_ad_monitoredInfo,
+ &bv, NULL ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "unable to add monitoredInfo to \"%s\" entry\n",
+ SLAPD_MONITOR_DN, 0, 0 );
+ return( -1 );
+ }
+ }
+
+ mp = monitor_entrypriv_create();
+ if ( mp == NULL ) {
+ return -1;
+ }
+ e->e_private = ( void * )mp;
+ ep = &mp->mp_children;
+
+ if ( monitor_cache_add( mi, e ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "unable to add entry \"%s\" to cache\n",
+ SLAPD_MONITOR_DN, 0, 0 );
+ return -1;
+ }
+ root = e;
+
+ /*
+ * Create all the subsystem specific entries
+ */
+ for ( i = 0; monitor_subsys[ i ] != NULL; i++ ) {
+ int len = strlen( monitor_subsys[ i ]->mss_name );
+ struct berval dn;
+ int rc;
+
+ dn.bv_len = len + sizeof( "cn=" ) - 1;
+ dn.bv_val = ch_calloc( sizeof( char ), dn.bv_len + 1 );
+ strcpy( dn.bv_val, "cn=" );
+ strcat( dn.bv_val, monitor_subsys[ i ]->mss_name );
+ rc = dnPretty( NULL, &dn, &monitor_subsys[ i ]->mss_rdn, NULL );
+ free( dn.bv_val );
+ if ( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor RDN \"%s\" is invalid\n",
+ dn.bv_val, 0, 0 );
+ return( -1 );
+ }
+
+ e = monitor_entry_stub( &root->e_name, &root->e_nname,
+ &monitor_subsys[ i ]->mss_rdn, mi->mi_oc_monitorContainer,
+ NULL, NULL );
+
+ if ( e == NULL) {
+ Debug( LDAP_DEBUG_ANY,
+ "unable to create \"%s\" entry\n",
+ monitor_subsys[ i ]->mss_dn.bv_val, 0, 0 );
+ return( -1 );
+ }
+ monitor_subsys[i]->mss_dn = e->e_name;
+ monitor_subsys[i]->mss_ndn = e->e_nname;
+
+ if ( !BER_BVISNULL( &monitor_subsys[ i ]->mss_desc[ 0 ] ) ) {
+ attr_merge_normalize( e, slap_schema.si_ad_description,
+ monitor_subsys[ i ]->mss_desc, NULL );
+ }
+
+ mp = monitor_entrypriv_create();
+ if ( mp == NULL ) {
+ return -1;
+ }
+ e->e_private = ( void * )mp;
+ mp->mp_info = monitor_subsys[ i ];
+ mp->mp_flags = monitor_subsys[ i ]->mss_flags;
+
+ if ( monitor_cache_add( mi, e ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "unable to add entry \"%s\" to cache\n",
+ monitor_subsys[ i ]->mss_dn.bv_val, 0, 0 );
+ return -1;
+ }
+
+ *ep = e;
+ ep = &mp->mp_next;
+ }
+
+ assert( be != NULL );
+
+ be->be_private = mi;
+
+ /*
+ * opens the monitor backend subsystems
+ */
+ for ( ms = monitor_subsys; ms[ 0 ] != NULL; ms++ ) {
+ if ( ms[ 0 ]->mss_open && ms[ 0 ]->mss_open( be, ms[ 0 ] ) ) {
+ return( -1 );
+ }
+ ms[ 0 ]->mss_flags |= MONITOR_F_OPENED;
+ }
+
+ monitor_subsys_opened = 1;
+
+ if ( mi->mi_entry_limbo ) {
+ entry_limbo_t *el = mi->mi_entry_limbo;
+
+ for ( ; el; ) {
+ entry_limbo_t *tmp;
+ int rc;
+
+ switch ( el->el_type ) {
+ case LIMBO_ENTRY:
+ rc = monitor_back_register_entry(
+ el->el_e,
+ el->el_cb,
+ el->el_mss,
+ el->el_flags );
+ break;
+
+ case LIMBO_ENTRY_PARENT:
+ rc = monitor_back_register_entry_parent(
+ el->el_e,
+ el->el_cb,
+ el->el_mss,
+ el->el_flags,
+ &el->el_nbase,
+ el->el_scope,
+ &el->el_filter );
+ break;
+
+
+ case LIMBO_ATTRS:
+ rc = monitor_back_register_entry_attrs(
+ el->el_ndn,
+ el->el_a,
+ el->el_cb,
+ &el->el_nbase,
+ el->el_scope,
+ &el->el_filter );
+ break;
+
+ case LIMBO_CB:
+ rc = monitor_back_register_entry_callback(
+ el->el_ndn,
+ el->el_cb,
+ &el->el_nbase,
+ el->el_scope,
+ &el->el_filter );
+ break;
+
+ case LIMBO_BACKEND:
+ rc = monitor_back_register_backend( el->el_bi );
+ break;
+
+ case LIMBO_DATABASE:
+ rc = monitor_back_register_database( el->el_be, el->el_ndn );
+ break;
+
+ case LIMBO_OVERLAY_INFO:
+ rc = monitor_back_register_overlay_info( el->el_on );
+ break;
+
+ case LIMBO_OVERLAY:
+ rc = monitor_back_register_overlay( el->el_be, el->el_on, el->el_ndn );
+ break;
+
+ case LIMBO_SUBSYS:
+ rc = monitor_back_register_subsys( el->el_mss );
+ break;
+
+ default:
+ assert( 0 );
+ }
+
+ tmp = el;
+ el = el->el_next;
+ monitor_back_destroy_limbo_entry( tmp, rc );
+
+ if ( rc != 0 ) {
+ /* try all, but report error at end */
+ retcode = 1;
+ }
+ }
+
+ mi->mi_entry_limbo = NULL;
+ }
+
+ return retcode;
+}
+
+int
+monitor_back_config(
+ BackendInfo *bi,
+ const char *fname,
+ int lineno,
+ int argc,
+ char **argv )
+{
+ /*
+ * eventually, will hold backend specific configuration parameters
+ */
+ return SLAP_CONF_UNKNOWN;
+}
+
+#if 0
+int
+monitor_back_db_config(
+ Backend *be,
+ const char *fname,
+ int lineno,
+ int argc,
+ char **argv )
+{
+ monitor_info_t *mi = ( monitor_info_t * )be->be_private;
+
+ /*
+ * eventually, will hold database specific configuration parameters
+ */
+ return SLAP_CONF_UNKNOWN;
+}
+#endif
+
+int
+monitor_back_db_destroy(
+ BackendDB *be,
+ ConfigReply *cr)
+{
+ monitor_info_t *mi = ( monitor_info_t * )be->be_private;
+
+ if ( mi == NULL ) {
+ return -1;
+ }
+
+ /*
+ * FIXME: destroys all the data
+ */
+ /* NOTE: mi points to static storage; don't free it */
+
+ (void)monitor_cache_destroy( mi );
+
+ if ( monitor_subsys ) {
+ int i;
+
+ for ( i = 0; monitor_subsys[ i ] != NULL; i++ ) {
+ if ( monitor_subsys[ i ]->mss_destroy ) {
+ monitor_subsys[ i ]->mss_destroy( be, monitor_subsys[ i ] );
+ }
+
+ if ( !BER_BVISNULL( &monitor_subsys[ i ]->mss_rdn ) ) {
+ ch_free( monitor_subsys[ i ]->mss_rdn.bv_val );
+ }
+ }
+
+ ch_free( monitor_subsys );
+ }
+
+ if ( mi->mi_entry_limbo ) {
+ entry_limbo_t *el = mi->mi_entry_limbo;
+
+ for ( ; el; ) {
+ entry_limbo_t *tmp = el;
+ el = el->el_next;
+ monitor_back_destroy_limbo_entry( tmp, 1 );
+ }
+ }
+
+ ldap_pvt_thread_mutex_destroy( &monitor_info.mi_cache_mutex );
+
+ be->be_private = NULL;
+
+ return 0;
+}
+
+#if SLAPD_MONITOR == SLAPD_MOD_DYNAMIC
+
+/* conditionally define the init_module() function */
+SLAP_BACKEND_INIT_MODULE( monitor )
+
+#endif /* SLAPD_MONITOR == SLAPD_MOD_DYNAMIC */
+
diff --git a/servers/slapd/back-monitor/listener.c b/servers/slapd/back-monitor/listener.c
new file mode 100644
index 0000000..8f7c3fa
--- /dev/null
+++ b/servers/slapd/back-monitor/listener.c
@@ -0,0 +1,138 @@
+/* listener.c - deals with listener subsystem */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2001-2018 The OpenLDAP Foundation.
+ * Portions Copyright 2001-2003 Pierangelo Masarati.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Pierangelo Masarati for inclusion
+ * in OpenLDAP Software.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+
+#include "slap.h"
+#include "back-monitor.h"
+
+int
+monitor_subsys_listener_init(
+ BackendDB *be,
+ monitor_subsys_t *ms
+)
+{
+ monitor_info_t *mi;
+ Entry *e_listener, **ep;
+ int i;
+ monitor_entry_t *mp;
+ Listener **l;
+
+ assert( be != NULL );
+
+ if ( ( l = slapd_get_listeners() ) == NULL ) {
+ if ( slapMode & SLAP_TOOL_MODE ) {
+ return 0;
+ }
+
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_listener_init: "
+ "unable to get listeners\n", 0, 0, 0 );
+ return( -1 );
+ }
+
+ mi = ( monitor_info_t * )be->be_private;
+
+ if ( monitor_cache_get( mi, &ms->mss_ndn, &e_listener ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_listener_init: "
+ "unable to get entry \"%s\"\n",
+ ms->mss_ndn.bv_val, 0, 0 );
+ return( -1 );
+ }
+
+ mp = ( monitor_entry_t * )e_listener->e_private;
+ mp->mp_children = NULL;
+ ep = &mp->mp_children;
+
+ for ( i = 0; l[ i ]; i++ ) {
+ char buf[ BACKMONITOR_BUFSIZE ];
+ Entry *e;
+ struct berval bv;
+
+ bv.bv_len = snprintf( buf, sizeof( buf ),
+ "cn=Listener %d", i );
+ bv.bv_val = buf;
+ e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, &bv,
+ mi->mi_oc_monitoredObject, NULL, NULL );
+
+ if ( e == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_listener_init: "
+ "unable to create entry \"cn=Listener %d,%s\"\n",
+ i, ms->mss_ndn.bv_val, 0 );
+ return( -1 );
+ }
+
+ attr_merge_normalize_one( e, mi->mi_ad_monitorConnectionLocalAddress,
+ &l[ i ]->sl_name, NULL );
+
+ attr_merge_normalize_one( e, slap_schema.si_ad_labeledURI,
+ &l[ i ]->sl_url, NULL );
+
+#ifdef HAVE_TLS
+ if ( l[ i ]->sl_is_tls ) {
+ struct berval bv;
+
+ BER_BVSTR( &bv, "TLS" );
+ attr_merge_normalize_one( e, mi->mi_ad_monitoredInfo,
+ &bv, NULL );
+ }
+#endif /* HAVE_TLS */
+#ifdef LDAP_CONNECTIONLESS
+ if ( l[ i ]->sl_is_udp ) {
+ struct berval bv;
+
+ BER_BVSTR( &bv, "UDP" );
+ attr_merge_normalize_one( e, mi->mi_ad_monitoredInfo,
+ &bv, NULL );
+ }
+#endif /* HAVE_TLS */
+
+ mp = monitor_entrypriv_create();
+ if ( mp == NULL ) {
+ return -1;
+ }
+ e->e_private = ( void * )mp;
+ mp->mp_info = ms;
+ mp->mp_flags = ms->mss_flags
+ | MONITOR_F_SUB;
+
+ if ( monitor_cache_add( mi, e ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_listener_init: "
+ "unable to add entry \"cn=Listener %d,%s\"\n",
+ i, ms->mss_ndn.bv_val, 0 );
+ return( -1 );
+ }
+
+ *ep = e;
+ ep = &mp->mp_next;
+ }
+
+ monitor_cache_release( mi, e_listener );
+
+ return( 0 );
+}
+
diff --git a/servers/slapd/back-monitor/log.c b/servers/slapd/back-monitor/log.c
new file mode 100644
index 0000000..d10cbac
--- /dev/null
+++ b/servers/slapd/back-monitor/log.c
@@ -0,0 +1,455 @@
+/* log.c - deal with log subsystem */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2001-2018 The OpenLDAP Foundation.
+ * Portions Copyright 2001-2003 Pierangelo Masarati.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Pierangelo Masarati for inclusion
+ * in OpenLDAP Software.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/string.h>
+
+#include "slap.h"
+#include <lber_pvt.h>
+#include "lutil.h"
+#include "ldif.h"
+#include "back-monitor.h"
+
+static int
+monitor_subsys_log_open(
+ BackendDB *be,
+ monitor_subsys_t *ms );
+
+static int
+monitor_subsys_log_modify(
+ Operation *op,
+ SlapReply *rs,
+ Entry *e );
+
+/*
+ * log mutex
+ */
+ldap_pvt_thread_mutex_t monitor_log_mutex;
+
+static int add_values( Operation *op, Entry *e, Modification *mod, int *newlevel );
+static int delete_values( Operation *op, Entry *e, Modification *mod, int *newlevel );
+static int replace_values( Operation *op, Entry *e, Modification *mod, int *newlevel );
+
+/*
+ * initializes log subentry
+ */
+int
+monitor_subsys_log_init(
+ BackendDB *be,
+ monitor_subsys_t *ms )
+{
+ ms->mss_open = monitor_subsys_log_open;
+ ms->mss_modify = monitor_subsys_log_modify;
+
+ ldap_pvt_thread_mutex_init( &monitor_log_mutex );
+
+ return( 0 );
+}
+
+/*
+ * opens log subentry
+ */
+int
+monitor_subsys_log_open(
+ BackendDB *be,
+ monitor_subsys_t *ms )
+{
+ BerVarray bva = NULL;
+
+ if ( loglevel2bvarray( ldap_syslog, &bva ) == 0 && bva != NULL ) {
+ monitor_info_t *mi;
+ Entry *e;
+
+ mi = ( monitor_info_t * )be->be_private;
+
+ if ( monitor_cache_get( mi, &ms->mss_ndn, &e ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_log_init: "
+ "unable to get entry \"%s\"\n",
+ ms->mss_ndn.bv_val, 0, 0 );
+ ber_bvarray_free( bva );
+ return( -1 );
+ }
+
+ attr_merge_normalize( e, mi->mi_ad_managedInfo, bva, NULL );
+ ber_bvarray_free( bva );
+
+ monitor_cache_release( mi, e );
+ }
+
+ return( 0 );
+}
+
+static int
+monitor_subsys_log_modify(
+ Operation *op,
+ SlapReply *rs,
+ Entry *e )
+{
+ monitor_info_t *mi = ( monitor_info_t * )op->o_bd->be_private;
+ int rc = LDAP_OTHER;
+ int newlevel = ldap_syslog;
+ Attribute *save_attrs;
+ Modifications *modlist = op->orm_modlist;
+ Modifications *ml;
+
+ ldap_pvt_thread_mutex_lock( &monitor_log_mutex );
+
+ save_attrs = e->e_attrs;
+ e->e_attrs = attrs_dup( e->e_attrs );
+
+ for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
+ Modification *mod = &ml->sml_mod;
+
+ /*
+ * accept all operational attributes;
+ * this includes modifersName and modifyTimestamp
+ * if lastmod is "on"
+ */
+ if ( is_at_operational( mod->sm_desc->ad_type ) ) {
+ ( void ) attr_delete( &e->e_attrs, mod->sm_desc );
+ rc = rs->sr_err = attr_merge( e, mod->sm_desc,
+ mod->sm_values, mod->sm_nvalues );
+ if ( rc != LDAP_SUCCESS ) {
+ break;
+ }
+ continue;
+
+ /*
+ * only the "managedInfo" attribute can be modified
+ */
+ } else if ( mod->sm_desc != mi->mi_ad_managedInfo ) {
+ rc = rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
+ break;
+ }
+
+ switch ( mod->sm_op ) {
+ case LDAP_MOD_ADD:
+ rc = add_values( op, e, mod, &newlevel );
+ break;
+
+ case LDAP_MOD_DELETE:
+ rc = delete_values( op, e, mod, &newlevel );
+ break;
+
+ case LDAP_MOD_REPLACE:
+ rc = replace_values( op, e, mod, &newlevel );
+ break;
+
+ default:
+ rc = LDAP_OTHER;
+ break;
+ }
+
+ if ( rc != LDAP_SUCCESS ) {
+ rs->sr_err = rc;
+ break;
+ }
+ }
+
+ /* set the new debug level */
+ if ( rc == LDAP_SUCCESS ) {
+ const char *text;
+ static char textbuf[ BACKMONITOR_BUFSIZE ];
+
+ /* check for abandon */
+ if ( op->o_abandon ) {
+ rc = rs->sr_err = SLAPD_ABANDON;
+
+ goto cleanup;
+ }
+
+ /* check that the entry still obeys the schema */
+ rc = entry_schema_check( op, e, save_attrs, 0, 0, NULL,
+ &text, textbuf, sizeof( textbuf ) );
+ if ( rc != LDAP_SUCCESS ) {
+ rs->sr_err = rc;
+ goto cleanup;
+ }
+
+ /*
+ * Do we need to protect this with a mutex?
+ */
+ ldap_syslog = newlevel;
+
+#if 0 /* debug rather than log */
+ slap_debug = newlevel;
+ lutil_set_debug_level( "slapd", slap_debug );
+ ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &slap_debug);
+ ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &slap_debug);
+ ldif_debug = slap_debug;
+#endif
+ }
+
+cleanup:;
+ if ( rc == LDAP_SUCCESS ) {
+ attrs_free( save_attrs );
+
+ } else {
+ attrs_free( e->e_attrs );
+ e->e_attrs = save_attrs;
+ }
+
+ ldap_pvt_thread_mutex_unlock( &monitor_log_mutex );
+
+ if ( rc == LDAP_SUCCESS ) {
+ rc = SLAP_CB_CONTINUE;
+ }
+
+ return rc;
+}
+
+static int
+check_constraints( Modification *mod, int *newlevel )
+{
+ int i;
+
+ if ( mod->sm_nvalues != NULL ) {
+ ber_bvarray_free( mod->sm_nvalues );
+ mod->sm_nvalues = NULL;
+ }
+
+ for ( i = 0; !BER_BVISNULL( &mod->sm_values[ i ] ); i++ ) {
+ int l;
+ struct berval bv;
+
+ if ( str2loglevel( mod->sm_values[ i ].bv_val, &l ) ) {
+ return LDAP_CONSTRAINT_VIOLATION;
+ }
+
+ if ( loglevel2bv( l, &bv ) ) {
+ return LDAP_CONSTRAINT_VIOLATION;
+ }
+
+ assert( bv.bv_len == mod->sm_values[ i ].bv_len );
+
+ AC_MEMCPY( mod->sm_values[ i ].bv_val,
+ bv.bv_val, bv.bv_len );
+
+ *newlevel |= l;
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int
+add_values( Operation *op, Entry *e, Modification *mod, int *newlevel )
+{
+ Attribute *a;
+ int i, rc;
+ MatchingRule *mr = mod->sm_desc->ad_type->sat_equality;
+
+ assert( mod->sm_values != NULL );
+
+ rc = check_constraints( mod, newlevel );
+ if ( rc != LDAP_SUCCESS ) {
+ return rc;
+ }
+
+ a = attr_find( e->e_attrs, mod->sm_desc );
+
+ if ( a != NULL ) {
+ /* "managedInfo" SHOULD have appropriate rules ... */
+ if ( mr == NULL || !mr->smr_match ) {
+ return LDAP_INAPPROPRIATE_MATCHING;
+ }
+
+ for ( i = 0; !BER_BVISNULL( &mod->sm_values[ i ] ); i++ ) {
+ int rc;
+ int j;
+ const char *text = NULL;
+ struct berval asserted;
+
+ rc = asserted_value_validate_normalize(
+ mod->sm_desc, mr, SLAP_MR_EQUALITY,
+ &mod->sm_values[ i ], &asserted, &text,
+ op->o_tmpmemctx );
+
+ if ( rc != LDAP_SUCCESS ) {
+ return rc;
+ }
+
+ for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); j++ ) {
+ int match;
+ int rc = value_match( &match, mod->sm_desc, mr,
+ 0, &a->a_nvals[ j ], &asserted, &text );
+
+ if ( rc == LDAP_SUCCESS && match == 0 ) {
+ free( asserted.bv_val );
+ return LDAP_TYPE_OR_VALUE_EXISTS;
+ }
+ }
+
+ free( asserted.bv_val );
+ }
+ }
+
+ /* no - add them */
+ rc = attr_merge_normalize( e, mod->sm_desc, mod->sm_values,
+ op->o_tmpmemctx );
+ if ( rc != LDAP_SUCCESS ) {
+ return rc;
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int
+delete_values( Operation *op, Entry *e, Modification *mod, int *newlevel )
+{
+ int i, j, k, found, rc, nl = 0;
+ Attribute *a;
+ MatchingRule *mr = mod->sm_desc->ad_type->sat_equality;
+
+ /* delete the entire attribute */
+ if ( mod->sm_values == NULL ) {
+ int rc = attr_delete( &e->e_attrs, mod->sm_desc );
+
+ if ( rc ) {
+ rc = LDAP_NO_SUCH_ATTRIBUTE;
+
+ } else {
+ *newlevel = 0;
+ rc = LDAP_SUCCESS;
+ }
+ return rc;
+ }
+
+ rc = check_constraints( mod, &nl );
+ if ( rc != LDAP_SUCCESS ) {
+ return rc;
+ }
+
+ *newlevel &= ~nl;
+
+ if ( mr == NULL || !mr->smr_match ) {
+ /* disallow specific attributes from being deleted if
+ * no equality rule */
+ return LDAP_INAPPROPRIATE_MATCHING;
+ }
+
+ /* delete specific values - find the attribute first */
+ if ( (a = attr_find( e->e_attrs, mod->sm_desc )) == NULL ) {
+ return( LDAP_NO_SUCH_ATTRIBUTE );
+ }
+
+ /* find each value to delete */
+ for ( i = 0; !BER_BVISNULL( &mod->sm_values[ i ] ); i++ ) {
+ int rc;
+ const char *text = NULL;
+
+ struct berval asserted;
+
+ rc = asserted_value_validate_normalize(
+ mod->sm_desc, mr, SLAP_MR_EQUALITY,
+ &mod->sm_values[ i ], &asserted, &text,
+ op->o_tmpmemctx );
+
+ if( rc != LDAP_SUCCESS ) return rc;
+
+ found = 0;
+ for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); j++ ) {
+ int match;
+ int rc = value_match( &match, mod->sm_desc, mr,
+ 0, &a->a_nvals[ j ], &asserted, &text );
+
+ if( rc == LDAP_SUCCESS && match != 0 ) {
+ continue;
+ }
+
+ /* found a matching value */
+ found = 1;
+
+ /* delete it */
+ if ( a->a_nvals != a->a_vals ) {
+ free( a->a_nvals[ j ].bv_val );
+ for ( k = j + 1; !BER_BVISNULL( &a->a_nvals[ k ] ); k++ ) {
+ a->a_nvals[ k - 1 ] = a->a_nvals[ k ];
+ }
+ BER_BVZERO( &a->a_nvals[ k - 1 ] );
+ }
+
+ free( a->a_vals[ j ].bv_val );
+ for ( k = j + 1; !BER_BVISNULL( &a->a_vals[ k ] ); k++ ) {
+ a->a_vals[ k - 1 ] = a->a_vals[ k ];
+ }
+ BER_BVZERO( &a->a_vals[ k - 1 ] );
+ a->a_numvals--;
+
+ break;
+ }
+
+ free( asserted.bv_val );
+
+ /* looked through them all w/o finding it */
+ if ( ! found ) {
+ return LDAP_NO_SUCH_ATTRIBUTE;
+ }
+ }
+
+ /* if no values remain, delete the entire attribute */
+ if ( BER_BVISNULL( &a->a_vals[ 0 ] ) ) {
+ assert( a->a_numvals == 0 );
+
+ /* should already be zero */
+ *newlevel = 0;
+
+ if ( attr_delete( &e->e_attrs, mod->sm_desc ) ) {
+ return LDAP_NO_SUCH_ATTRIBUTE;
+ }
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int
+replace_values( Operation *op, Entry *e, Modification *mod, int *newlevel )
+{
+ int rc;
+
+ if ( mod->sm_values != NULL ) {
+ *newlevel = 0;
+ rc = check_constraints( mod, newlevel );
+ if ( rc != LDAP_SUCCESS ) {
+ return rc;
+ }
+ }
+
+ rc = attr_delete( &e->e_attrs, mod->sm_desc );
+
+ if ( rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_ATTRIBUTE ) {
+ return rc;
+ }
+
+ if ( mod->sm_values != NULL ) {
+ rc = attr_merge_normalize( e, mod->sm_desc, mod->sm_values,
+ op->o_tmpmemctx );
+ if ( rc != LDAP_SUCCESS ) {
+ return rc;
+ }
+ }
+
+ return LDAP_SUCCESS;
+}
+
diff --git a/servers/slapd/back-monitor/modify.c b/servers/slapd/back-monitor/modify.c
new file mode 100644
index 0000000..8079c6e
--- /dev/null
+++ b/servers/slapd/back-monitor/modify.c
@@ -0,0 +1,90 @@
+/* modify.c - monitor backend modify routine */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2001-2018 The OpenLDAP Foundation.
+ * Portions Copyright 2001-2003 Pierangelo Masarati.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Pierangelo Masarati for inclusion
+ * in OpenLDAP Software.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "slap.h"
+#include "back-monitor.h"
+#include "proto-back-monitor.h"
+
+int
+monitor_back_modify( Operation *op, SlapReply *rs )
+{
+ int rc = 0;
+ monitor_info_t *mi = ( monitor_info_t * )op->o_bd->be_private;
+ Entry *matched;
+ Entry *e;
+
+ Debug(LDAP_DEBUG_ARGS, "monitor_back_modify:\n", 0, 0, 0);
+
+ /* acquire and lock entry */
+ monitor_cache_dn2entry( op, rs, &op->o_req_ndn, &e, &matched );
+ if ( e == NULL ) {
+ rs->sr_err = LDAP_NO_SUCH_OBJECT;
+ if ( matched ) {
+ if ( !access_allowed_mask( op, matched,
+ slap_schema.si_ad_entry,
+ NULL, ACL_DISCLOSE, NULL, NULL ) )
+ {
+ /* do nothing */ ;
+ } else {
+ rs->sr_matched = matched->e_dn;
+ }
+ }
+ send_ldap_result( op, rs );
+ if ( matched != NULL ) {
+ rs->sr_matched = NULL;
+ monitor_cache_release( mi, matched );
+ }
+ return rs->sr_err;
+ }
+
+ if ( !acl_check_modlist( op, e, op->orm_modlist )) {
+ rc = LDAP_INSUFFICIENT_ACCESS;
+
+ } else {
+ assert( !SLAP_SHADOW( op->o_bd ) );
+ slap_mods_opattrs( op, &op->orm_modlist, 0 );
+
+ rc = monitor_entry_modify( op, rs, e );
+ }
+
+ if ( rc != LDAP_SUCCESS ) {
+ if ( !access_allowed_mask( op, e, slap_schema.si_ad_entry,
+ NULL, ACL_DISCLOSE, NULL, NULL ) )
+ {
+ rc = LDAP_NO_SUCH_OBJECT;
+ }
+ }
+
+ rs->sr_err = rc;
+ send_ldap_result( op, rs );
+
+ monitor_cache_release( mi, e );
+
+ return rs->sr_err;
+}
+
diff --git a/servers/slapd/back-monitor/operation.c b/servers/slapd/back-monitor/operation.c
new file mode 100644
index 0000000..fbf5f24
--- /dev/null
+++ b/servers/slapd/back-monitor/operation.c
@@ -0,0 +1,249 @@
+/* operation.c - deal with operation subsystem */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2001-2018 The OpenLDAP Foundation.
+ * Portions Copyright 2001-2003 Pierangelo Masarati.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Pierangelo Masarati for inclusion
+ * in OpenLDAP Software.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+
+#include "slap.h"
+#include "back-monitor.h"
+#include "lber_pvt.h"
+
+struct monitor_ops_t {
+ struct berval rdn;
+ struct berval nrdn;
+} monitor_op[] = {
+ { BER_BVC( "cn=Bind" ), BER_BVNULL },
+ { BER_BVC( "cn=Unbind" ), BER_BVNULL },
+ { BER_BVC( "cn=Search" ), BER_BVNULL },
+ { BER_BVC( "cn=Compare" ), BER_BVNULL },
+ { BER_BVC( "cn=Modify" ), BER_BVNULL },
+ { BER_BVC( "cn=Modrdn" ), BER_BVNULL },
+ { BER_BVC( "cn=Add" ), BER_BVNULL },
+ { BER_BVC( "cn=Delete" ), BER_BVNULL },
+ { BER_BVC( "cn=Abandon" ), BER_BVNULL },
+ { BER_BVC( "cn=Extended" ), BER_BVNULL },
+ { BER_BVNULL, BER_BVNULL }
+};
+
+static int
+monitor_subsys_ops_destroy(
+ BackendDB *be,
+ monitor_subsys_t *ms );
+
+static int
+monitor_subsys_ops_update(
+ Operation *op,
+ SlapReply *rs,
+ Entry *e );
+
+int
+monitor_subsys_ops_init(
+ BackendDB *be,
+ monitor_subsys_t *ms )
+{
+ monitor_info_t *mi;
+
+ Entry *e_op, **ep;
+ monitor_entry_t *mp;
+ int i;
+ struct berval bv_zero = BER_BVC( "0" );
+
+ assert( be != NULL );
+
+ ms->mss_destroy = monitor_subsys_ops_destroy;
+ ms->mss_update = monitor_subsys_ops_update;
+
+ mi = ( monitor_info_t * )be->be_private;
+
+ if ( monitor_cache_get( mi,
+ &ms->mss_ndn, &e_op ) )
+ {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_ops_init: "
+ "unable to get entry \"%s\"\n",
+ ms->mss_ndn.bv_val,
+ 0, 0 );
+ return( -1 );
+ }
+
+ attr_merge_one( e_op, mi->mi_ad_monitorOpInitiated, &bv_zero, NULL );
+ attr_merge_one( e_op, mi->mi_ad_monitorOpCompleted, &bv_zero, NULL );
+
+ mp = ( monitor_entry_t * )e_op->e_private;
+ mp->mp_children = NULL;
+ ep = &mp->mp_children;
+
+ for ( i = 0; i < SLAP_OP_LAST; i++ ) {
+ struct berval rdn;
+ Entry *e;
+ struct berval bv;
+
+ /*
+ * Initiated ops
+ */
+ e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, &monitor_op[i].rdn,
+ mi->mi_oc_monitorOperation, NULL, NULL );
+
+ if ( e == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_ops_init: "
+ "unable to create entry \"%s,%s\"\n",
+ monitor_op[ i ].rdn.bv_val,
+ ms->mss_ndn.bv_val, 0 );
+ return( -1 );
+ }
+
+ BER_BVSTR( &bv, "0" );
+ attr_merge_one( e, mi->mi_ad_monitorOpInitiated, &bv, NULL );
+ attr_merge_one( e, mi->mi_ad_monitorOpCompleted, &bv, NULL );
+
+ /* steal normalized RDN */
+ dnRdn( &e->e_nname, &rdn );
+ ber_dupbv( &monitor_op[ i ].nrdn, &rdn );
+
+ mp = monitor_entrypriv_create();
+ if ( mp == NULL ) {
+ return -1;
+ }
+ e->e_private = ( void * )mp;
+ mp->mp_info = ms;
+ mp->mp_flags = ms->mss_flags \
+ | MONITOR_F_SUB | MONITOR_F_PERSISTENT;
+
+ if ( monitor_cache_add( mi, e ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_ops_init: "
+ "unable to add entry \"%s,%s\"\n",
+ monitor_op[ i ].rdn.bv_val,
+ ms->mss_ndn.bv_val, 0 );
+ return( -1 );
+ }
+
+ *ep = e;
+ ep = &mp->mp_next;
+ }
+
+ monitor_cache_release( mi, e_op );
+
+ return( 0 );
+}
+
+static int
+monitor_subsys_ops_destroy(
+ BackendDB *be,
+ monitor_subsys_t *ms )
+{
+ int i;
+
+ for ( i = 0; i < SLAP_OP_LAST; i++ ) {
+ if ( !BER_BVISNULL( &monitor_op[ i ].nrdn ) ) {
+ ch_free( monitor_op[ i ].nrdn.bv_val );
+ }
+ }
+
+ return 0;
+}
+
+static int
+monitor_subsys_ops_update(
+ Operation *op,
+ SlapReply *rs,
+ Entry *e )
+{
+ monitor_info_t *mi = ( monitor_info_t * )op->o_bd->be_private;
+
+ ldap_pvt_mp_t nInitiated = LDAP_PVT_MP_INIT,
+ nCompleted = LDAP_PVT_MP_INIT;
+ struct berval rdn;
+ int i;
+ Attribute *a;
+ slap_counters_t *sc;
+ static struct berval bv_ops = BER_BVC( "cn=operations" );
+
+ assert( mi != NULL );
+ assert( e != NULL );
+
+ dnRdn( &e->e_nname, &rdn );
+
+ if ( dn_match( &rdn, &bv_ops ) ) {
+ ldap_pvt_mp_init( nInitiated );
+ ldap_pvt_mp_init( nCompleted );
+
+ ldap_pvt_thread_mutex_lock( &slap_counters.sc_mutex );
+ for ( i = 0; i < SLAP_OP_LAST; i++ ) {
+ ldap_pvt_mp_add( nInitiated, slap_counters.sc_ops_initiated_[ i ] );
+ ldap_pvt_mp_add( nCompleted, slap_counters.sc_ops_completed_[ i ] );
+ }
+ for ( sc = slap_counters.sc_next; sc; sc = sc->sc_next ) {
+ ldap_pvt_thread_mutex_lock( &sc->sc_mutex );
+ for ( i = 0; i < SLAP_OP_LAST; i++ ) {
+ ldap_pvt_mp_add( nInitiated, sc->sc_ops_initiated_[ i ] );
+ ldap_pvt_mp_add( nCompleted, sc->sc_ops_completed_[ i ] );
+ }
+ ldap_pvt_thread_mutex_unlock( &sc->sc_mutex );
+ }
+ ldap_pvt_thread_mutex_unlock( &slap_counters.sc_mutex );
+
+ } else {
+ for ( i = 0; i < SLAP_OP_LAST; i++ ) {
+ if ( dn_match( &rdn, &monitor_op[ i ].nrdn ) )
+ {
+ ldap_pvt_thread_mutex_lock( &slap_counters.sc_mutex );
+ ldap_pvt_mp_init_set( nInitiated, slap_counters.sc_ops_initiated_[ i ] );
+ ldap_pvt_mp_init_set( nCompleted, slap_counters.sc_ops_completed_[ i ] );
+ for ( sc = slap_counters.sc_next; sc; sc = sc->sc_next ) {
+ ldap_pvt_thread_mutex_lock( &sc->sc_mutex );
+ ldap_pvt_mp_add( nInitiated, sc->sc_ops_initiated_[ i ] );
+ ldap_pvt_mp_add( nCompleted, sc->sc_ops_completed_[ i ] );
+ ldap_pvt_thread_mutex_unlock( &sc->sc_mutex );
+ }
+ ldap_pvt_thread_mutex_unlock( &slap_counters.sc_mutex );
+ break;
+ }
+ }
+
+ if ( i == SLAP_OP_LAST ) {
+ /* not found ... */
+ return( 0 );
+ }
+ }
+
+ a = attr_find( e->e_attrs, mi->mi_ad_monitorOpInitiated );
+ assert ( a != NULL );
+
+ /* NOTE: no minus sign is allowed in the counters... */
+ UI2BV( &a->a_vals[ 0 ], nInitiated );
+ ldap_pvt_mp_clear( nInitiated );
+
+ a = attr_find( e->e_attrs, mi->mi_ad_monitorOpCompleted );
+ assert ( a != NULL );
+
+ /* NOTE: no minus sign is allowed in the counters... */
+ UI2BV( &a->a_vals[ 0 ], nCompleted );
+ ldap_pvt_mp_clear( nCompleted );
+
+ /* FIXME: touch modifyTimestamp? */
+
+ return SLAP_CB_CONTINUE;
+}
+
diff --git a/servers/slapd/back-monitor/operational.c b/servers/slapd/back-monitor/operational.c
new file mode 100644
index 0000000..f335e11
--- /dev/null
+++ b/servers/slapd/back-monitor/operational.c
@@ -0,0 +1,72 @@
+/* operational.c - monitor backend operational attributes function */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2001-2018 The OpenLDAP Foundation.
+ * Portions Copyright 2001-2003 Pierangelo Masarati.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Pierangelo Masarati for inclusion
+ * in OpenLDAP Software.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "slap.h"
+#include "back-monitor.h"
+#include "proto-back-monitor.h"
+
+/*
+ * sets the supported operational attributes (if required)
+ */
+
+int
+monitor_back_operational(
+ Operation *op,
+ SlapReply *rs )
+{
+ Attribute **ap;
+
+ assert( rs->sr_entry != NULL );
+
+ for ( ap = &rs->sr_operational_attrs; *ap; ap = &(*ap)->a_next ) {
+ if ( (*ap)->a_desc == slap_schema.si_ad_hasSubordinates ) {
+ break;
+ }
+ }
+
+ if ( *ap == NULL &&
+ attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_hasSubordinates ) == NULL &&
+ ( SLAP_OPATTRS( rs->sr_attr_flags ) ||
+ ad_inlist( slap_schema.si_ad_hasSubordinates, rs->sr_attrs ) ) )
+ {
+ int hs;
+ monitor_entry_t *mp;
+
+ mp = ( monitor_entry_t * )rs->sr_entry->e_private;
+
+ assert( mp != NULL );
+
+ hs = MONITOR_HAS_CHILDREN( mp );
+ *ap = slap_operational_hasSubordinate( hs );
+ assert( *ap != NULL );
+ ap = &(*ap)->a_next;
+ }
+
+ return LDAP_SUCCESS;
+}
+
diff --git a/servers/slapd/back-monitor/overlay.c b/servers/slapd/back-monitor/overlay.c
new file mode 100644
index 0000000..3d3f312
--- /dev/null
+++ b/servers/slapd/back-monitor/overlay.c
@@ -0,0 +1,141 @@
+/* overlay.c - deals with overlay subsystem */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2001-2018 The OpenLDAP Foundation.
+ * Portions Copyright 2001-2003 Pierangelo Masarati.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Pierangelo Masarati for inclusion
+ * in OpenLDAP Software.
+ */
+
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+
+#include "slap.h"
+#include "back-monitor.h"
+
+/*
+ * initializes overlay subentries
+ */
+int
+monitor_subsys_overlay_init(
+ BackendDB *be,
+ monitor_subsys_t *ms
+)
+{
+ monitor_info_t *mi;
+ Entry *e_overlay, **ep;
+ int i;
+ monitor_entry_t *mp;
+ slap_overinst *on;
+ monitor_subsys_t *ms_database;
+
+ mi = ( monitor_info_t * )be->be_private;
+
+ ms_database = monitor_back_get_subsys( SLAPD_MONITOR_DATABASE_NAME );
+ if ( ms_database == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_backend_init: "
+ "unable to get "
+ "\"" SLAPD_MONITOR_DATABASE_NAME "\" "
+ "subsystem\n",
+ 0, 0, 0 );
+ return -1;
+ }
+
+ if ( monitor_cache_get( mi, &ms->mss_ndn, &e_overlay ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_overlay_init: "
+ "unable to get entry \"%s\"\n",
+ ms->mss_ndn.bv_val, 0, 0 );
+ return( -1 );
+ }
+
+ mp = ( monitor_entry_t * )e_overlay->e_private;
+ mp->mp_children = NULL;
+ ep = &mp->mp_children;
+
+ for ( on = overlay_next( NULL ), i = 0; on; on = overlay_next( on ), i++ ) {
+ char buf[ BACKMONITOR_BUFSIZE ];
+ struct berval bv;
+ int j;
+ Entry *e;
+ BackendDB *be;
+
+ bv.bv_len = snprintf( buf, sizeof( buf ), "cn=Overlay %d", i );
+ bv.bv_val = buf;
+ e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, &bv,
+ mi->mi_oc_monitoredObject, NULL, NULL );
+ if ( e == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_overlay_init: "
+ "unable to create entry \"cn=Overlay %d,%s\"\n",
+ i, ms->mss_ndn.bv_val, 0 );
+ return( -1 );
+ }
+ ber_str2bv( on->on_bi.bi_type, 0, 0, &bv );
+ attr_merge_normalize_one( e, mi->mi_ad_monitoredInfo, &bv, NULL );
+ attr_merge_normalize_one( e, mi->mi_ad_monitorRuntimeConfig,
+ on->on_bi.bi_cf_ocs ? (struct berval *)&slap_true_bv :
+ (struct berval *)&slap_false_bv, NULL );
+
+ attr_merge_normalize_one( e_overlay, mi->mi_ad_monitoredInfo,
+ &bv, NULL );
+
+ j = -1;
+ LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) {
+ char buf[ SLAP_LDAPDN_MAXLEN ];
+ struct berval dn;
+
+ j++;
+ if ( !overlay_is_inst( be, on->on_bi.bi_type ) ) {
+ continue;
+ }
+
+ snprintf( buf, sizeof( buf ), "cn=Database %d,%s",
+ j, ms_database->mss_dn.bv_val );
+
+ ber_str2bv( buf, 0, 0, &dn );
+ attr_merge_normalize_one( e, slap_schema.si_ad_seeAlso,
+ &dn, NULL );
+ }
+
+ mp = monitor_entrypriv_create();
+ if ( mp == NULL ) {
+ return -1;
+ }
+ e->e_private = ( void * )mp;
+ mp->mp_info = ms;
+ mp->mp_flags = ms->mss_flags
+ | MONITOR_F_SUB;
+
+ if ( monitor_cache_add( mi, e ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_overlay_init: "
+ "unable to add entry \"cn=Overlay %d,%s\"\n",
+ i, ms->mss_ndn.bv_val, 0 );
+ return( -1 );
+ }
+
+ *ep = e;
+ ep = &mp->mp_next;
+ }
+
+ monitor_cache_release( mi, e_overlay );
+
+ return( 0 );
+}
+
diff --git a/servers/slapd/back-monitor/proto-back-monitor.h b/servers/slapd/back-monitor/proto-back-monitor.h
new file mode 100644
index 0000000..045b779
--- /dev/null
+++ b/servers/slapd/back-monitor/proto-back-monitor.h
@@ -0,0 +1,338 @@
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2001-2018 The OpenLDAP Foundation.
+ * Portions Copyright 2001-2003 Pierangelo Masarati.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Pierangelo Masarati for inclusion
+ * in OpenLDAP Software.
+ */
+
+#ifndef _PROTO_BACK_MONITOR
+#define _PROTO_BACK_MONITOR
+
+#include <ldap_cdefs.h>
+
+LDAP_BEGIN_DECL
+
+/*
+ * backends
+ */
+int
+monitor_subsys_backend_init LDAP_P((
+ BackendDB *be,
+ monitor_subsys_t *ms ));
+
+/*
+ * cache
+ */
+extern int
+monitor_cache_cmp LDAP_P((
+ const void *c1,
+ const void *c2 ));
+extern int
+monitor_cache_dup LDAP_P((
+ void *c1,
+ void *c2 ));
+extern int
+monitor_cache_add LDAP_P((
+ monitor_info_t *mi,
+ Entry *e ));
+extern int
+monitor_cache_get LDAP_P((
+ monitor_info_t *mi,
+ struct berval *ndn,
+ Entry **ep ));
+extern int
+monitor_cache_remove LDAP_P((
+ monitor_info_t *mi,
+ struct berval *ndn,
+ Entry **ep ));
+extern int
+monitor_cache_dn2entry LDAP_P((
+ Operation *op,
+ SlapReply *rs,
+ struct berval *ndn,
+ Entry **ep,
+ Entry **matched ));
+extern int
+monitor_cache_lock LDAP_P((
+ Entry *e ));
+extern int
+monitor_cache_release LDAP_P((
+ monitor_info_t *mi,
+ Entry *e ));
+
+extern int
+monitor_cache_destroy LDAP_P((
+ monitor_info_t *mi ));
+
+extern int
+monitor_back_release(
+ Operation *op,
+ Entry *e,
+ int rw );
+
+/*
+ * connections
+ */
+extern int
+monitor_subsys_conn_init LDAP_P((
+ BackendDB *be,
+ monitor_subsys_t *ms ));
+
+/*
+ * databases
+ */
+extern int
+monitor_subsys_database_init LDAP_P((
+ BackendDB *be,
+ monitor_subsys_t *ms ));
+
+/*
+ * entry
+ */
+extern int
+monitor_entry_update LDAP_P((
+ Operation *op,
+ SlapReply *rs,
+ Entry *e ));
+extern int
+monitor_entry_create LDAP_P((
+ Operation *op,
+ SlapReply *rs,
+ struct berval *ndn,
+ Entry *e_parent,
+ Entry **ep ));
+extern int
+monitor_entry_modify LDAP_P((
+ Operation *op,
+ SlapReply *rs,
+ Entry *e ));
+extern int
+monitor_entry_test_flags LDAP_P((
+ monitor_entry_t *mp,
+ int cond ));
+extern monitor_entry_t *
+monitor_back_entrypriv_create LDAP_P((
+ void ));
+extern Entry *
+monitor_back_entry_stub LDAP_P((
+ struct berval *pdn,
+ struct berval *pndn,
+ struct berval *rdn,
+ ObjectClass *oc,
+ struct berval *create,
+ struct berval *modify ));
+
+#define monitor_entrypriv_create monitor_back_entrypriv_create
+#define monitor_entry_stub monitor_back_entry_stub
+
+/*
+ * init
+ */
+extern int
+monitor_subsys_is_opened LDAP_P((
+ void ));
+extern int
+monitor_back_register_subsys LDAP_P((
+ monitor_subsys_t *ms ));
+extern int
+monitor_back_register_subsys_late LDAP_P((
+ monitor_subsys_t *ms ));
+extern int
+monitor_back_register_backend LDAP_P((
+ BackendInfo *bi ));
+extern int
+monitor_back_register_database LDAP_P((
+ BackendDB *be,
+ struct berval *ndn ));
+extern int
+monitor_back_register_overlay_info LDAP_P((
+ slap_overinst *on ));
+extern int
+monitor_back_register_overlay LDAP_P((
+ BackendDB *be,
+ struct slap_overinst *on,
+ struct berval *ndn_out ));
+extern int
+monitor_back_register_backend_limbo LDAP_P((
+ BackendInfo *bi ));
+extern int
+monitor_back_register_database_limbo LDAP_P((
+ BackendDB *be,
+ struct berval *ndn_out ));
+extern int
+monitor_back_register_overlay_info_limbo LDAP_P((
+ slap_overinst *on ));
+extern int
+monitor_back_register_overlay_limbo LDAP_P((
+ BackendDB *be,
+ struct slap_overinst *on,
+ struct berval *ndn_out ));
+extern monitor_subsys_t *
+monitor_back_get_subsys LDAP_P((
+ const char *name ));
+extern monitor_subsys_t *
+monitor_back_get_subsys_by_dn LDAP_P((
+ struct berval *ndn,
+ int sub ));
+extern int
+monitor_back_is_configured LDAP_P(( void ));
+extern int
+monitor_back_register_entry LDAP_P((
+ Entry *e,
+ monitor_callback_t *cb,
+ monitor_subsys_t *mss,
+ unsigned long flags ));
+extern int
+monitor_back_register_entry_parent LDAP_P((
+ Entry *e,
+ monitor_callback_t *cb,
+ monitor_subsys_t *mss,
+ unsigned long flags,
+ struct berval *base,
+ int scope,
+ struct berval *filter ));
+extern int
+monitor_search2ndn LDAP_P((
+ struct berval *base,
+ int scope,
+ struct berval *filter,
+ struct berval *ndn ));
+extern int
+monitor_back_register_entry_attrs LDAP_P((
+ struct berval *ndn,
+ Attribute *a,
+ monitor_callback_t *cb,
+ struct berval *base,
+ int scope,
+ struct berval *filter ));
+extern int
+monitor_back_register_entry_callback LDAP_P((
+ struct berval *ndn,
+ monitor_callback_t *cb,
+ struct berval *base,
+ int scope,
+ struct berval *filter ));
+extern int
+monitor_back_unregister_entry LDAP_P((
+ struct berval *ndn ));
+extern int
+monitor_back_unregister_entry_parent LDAP_P((
+ struct berval *nrdn,
+ monitor_callback_t *target_cb,
+ struct berval *base,
+ int scope,
+ struct berval *filter ));
+extern int
+monitor_back_unregister_entry_attrs LDAP_P((
+ struct berval *ndn,
+ Attribute *a,
+ monitor_callback_t *cb,
+ struct berval *base,
+ int scope,
+ struct berval *filter ));
+extern int
+monitor_back_unregister_entry_callback LDAP_P((
+ struct berval *ndn,
+ monitor_callback_t *cb,
+ struct berval *base,
+ int scope,
+ struct berval *filter ));
+
+/*
+ * listener
+ */
+extern int
+monitor_subsys_listener_init LDAP_P((
+ BackendDB *be,
+ monitor_subsys_t *ms ));
+
+/*
+ * log
+ */
+extern int
+monitor_subsys_log_init LDAP_P((
+ BackendDB *be,
+ monitor_subsys_t *ms ));
+
+/*
+ * operations
+ */
+extern int
+monitor_subsys_ops_init LDAP_P((
+ BackendDB *be,
+ monitor_subsys_t *ms ));
+
+/*
+ * overlay
+ */
+extern int
+monitor_subsys_overlay_init LDAP_P((
+ BackendDB *be,
+ monitor_subsys_t *ms ));
+
+/*
+ * sent
+ */
+extern int
+monitor_subsys_sent_init LDAP_P((
+ BackendDB *be,
+ monitor_subsys_t *ms ));
+
+/*
+ * threads
+ */
+extern int
+monitor_subsys_thread_init LDAP_P((
+ BackendDB *be,
+ monitor_subsys_t *ms ));
+
+/*
+ * time
+ */
+extern int monitor_subsys_time_init LDAP_P((
+ BackendDB *be,
+ monitor_subsys_t *ms ));
+
+/*
+ * waiters
+ */
+extern int
+monitor_subsys_rww_init LDAP_P((
+ BackendDB *be,
+ monitor_subsys_t *ms ));
+
+/*
+ * former external.h
+ */
+
+extern BI_init monitor_back_initialize;
+
+extern BI_db_init monitor_back_db_init;
+extern BI_db_open monitor_back_db_open;
+extern BI_config monitor_back_config;
+extern BI_db_destroy monitor_back_db_destroy;
+extern BI_db_config monitor_back_db_config;
+
+extern BI_op_search monitor_back_search;
+extern BI_op_compare monitor_back_compare;
+extern BI_op_modify monitor_back_modify;
+extern BI_op_bind monitor_back_bind;
+extern BI_operational monitor_back_operational;
+
+LDAP_END_DECL
+
+#endif /* _PROTO_BACK_MONITOR */
+
diff --git a/servers/slapd/back-monitor/rww.c b/servers/slapd/back-monitor/rww.c
new file mode 100644
index 0000000..f99c4c1
--- /dev/null
+++ b/servers/slapd/back-monitor/rww.c
@@ -0,0 +1,232 @@
+/* readw.c - deal with read waiters subsystem */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2001-2018 The OpenLDAP Foundation.
+ * Portions Copyright 2001-2003 Pierangelo Masarati.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Pierangelo Masarati for inclusion
+ * in OpenLDAP Software.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+
+#include "slap.h"
+#include "lutil.h"
+#include "back-monitor.h"
+
+static int
+monitor_subsys_rww_destroy(
+ BackendDB *be,
+ monitor_subsys_t *ms );
+
+static int
+monitor_subsys_rww_update(
+ Operation *op,
+ SlapReply *rs,
+ Entry *e );
+
+enum {
+ MONITOR_RWW_READ = 0,
+ MONITOR_RWW_WRITE,
+
+ MONITOR_RWW_LAST
+};
+
+static struct monitor_rww_t {
+ struct berval rdn;
+ struct berval nrdn;
+} monitor_rww[] = {
+ { BER_BVC("cn=Read"), BER_BVNULL },
+ { BER_BVC("cn=Write"), BER_BVNULL },
+ { BER_BVNULL, BER_BVNULL }
+};
+
+int
+monitor_subsys_rww_init(
+ BackendDB *be,
+ monitor_subsys_t *ms )
+{
+ monitor_info_t *mi;
+
+ Entry **ep, *e_conn;
+ monitor_entry_t *mp;
+ int i;
+
+ assert( be != NULL );
+
+ ms->mss_destroy = monitor_subsys_rww_destroy;
+ ms->mss_update = monitor_subsys_rww_update;
+
+ mi = ( monitor_info_t * )be->be_private;
+
+ if ( monitor_cache_get( mi, &ms->mss_ndn, &e_conn ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_rww_init: "
+ "unable to get entry \"%s\"\n",
+ ms->mss_ndn.bv_val, 0, 0 );
+ return( -1 );
+ }
+
+ mp = ( monitor_entry_t * )e_conn->e_private;
+ mp->mp_children = NULL;
+ ep = &mp->mp_children;
+
+ for ( i = 0; i < MONITOR_RWW_LAST; i++ ) {
+ struct berval nrdn, bv;
+ Entry *e;
+
+ e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, &monitor_rww[i].rdn,
+ mi->mi_oc_monitorCounterObject, NULL, NULL );
+ if ( e == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_rww_init: "
+ "unable to create entry \"cn=Read,%s\"\n",
+ ms->mss_ndn.bv_val, 0, 0 );
+ return( -1 );
+ }
+
+ /* steal normalized RDN */
+ dnRdn( &e->e_nname, &nrdn );
+ ber_dupbv( &monitor_rww[ i ].nrdn, &nrdn );
+
+ BER_BVSTR( &bv, "0" );
+ attr_merge_one( e, mi->mi_ad_monitorCounter, &bv, NULL );
+
+ mp = monitor_entrypriv_create();
+ if ( mp == NULL ) {
+ return -1;
+ }
+ e->e_private = ( void * )mp;
+ mp->mp_info = ms;
+ mp->mp_flags = ms->mss_flags \
+ | MONITOR_F_SUB | MONITOR_F_PERSISTENT;
+
+ if ( monitor_cache_add( mi, e ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_rww_init: "
+ "unable to add entry \"%s,%s\"\n",
+ monitor_rww[ i ].rdn.bv_val,
+ ms->mss_ndn.bv_val, 0 );
+ return( -1 );
+ }
+
+ *ep = e;
+ ep = &mp->mp_next;
+ }
+
+ monitor_cache_release( mi, e_conn );
+
+ return( 0 );
+}
+
+static int
+monitor_subsys_rww_destroy(
+ BackendDB *be,
+ monitor_subsys_t *ms )
+{
+ int i;
+
+ for ( i = 0; i < MONITOR_RWW_LAST; i++ ) {
+ ber_memfree_x( monitor_rww[ i ].nrdn.bv_val, NULL );
+ }
+
+ return 0;
+}
+
+static int
+monitor_subsys_rww_update(
+ Operation *op,
+ SlapReply *rs,
+ Entry *e )
+{
+ monitor_info_t *mi = (monitor_info_t *)op->o_bd->be_private;
+ Connection *c;
+ ber_socket_t connindex;
+ long nconns, nwritewaiters, nreadwaiters;
+
+ int i;
+ struct berval nrdn;
+
+ Attribute *a;
+ char buf[LDAP_PVT_INTTYPE_CHARS(long)];
+ long num = 0;
+ ber_len_t len;
+
+ assert( mi != NULL );
+ assert( e != NULL );
+
+ dnRdn( &e->e_nname, &nrdn );
+
+ for ( i = 0; !BER_BVISNULL( &monitor_rww[ i ].nrdn ); i++ ) {
+ if ( dn_match( &nrdn, &monitor_rww[ i ].nrdn ) ) {
+ break;
+ }
+ }
+
+ if ( i == MONITOR_RWW_LAST ) {
+ return SLAP_CB_CONTINUE;
+ }
+
+ nconns = nwritewaiters = nreadwaiters = 0;
+ for ( c = connection_first( &connindex );
+ c != NULL;
+ c = connection_next( c, &connindex ), nconns++ )
+ {
+ if ( c->c_writewaiter ) {
+ nwritewaiters++;
+ }
+
+ /* FIXME: ?!? */
+ if ( c->c_currentber != NULL ) {
+ nreadwaiters++;
+ }
+ }
+ connection_done(c);
+
+ switch ( i ) {
+ case MONITOR_RWW_READ:
+ num = nreadwaiters;
+ break;
+
+ case MONITOR_RWW_WRITE:
+ num = nwritewaiters;
+ break;
+
+ default:
+ assert( 0 );
+ }
+
+ snprintf( buf, sizeof( buf ), "%ld", num );
+
+ a = attr_find( e->e_attrs, mi->mi_ad_monitorCounter );
+ assert( a != NULL );
+ len = strlen( buf );
+ if ( len > a->a_vals[ 0 ].bv_len ) {
+ a->a_vals[ 0 ].bv_val = ber_memrealloc( a->a_vals[ 0 ].bv_val, len + 1 );
+ if ( BER_BVISNULL( &a->a_vals[ 0 ] ) ) {
+ BER_BVZERO( &a->a_vals[ 0 ] );
+ return SLAP_CB_CONTINUE;
+ }
+ }
+ AC_MEMCPY( a->a_vals[ 0 ].bv_val, buf, len + 1 );
+ a->a_vals[ 0 ].bv_len = len;
+
+ /* FIXME: touch modifyTimestamp? */
+
+ return SLAP_CB_CONTINUE;
+}
+
diff --git a/servers/slapd/back-monitor/search.c b/servers/slapd/back-monitor/search.c
new file mode 100644
index 0000000..adbd623
--- /dev/null
+++ b/servers/slapd/back-monitor/search.c
@@ -0,0 +1,271 @@
+/* search.c - monitor backend search function */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2001-2018 The OpenLDAP Foundation.
+ * Portions Copyright 2001-2003 Pierangelo Masarati.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Pierangelo Masarati for inclusion
+ * in OpenLDAP Software.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "slap.h"
+#include "back-monitor.h"
+#include "proto-back-monitor.h"
+
+static void
+monitor_find_children(
+ Operation *op,
+ SlapReply *rs,
+ Entry *e_parent,
+ Entry **nonv,
+ Entry **vol
+)
+{
+ monitor_entry_t *mp;
+
+ mp = ( monitor_entry_t * )e_parent->e_private;
+ *nonv = mp->mp_children;
+
+ if ( MONITOR_HAS_VOLATILE_CH( mp ) ) {
+ monitor_entry_create( op, rs, NULL, e_parent, vol );
+ }
+}
+
+static int
+monitor_send_children(
+ Operation *op,
+ SlapReply *rs,
+ Entry *e_nonvolatile,
+ Entry *e_ch,
+ int sub )
+{
+ monitor_info_t *mi = ( monitor_info_t * )op->o_bd->be_private;
+ Entry *e,
+ *e_tmp;
+ monitor_entry_t *mp;
+ int rc,
+ nonvolatile = 0;
+
+ e = e_nonvolatile;
+
+ /* no volatile entries? */
+ if ( e_ch == NULL ) {
+ /* no persistent entries? return */
+ if ( e == NULL ) {
+ return LDAP_SUCCESS;
+ }
+
+ /* volatile entries */
+ } else {
+ /* if no persistent, return only volatile */
+ if ( e == NULL ) {
+ e = e_ch;
+
+ /* else append persistent to volatile */
+ } else {
+ e_tmp = e_ch;
+ do {
+ mp = ( monitor_entry_t * )e_tmp->e_private;
+ e_tmp = mp->mp_next;
+
+ if ( e_tmp == NULL ) {
+ mp->mp_next = e;
+ break;
+ }
+ } while ( e_tmp );
+ e = e_ch;
+ }
+ }
+
+ /* return entries */
+ for ( ; e != NULL; e = e_tmp ) {
+ Entry *sub_nv = NULL, *sub_ch = NULL;
+
+ monitor_cache_lock( e );
+ monitor_entry_update( op, rs, e );
+
+ if ( e == e_nonvolatile )
+ nonvolatile = 1;
+
+ mp = ( monitor_entry_t * )e->e_private;
+ e_tmp = mp->mp_next;
+
+ if ( op->o_abandon ) {
+ monitor_cache_release( mi, e );
+ rc = SLAPD_ABANDON;
+ goto freeout;
+ }
+
+ if ( sub )
+ monitor_find_children( op, rs, e, &sub_nv, &sub_ch );
+
+ rc = test_filter( op, e, op->oq_search.rs_filter );
+ if ( rc == LDAP_COMPARE_TRUE ) {
+ rs->sr_entry = e;
+ rs->sr_flags = REP_ENTRY_MUSTRELEASE;
+ rc = send_search_entry( op, rs );
+ if ( rc ) {
+ for ( e = sub_ch; e != NULL; e = sub_nv ) {
+ mp = ( monitor_entry_t * )e->e_private;
+ sub_nv = mp->mp_next;
+ monitor_cache_lock( e );
+ monitor_cache_release( mi, e );
+ }
+ goto freeout;
+ }
+ } else {
+ monitor_cache_release( mi, e );
+ }
+
+ if ( sub ) {
+ rc = monitor_send_children( op, rs, sub_nv, sub_ch, sub );
+ if ( rc ) {
+freeout:
+ if ( nonvolatile == 0 ) {
+ for ( ; e_tmp != NULL; ) {
+ mp = ( monitor_entry_t * )e_tmp->e_private;
+ e = e_tmp;
+ e_tmp = mp->mp_next;
+ monitor_cache_lock( e );
+ monitor_cache_release( mi, e );
+
+ if ( e_tmp == e_nonvolatile ) {
+ break;
+ }
+ }
+ }
+
+ return( rc );
+ }
+ }
+ }
+
+ return LDAP_SUCCESS;
+}
+
+int
+monitor_back_search( Operation *op, SlapReply *rs )
+{
+ monitor_info_t *mi = ( monitor_info_t * )op->o_bd->be_private;
+ int rc = LDAP_SUCCESS;
+ Entry *e = NULL, *matched = NULL;
+ Entry *e_nv = NULL, *e_ch = NULL;
+ slap_mask_t mask;
+
+ Debug( LDAP_DEBUG_TRACE, "=> monitor_back_search\n", 0, 0, 0 );
+
+
+ /* get entry with reader lock */
+ monitor_cache_dn2entry( op, rs, &op->o_req_ndn, &e, &matched );
+ if ( e == NULL ) {
+ rs->sr_err = LDAP_NO_SUCH_OBJECT;
+ if ( matched ) {
+ if ( !access_allowed_mask( op, matched,
+ slap_schema.si_ad_entry,
+ NULL, ACL_DISCLOSE, NULL, NULL ) )
+ {
+ /* do nothing */ ;
+ } else {
+ rs->sr_matched = matched->e_dn;
+ }
+ }
+
+ send_ldap_result( op, rs );
+ if ( matched ) {
+ monitor_cache_release( mi, matched );
+ rs->sr_matched = NULL;
+ }
+
+ return rs->sr_err;
+ }
+
+ /* NOTE: __NEW__ "search" access is required
+ * on searchBase object */
+ if ( !access_allowed_mask( op, e, slap_schema.si_ad_entry,
+ NULL, ACL_SEARCH, NULL, &mask ) )
+ {
+ monitor_cache_release( mi, e );
+
+ if ( !ACL_GRANT( mask, ACL_DISCLOSE ) ) {
+ rs->sr_err = LDAP_NO_SUCH_OBJECT;
+ } else {
+ rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
+ }
+
+ send_ldap_result( op, rs );
+
+ return rs->sr_err;
+ }
+
+ rs->sr_attrs = op->oq_search.rs_attrs;
+ switch ( op->oq_search.rs_scope ) {
+ case LDAP_SCOPE_BASE:
+ monitor_entry_update( op, rs, e );
+ rc = test_filter( op, e, op->oq_search.rs_filter );
+ if ( rc == LDAP_COMPARE_TRUE ) {
+ rs->sr_entry = e;
+ rs->sr_flags = REP_ENTRY_MUSTRELEASE;
+ send_search_entry( op, rs );
+ rs->sr_entry = NULL;
+ } else {
+ monitor_cache_release( mi, e );
+ }
+ rc = LDAP_SUCCESS;
+ break;
+
+ case LDAP_SCOPE_ONELEVEL:
+ case LDAP_SCOPE_SUBORDINATE:
+ monitor_find_children( op, rs, e, &e_nv, &e_ch );
+ monitor_cache_release( mi, e );
+ rc = monitor_send_children( op, rs, e_nv, e_ch,
+ op->oq_search.rs_scope == LDAP_SCOPE_SUBORDINATE );
+ break;
+
+ case LDAP_SCOPE_SUBTREE:
+ monitor_entry_update( op, rs, e );
+ monitor_find_children( op, rs, e, &e_nv, &e_ch );
+ rc = test_filter( op, e, op->oq_search.rs_filter );
+ if ( rc == LDAP_COMPARE_TRUE ) {
+ rs->sr_entry = e;
+ rs->sr_flags = REP_ENTRY_MUSTRELEASE;
+ send_search_entry( op, rs );
+ rs->sr_entry = NULL;
+ } else {
+ monitor_cache_release( mi, e );
+ }
+
+ rc = monitor_send_children( op, rs, e_nv, e_ch, 1 );
+ break;
+
+ default:
+ rc = LDAP_UNWILLING_TO_PERFORM;
+ monitor_cache_release( mi, e );
+ }
+
+ rs->sr_attrs = NULL;
+ rs->sr_err = rc;
+ if ( rs->sr_err != SLAPD_ABANDON ) {
+ send_ldap_result( op, rs );
+ }
+
+ return rs->sr_err;
+}
+
diff --git a/servers/slapd/back-monitor/sent.c b/servers/slapd/back-monitor/sent.c
new file mode 100644
index 0000000..9852ac6
--- /dev/null
+++ b/servers/slapd/back-monitor/sent.c
@@ -0,0 +1,241 @@
+/* sent.c - deal with data sent subsystem */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2001-2018 The OpenLDAP Foundation.
+ * Portions Copyright 2001-2003 Pierangelo Masarati.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Pierangelo Masarati for inclusion
+ * in OpenLDAP Software.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+
+#include "slap.h"
+#include "back-monitor.h"
+
+static int
+monitor_subsys_sent_destroy(
+ BackendDB *be,
+ monitor_subsys_t *ms );
+
+static int
+monitor_subsys_sent_update(
+ Operation *op,
+ SlapReply *rs,
+ Entry *e );
+
+enum {
+ MONITOR_SENT_BYTES = 0,
+ MONITOR_SENT_PDU,
+ MONITOR_SENT_ENTRIES,
+ MONITOR_SENT_REFERRALS,
+
+ MONITOR_SENT_LAST
+};
+
+struct monitor_sent_t {
+ struct berval rdn;
+ struct berval nrdn;
+} monitor_sent[] = {
+ { BER_BVC("cn=Bytes"), BER_BVNULL },
+ { BER_BVC("cn=PDU"), BER_BVNULL },
+ { BER_BVC("cn=Entries"), BER_BVNULL },
+ { BER_BVC("cn=Referrals"), BER_BVNULL },
+ { BER_BVNULL, BER_BVNULL }
+};
+
+int
+monitor_subsys_sent_init(
+ BackendDB *be,
+ monitor_subsys_t *ms )
+{
+ monitor_info_t *mi;
+
+ Entry **ep, *e_sent;
+ monitor_entry_t *mp;
+ int i;
+
+ assert( be != NULL );
+
+ ms->mss_destroy = monitor_subsys_sent_destroy;
+ ms->mss_update = monitor_subsys_sent_update;
+
+ mi = ( monitor_info_t * )be->be_private;
+
+ if ( monitor_cache_get( mi, &ms->mss_ndn, &e_sent ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_sent_init: "
+ "unable to get entry \"%s\"\n",
+ ms->mss_ndn.bv_val, 0, 0 );
+ return( -1 );
+ }
+
+ mp = ( monitor_entry_t * )e_sent->e_private;
+ mp->mp_children = NULL;
+ ep = &mp->mp_children;
+
+ for ( i = 0; i < MONITOR_SENT_LAST; i++ ) {
+ struct berval nrdn, bv;
+ Entry *e;
+
+ e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn,
+ &monitor_sent[i].rdn, mi->mi_oc_monitorCounterObject,
+ NULL, NULL );
+
+ if ( e == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_sent_init: "
+ "unable to create entry \"%s,%s\"\n",
+ monitor_sent[ i ].rdn.bv_val,
+ ms->mss_ndn.bv_val, 0 );
+ return( -1 );
+ }
+
+ /* steal normalized RDN */
+ dnRdn( &e->e_nname, &nrdn );
+ ber_dupbv( &monitor_sent[ i ].nrdn, &nrdn );
+
+ BER_BVSTR( &bv, "0" );
+ attr_merge_one( e, mi->mi_ad_monitorCounter, &bv, NULL );
+
+ mp = monitor_entrypriv_create();
+ if ( mp == NULL ) {
+ return -1;
+ }
+ e->e_private = ( void * )mp;
+ mp->mp_info = ms;
+ mp->mp_flags = ms->mss_flags \
+ | MONITOR_F_SUB | MONITOR_F_PERSISTENT;
+
+ if ( monitor_cache_add( mi, e ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_sent_init: "
+ "unable to add entry \"%s,%s\"\n",
+ monitor_sent[ i ].rdn.bv_val,
+ ms->mss_ndn.bv_val, 0 );
+ return( -1 );
+ }
+
+ *ep = e;
+ ep = &mp->mp_next;
+ }
+
+ monitor_cache_release( mi, e_sent );
+
+ return( 0 );
+}
+
+static int
+monitor_subsys_sent_destroy(
+ BackendDB *be,
+ monitor_subsys_t *ms )
+{
+ int i;
+
+ for ( i = 0; i < MONITOR_SENT_LAST; i++ ) {
+ if ( !BER_BVISNULL( &monitor_sent[ i ].nrdn ) ) {
+ ch_free( monitor_sent[ i ].nrdn.bv_val );
+ }
+ }
+
+ return 0;
+}
+
+static int
+monitor_subsys_sent_update(
+ Operation *op,
+ SlapReply *rs,
+ Entry *e )
+{
+ monitor_info_t *mi = ( monitor_info_t *)op->o_bd->be_private;
+
+ struct berval nrdn;
+ ldap_pvt_mp_t n;
+ Attribute *a;
+ slap_counters_t *sc;
+ int i;
+
+ assert( mi != NULL );
+ assert( e != NULL );
+
+ dnRdn( &e->e_nname, &nrdn );
+
+ for ( i = 0; i < MONITOR_SENT_LAST; i++ ) {
+ if ( dn_match( &nrdn, &monitor_sent[ i ].nrdn ) ) {
+ break;
+ }
+ }
+
+ if ( i == MONITOR_SENT_LAST ) {
+ return SLAP_CB_CONTINUE;
+ }
+
+ ldap_pvt_thread_mutex_lock(&slap_counters.sc_mutex);
+ switch ( i ) {
+ case MONITOR_SENT_ENTRIES:
+ ldap_pvt_mp_init_set( n, slap_counters.sc_entries );
+ for ( sc = slap_counters.sc_next; sc; sc = sc->sc_next ) {
+ ldap_pvt_thread_mutex_lock( &sc->sc_mutex );
+ ldap_pvt_mp_add( n, sc->sc_entries );
+ ldap_pvt_thread_mutex_unlock( &sc->sc_mutex );
+ }
+ break;
+
+ case MONITOR_SENT_REFERRALS:
+ ldap_pvt_mp_init_set( n, slap_counters.sc_refs );
+ for ( sc = slap_counters.sc_next; sc; sc = sc->sc_next ) {
+ ldap_pvt_thread_mutex_lock( &sc->sc_mutex );
+ ldap_pvt_mp_add( n, sc->sc_refs );
+ ldap_pvt_thread_mutex_unlock( &sc->sc_mutex );
+ }
+ break;
+
+ case MONITOR_SENT_PDU:
+ ldap_pvt_mp_init_set( n, slap_counters.sc_pdu );
+ for ( sc = slap_counters.sc_next; sc; sc = sc->sc_next ) {
+ ldap_pvt_thread_mutex_lock( &sc->sc_mutex );
+ ldap_pvt_mp_add( n, sc->sc_pdu );
+ ldap_pvt_thread_mutex_unlock( &sc->sc_mutex );
+ }
+ break;
+
+ case MONITOR_SENT_BYTES:
+ ldap_pvt_mp_init_set( n, slap_counters.sc_bytes );
+ for ( sc = slap_counters.sc_next; sc; sc = sc->sc_next ) {
+ ldap_pvt_thread_mutex_lock( &sc->sc_mutex );
+ ldap_pvt_mp_add( n, sc->sc_bytes );
+ ldap_pvt_thread_mutex_unlock( &sc->sc_mutex );
+ }
+ break;
+
+ default:
+ assert(0);
+ }
+ ldap_pvt_thread_mutex_unlock(&slap_counters.sc_mutex);
+
+ a = attr_find( e->e_attrs, mi->mi_ad_monitorCounter );
+ assert( a != NULL );
+
+ /* NOTE: no minus sign is allowed in the counters... */
+ UI2BV( &a->a_vals[ 0 ], n );
+ ldap_pvt_mp_clear( n );
+
+ /* FIXME: touch modifyTimestamp? */
+
+ return SLAP_CB_CONTINUE;
+}
+
diff --git a/servers/slapd/back-monitor/thread.c b/servers/slapd/back-monitor/thread.c
new file mode 100644
index 0000000..6bc087f
--- /dev/null
+++ b/servers/slapd/back-monitor/thread.c
@@ -0,0 +1,358 @@
+/* thread.c - deal with thread subsystem */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2001-2018 The OpenLDAP Foundation.
+ * Portions Copyright 2001-2003 Pierangelo Masarati.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Pierangelo Masarati for inclusion
+ * in OpenLDAP Software.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+
+#include "slap.h"
+#include "back-monitor.h"
+
+#include <ldap_rq.h>
+
+#ifndef NO_THREADS
+typedef enum {
+ MT_UNKNOWN,
+ MT_RUNQUEUE,
+ MT_TASKLIST,
+
+ MT_LAST
+} monitor_thread_t;
+
+static struct {
+ struct berval rdn;
+ struct berval desc;
+ struct berval nrdn;
+ ldap_pvt_thread_pool_param_t param;
+ monitor_thread_t mt;
+} mt[] = {
+ { BER_BVC( "cn=Max" ),
+ BER_BVC("Maximum number of threads as configured"),
+ BER_BVNULL, LDAP_PVT_THREAD_POOL_PARAM_MAX, MT_UNKNOWN },
+ { BER_BVC( "cn=Max Pending" ),
+ BER_BVC("Maximum number of pending threads"),
+ BER_BVNULL, LDAP_PVT_THREAD_POOL_PARAM_MAX_PENDING, MT_UNKNOWN },
+ { BER_BVC( "cn=Open" ),
+ BER_BVC("Number of open threads"),
+ BER_BVNULL, LDAP_PVT_THREAD_POOL_PARAM_OPEN, MT_UNKNOWN },
+ { BER_BVC( "cn=Starting" ),
+ BER_BVC("Number of threads being started"),
+ BER_BVNULL, LDAP_PVT_THREAD_POOL_PARAM_STARTING, MT_UNKNOWN },
+ { BER_BVC( "cn=Active" ),
+ BER_BVC("Number of active threads"),
+ BER_BVNULL, LDAP_PVT_THREAD_POOL_PARAM_ACTIVE, MT_UNKNOWN },
+ { BER_BVC( "cn=Pending" ),
+ BER_BVC("Number of pending threads"),
+ BER_BVNULL, LDAP_PVT_THREAD_POOL_PARAM_PENDING, MT_UNKNOWN },
+ { BER_BVC( "cn=Backload" ),
+ BER_BVC("Number of active plus pending threads"),
+ BER_BVNULL, LDAP_PVT_THREAD_POOL_PARAM_BACKLOAD, MT_UNKNOWN },
+#if 0 /* not meaningful right now */
+ { BER_BVC( "cn=Active Max" ),
+ BER_BVNULL,
+ BER_BVNULL, LDAP_PVT_THREAD_POOL_PARAM_ACTIVE_MAX, MT_UNKNOWN },
+ { BER_BVC( "cn=Pending Max" ),
+ BER_BVNULL,
+ BER_BVNULL, LDAP_PVT_THREAD_POOL_PARAM_PENDING_MAX, MT_UNKNOWN },
+ { BER_BVC( "cn=Backload Max" ),
+ BER_BVNULL,
+ BER_BVNULL, LDAP_PVT_THREAD_POOL_PARAM_BACKLOAD_MAX,MT_UNKNOWN },
+#endif
+ { BER_BVC( "cn=State" ),
+ BER_BVC("Thread pool state"),
+ BER_BVNULL, LDAP_PVT_THREAD_POOL_PARAM_STATE, MT_UNKNOWN },
+
+ { BER_BVC( "cn=Runqueue" ),
+ BER_BVC("Queue of running threads - besides those handling operations"),
+ BER_BVNULL, LDAP_PVT_THREAD_POOL_PARAM_UNKNOWN, MT_RUNQUEUE },
+ { BER_BVC( "cn=Tasklist" ),
+ BER_BVC("List of running plus standby threads - besides those handling operations"),
+ BER_BVNULL, LDAP_PVT_THREAD_POOL_PARAM_UNKNOWN, MT_TASKLIST },
+
+ { BER_BVNULL }
+};
+
+static int
+monitor_subsys_thread_update(
+ Operation *op,
+ SlapReply *rs,
+ Entry *e );
+#endif /* ! NO_THREADS */
+
+/*
+ * initializes log subentry
+ */
+int
+monitor_subsys_thread_init(
+ BackendDB *be,
+ monitor_subsys_t *ms )
+{
+#ifndef NO_THREADS
+ monitor_info_t *mi;
+ monitor_entry_t *mp;
+ Entry *e, **ep, *e_thread;
+ int i;
+
+ ms->mss_update = monitor_subsys_thread_update;
+
+ mi = ( monitor_info_t * )be->be_private;
+
+ if ( monitor_cache_get( mi, &ms->mss_ndn, &e_thread ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_thread_init: unable to get entry \"%s\"\n",
+ ms->mss_dn.bv_val,
+ 0, 0 );
+ return( -1 );
+ }
+
+ mp = ( monitor_entry_t * )e_thread->e_private;
+ mp->mp_children = NULL;
+ ep = &mp->mp_children;
+
+ for ( i = 0; !BER_BVISNULL( &mt[ i ].rdn ); i++ ) {
+ static char buf[ BACKMONITOR_BUFSIZE ];
+ int count = -1;
+ char *state = NULL;
+ struct berval bv = BER_BVNULL;
+
+ /*
+ * Max
+ */
+ e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn,
+ &mt[ i ].rdn,
+ mi->mi_oc_monitoredObject, NULL, NULL );
+ if ( e == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_thread_init: "
+ "unable to create entry \"%s,%s\"\n",
+ mt[ i ].rdn.bv_val,
+ ms->mss_ndn.bv_val, 0 );
+ return( -1 );
+ }
+
+ /* NOTE: reference to the normalized DN of the entry,
+ * under the assumption it's not modified */
+ dnRdn( &e->e_nname, &mt[ i ].nrdn );
+
+ switch ( mt[ i ].param ) {
+ case LDAP_PVT_THREAD_POOL_PARAM_UNKNOWN:
+ break;
+
+ case LDAP_PVT_THREAD_POOL_PARAM_STATE:
+ if ( ldap_pvt_thread_pool_query( &connection_pool,
+ mt[ i ].param, (void *)&state ) == 0 )
+ {
+ ber_str2bv( state, 0, 0, &bv );
+
+ } else {
+ BER_BVSTR( &bv, "unknown" );
+ }
+ break;
+
+ default:
+ /* NOTE: in case of error, it'll be set to -1 */
+ (void)ldap_pvt_thread_pool_query( &connection_pool,
+ mt[ i ].param, (void *)&count );
+ bv.bv_val = buf;
+ bv.bv_len = snprintf( buf, sizeof( buf ), "%d", count );
+ break;
+ }
+
+ if ( !BER_BVISNULL( &bv ) ) {
+ attr_merge_normalize_one( e, mi->mi_ad_monitoredInfo, &bv, NULL );
+ }
+
+ if ( !BER_BVISNULL( &mt[ i ].desc ) ) {
+ attr_merge_normalize_one( e,
+ slap_schema.si_ad_description,
+ &mt[ i ].desc, NULL );
+ }
+
+ mp = monitor_entrypriv_create();
+ if ( mp == NULL ) {
+ return -1;
+ }
+ e->e_private = ( void * )mp;
+ mp->mp_info = ms;
+ mp->mp_flags = ms->mss_flags \
+ | MONITOR_F_SUB | MONITOR_F_PERSISTENT;
+
+ if ( monitor_cache_add( mi, e ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_thread_init: "
+ "unable to add entry \"%s,%s\"\n",
+ mt[ i ].rdn.bv_val,
+ ms->mss_dn.bv_val, 0 );
+ return( -1 );
+ }
+
+ *ep = e;
+ ep = &mp->mp_next;
+ }
+
+ monitor_cache_release( mi, e_thread );
+
+#endif /* ! NO_THREADS */
+ return( 0 );
+}
+
+#ifndef NO_THREADS
+static int
+monitor_subsys_thread_update(
+ Operation *op,
+ SlapReply *rs,
+ Entry *e )
+{
+ monitor_info_t *mi = ( monitor_info_t * )op->o_bd->be_private;
+ Attribute *a;
+ BerVarray vals = NULL;
+ char buf[ BACKMONITOR_BUFSIZE ];
+ struct berval rdn, bv;
+ int which, i;
+ struct re_s *re;
+ int count = -1;
+ char *state = NULL;
+
+ assert( mi != NULL );
+
+ dnRdn( &e->e_nname, &rdn );
+
+ for ( i = 0; !BER_BVISNULL( &mt[ i ].nrdn ); i++ ) {
+ if ( dn_match( &mt[ i ].nrdn, &rdn ) ) {
+ break;
+ }
+ }
+
+ which = i;
+ if ( BER_BVISNULL( &mt[ which ].nrdn ) ) {
+ return SLAP_CB_CONTINUE;
+ }
+
+ a = attr_find( e->e_attrs, mi->mi_ad_monitoredInfo );
+
+ switch ( mt[ which ].param ) {
+ case LDAP_PVT_THREAD_POOL_PARAM_UNKNOWN:
+ switch ( mt[ which ].mt ) {
+ case MT_RUNQUEUE:
+ if ( a != NULL ) {
+ if ( a->a_nvals != a->a_vals ) {
+ ber_bvarray_free( a->a_nvals );
+ }
+ ber_bvarray_free( a->a_vals );
+ a->a_vals = NULL;
+ a->a_nvals = NULL;
+ a->a_numvals = 0;
+ }
+
+ i = 0;
+ bv.bv_val = buf;
+ ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
+ LDAP_STAILQ_FOREACH( re, &slapd_rq.run_list, rnext ) {
+ bv.bv_len = snprintf( buf, sizeof( buf ), "{%d}%s(%s)",
+ i, re->tname, re->tspec );
+ if ( bv.bv_len < sizeof( buf ) ) {
+ value_add_one( &vals, &bv );
+ }
+ i++;
+ }
+ ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
+
+ if ( vals ) {
+ attr_merge_normalize( e, mi->mi_ad_monitoredInfo, vals, NULL );
+ ber_bvarray_free( vals );
+
+ } else {
+ attr_delete( &e->e_attrs, mi->mi_ad_monitoredInfo );
+ }
+ break;
+
+ case MT_TASKLIST:
+ if ( a != NULL ) {
+ if ( a->a_nvals != a->a_vals ) {
+ ber_bvarray_free( a->a_nvals );
+ }
+ ber_bvarray_free( a->a_vals );
+ a->a_vals = NULL;
+ a->a_nvals = NULL;
+ a->a_numvals = 0;
+ }
+
+ i = 0;
+ bv.bv_val = buf;
+ ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
+ LDAP_STAILQ_FOREACH( re, &slapd_rq.task_list, tnext ) {
+ bv.bv_len = snprintf( buf, sizeof( buf ), "{%d}%s(%s)",
+ i, re->tname, re->tspec );
+ if ( bv.bv_len < sizeof( buf ) ) {
+ value_add_one( &vals, &bv );
+ }
+ i++;
+ }
+ ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
+
+ if ( vals ) {
+ attr_merge_normalize( e, mi->mi_ad_monitoredInfo, vals, NULL );
+ ber_bvarray_free( vals );
+
+ } else {
+ attr_delete( &e->e_attrs, mi->mi_ad_monitoredInfo );
+ }
+ break;
+
+ default:
+ assert( 0 );
+ }
+ break;
+
+ case LDAP_PVT_THREAD_POOL_PARAM_STATE:
+ if ( a == NULL ) {
+ return rs->sr_err = LDAP_OTHER;
+ }
+ if ( ldap_pvt_thread_pool_query( &connection_pool,
+ mt[ i ].param, (void *)&state ) == 0 )
+ {
+ ber_str2bv( state, 0, 0, &bv );
+ ber_bvreplace( &a->a_vals[ 0 ], &bv );
+ }
+ break;
+
+ default:
+ if ( a == NULL ) {
+ return rs->sr_err = LDAP_OTHER;
+ }
+ if ( ldap_pvt_thread_pool_query( &connection_pool,
+ mt[ i ].param, (void *)&count ) == 0 )
+ {
+ bv.bv_val = buf;
+ bv.bv_len = snprintf( buf, sizeof( buf ), "%d", count );
+ if ( bv.bv_len < sizeof( buf ) ) {
+ ber_bvreplace( &a->a_vals[ 0 ], &bv );
+ }
+ }
+ break;
+ }
+
+ /* FIXME: touch modifyTimestamp? */
+
+ return SLAP_CB_CONTINUE;
+}
+#endif /* ! NO_THREADS */
diff --git a/servers/slapd/back-monitor/time.c b/servers/slapd/back-monitor/time.c
new file mode 100644
index 0000000..68cd6ff
--- /dev/null
+++ b/servers/slapd/back-monitor/time.c
@@ -0,0 +1,247 @@
+/* time.c - deal with time subsystem */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2001-2018 The OpenLDAP Foundation.
+ * Portions Copyright 2001-2003 Pierangelo Masarati.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Pierangelo Masarati for inclusion
+ * in OpenLDAP Software.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+#include <ac/time.h>
+
+
+#include "slap.h"
+#include <lutil.h>
+#include "proto-slap.h"
+#include "back-monitor.h"
+
+static int
+monitor_subsys_time_update(
+ Operation *op,
+ SlapReply *rs,
+ Entry *e );
+
+int
+monitor_subsys_time_init(
+ BackendDB *be,
+ monitor_subsys_t *ms )
+{
+ monitor_info_t *mi;
+
+ Entry *e, **ep, *e_time;
+ monitor_entry_t *mp;
+ struct berval bv, value;
+
+ assert( be != NULL );
+
+ ms->mss_update = monitor_subsys_time_update;
+
+ mi = ( monitor_info_t * )be->be_private;
+
+ if ( monitor_cache_get( mi,
+ &ms->mss_ndn, &e_time ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_time_init: "
+ "unable to get entry \"%s\"\n",
+ ms->mss_ndn.bv_val, 0, 0 );
+ return( -1 );
+ }
+
+ mp = ( monitor_entry_t * )e_time->e_private;
+ mp->mp_children = NULL;
+ ep = &mp->mp_children;
+
+ BER_BVSTR( &bv, "cn=Start" );
+ e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, &bv,
+ mi->mi_oc_monitoredObject, NULL, NULL );
+ if ( e == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_time_init: "
+ "unable to create entry \"%s,%s\"\n",
+ bv.bv_val, ms->mss_ndn.bv_val, 0 );
+ return( -1 );
+ }
+ attr_merge_normalize_one( e, mi->mi_ad_monitorTimestamp,
+ &mi->mi_startTime, NULL );
+
+ mp = monitor_entrypriv_create();
+ if ( mp == NULL ) {
+ return -1;
+ }
+ e->e_private = ( void * )mp;
+ mp->mp_info = ms;
+ mp->mp_flags = ms->mss_flags \
+ | MONITOR_F_SUB | MONITOR_F_PERSISTENT;
+
+ if ( monitor_cache_add( mi, e ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_time_init: "
+ "unable to add entry \"%s,%s\"\n",
+ bv.bv_val, ms->mss_ndn.bv_val, 0 );
+ return( -1 );
+ }
+
+ *ep = e;
+ ep = &mp->mp_next;
+
+ /*
+ * Current
+ */
+ BER_BVSTR( &bv, "cn=Current" );
+ e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, &bv,
+ mi->mi_oc_monitoredObject, NULL, NULL );
+ if ( e == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_time_init: "
+ "unable to create entry \"%s,%s\"\n",
+ bv.bv_val, ms->mss_ndn.bv_val, 0 );
+ return( -1 );
+ }
+ attr_merge_normalize_one( e, mi->mi_ad_monitorTimestamp,
+ &mi->mi_startTime, NULL );
+
+ mp = monitor_entrypriv_create();
+ if ( mp == NULL ) {
+ return -1;
+ }
+ e->e_private = ( void * )mp;
+ mp->mp_info = ms;
+ mp->mp_flags = ms->mss_flags \
+ | MONITOR_F_SUB | MONITOR_F_PERSISTENT;
+
+ if ( monitor_cache_add( mi, e ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_time_init: "
+ "unable to add entry \"%s,%s\"\n",
+ bv.bv_val, ms->mss_ndn.bv_val, 0 );
+ return( -1 );
+ }
+
+ *ep = e;
+ ep = &mp->mp_next;
+
+ /*
+ * Uptime
+ */
+ BER_BVSTR( &bv, "cn=Uptime" );
+ e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, &bv,
+ mi->mi_oc_monitoredObject, NULL, NULL );
+ if ( e == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_time_init: "
+ "unable to create entry \"%s,%s\"\n",
+ bv.bv_val, ms->mss_ndn.bv_val, 0 );
+ return( -1 );
+ }
+ BER_BVSTR( &value, "0" );
+ attr_merge_normalize_one( e, mi->mi_ad_monitoredInfo,
+ &value, NULL );
+
+ mp = monitor_entrypriv_create();
+ if ( mp == NULL ) {
+ return -1;
+ }
+ e->e_private = ( void * )mp;
+ mp->mp_info = ms;
+ mp->mp_flags = ms->mss_flags \
+ | MONITOR_F_SUB | MONITOR_F_PERSISTENT;
+
+ if ( monitor_cache_add( mi, e ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "monitor_subsys_time_init: "
+ "unable to add entry \"%s,%s\"\n",
+ bv.bv_val, ms->mss_ndn.bv_val, 0 );
+ return( -1 );
+ }
+
+ *ep = e;
+ ep = &mp->mp_next;
+
+ monitor_cache_release( mi, e_time );
+
+ return( 0 );
+}
+
+static int
+monitor_subsys_time_update(
+ Operation *op,
+ SlapReply *rs,
+ Entry *e )
+{
+ monitor_info_t *mi = ( monitor_info_t * )op->o_bd->be_private;
+ static struct berval bv_current = BER_BVC( "cn=current" ),
+ bv_uptime = BER_BVC( "cn=uptime" );
+ struct berval rdn;
+
+ assert( mi != NULL );
+ assert( e != NULL );
+
+ dnRdn( &e->e_nname, &rdn );
+
+ if ( dn_match( &rdn, &bv_current ) ) {
+ struct tm tm;
+ char tmbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
+ Attribute *a;
+ ber_len_t len;
+ time_t currtime;
+
+ currtime = slap_get_time();
+
+ ldap_pvt_gmtime( &currtime, &tm );
+ lutil_gentime( tmbuf, sizeof( tmbuf ), &tm );
+
+ len = strlen( tmbuf );
+
+ a = attr_find( e->e_attrs, mi->mi_ad_monitorTimestamp );
+ if ( a == NULL ) {
+ return rs->sr_err = LDAP_OTHER;
+ }
+
+ assert( len == a->a_vals[ 0 ].bv_len );
+ AC_MEMCPY( a->a_vals[ 0 ].bv_val, tmbuf, len );
+
+ /* FIXME: touch modifyTimestamp? */
+
+ } else if ( dn_match( &rdn, &bv_uptime ) ) {
+ Attribute *a;
+ double diff;
+ char buf[ BACKMONITOR_BUFSIZE ];
+ struct berval bv;
+
+ a = attr_find( e->e_attrs, mi->mi_ad_monitoredInfo );
+ if ( a == NULL ) {
+ return rs->sr_err = LDAP_OTHER;
+ }
+
+ diff = difftime( slap_get_time(), starttime );
+ bv.bv_len = snprintf( buf, sizeof( buf ), "%lu",
+ (unsigned long) diff );
+ bv.bv_val = buf;
+
+ ber_bvreplace( &a->a_vals[ 0 ], &bv );
+ if ( a->a_nvals != a->a_vals ) {
+ ber_bvreplace( &a->a_nvals[ 0 ], &bv );
+ }
+
+ /* FIXME: touch modifyTimestamp? */
+ }
+
+ return SLAP_CB_CONTINUE;
+}
+