diff options
Diffstat (limited to 'servers/slapd/back-monitor')
23 files changed, 8558 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..0de9b5b --- /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-2021 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..3e705f3 --- /dev/null +++ b/servers/slapd/back-monitor/back-monitor.h @@ -0,0 +1,325 @@ +/* back-monitor.h - ldap monitor back-end header file */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2001-2021 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 */ + void *mp_private; +} 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..19c5451 --- /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-2021 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..7994955 --- /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-2021 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..71e06a1 --- /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-2021 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..aeb6115 --- /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-2021 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..64167c9 --- /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-2021 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, ¤t_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..0c6a7b9 --- /dev/null +++ b/servers/slapd/back-monitor/database.c @@ -0,0 +1,1031 @@ +/* database.c - deals with database subsystem */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2001-2021 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; + mp->mp_private = be; + + 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++ ) { + mp = ( monitor_entry_t * )(*ep)->e_private; + + assert( mp != NULL ); + if ( mp->mp_private == be->bd_self ) { + rc = 0; + goto done; + } + 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..2b7ba03 --- /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-2021 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..1629849 --- /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-2021 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..fdc6943 --- /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-2021 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..7f88df0 --- /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-2021 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..6c2c9b9 --- /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-2021 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..c9ebb85 --- /dev/null +++ b/servers/slapd/back-monitor/operation.c @@ -0,0 +1,245 @@ +/* operation.c - deal with operation subsystem */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2001-2021 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 ); + ldap_pvt_mp_add( nInitiated, slap_counters.sc_ops_initiated ); + ldap_pvt_mp_add( nCompleted, slap_counters.sc_ops_completed ); + 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 ); + ldap_pvt_mp_add( nCompleted, sc->sc_ops_completed ); + 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..2794fcf --- /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-2021 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..e2e8fab --- /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-2021 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..6b6809e --- /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-2021 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..cfe3a54 --- /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-2021 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..bf00965 --- /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-2021 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..8d4b74c --- /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-2021 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..b3f05de --- /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-2021 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..5e1fc45 --- /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-2021 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; +} + |