]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldap/monitor.c
ITS#7182 Remove use of monitor_info_t in back-ldap.
[openldap] / servers / slapd / back-ldap / monitor.c
1 /* monitor.c - monitor ldap backend */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2003-2012 The OpenLDAP Foundation.
6  * Portions Copyright 1999-2003 Howard Chu.
7  * Portions Copyright 2000-2003 Pierangelo Masarati.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted only as authorized by the OpenLDAP
12  * Public License.
13  *
14  * A copy of this license is available in the file LICENSE in the
15  * top-level directory of the distribution or, alternatively, at
16  * <http://www.OpenLDAP.org/license.html>.
17  */
18 /* ACKNOWLEDGEMENTS:
19  * This work was initially developed by the Howard Chu for inclusion
20  * in OpenLDAP Software and subsequently enhanced by Pierangelo
21  * Masarati.
22  */
23
24 #include "portable.h"
25
26 #include <stdio.h>
27 #include <ac/string.h>
28 #include <ac/unistd.h>
29 #include <ac/stdlib.h>
30 #include <ac/errno.h>
31 #include <sys/stat.h>
32 #include "lutil.h"
33 #include "back-ldap.h"
34
35 #include "config.h"
36
37 static ObjectClass              *oc_olmLDAPDatabase;
38 static ObjectClass              *oc_olmLDAPConnection;
39
40 static ObjectClass              *oc_monitorContainer;
41 static ObjectClass              *oc_monitorCounterObject;
42
43 static AttributeDescription     *ad_olmDbURIList;
44 static AttributeDescription     *ad_olmDbOperations;
45 static AttributeDescription     *ad_olmDbBoundDN;
46 static AttributeDescription     *ad_olmDbConnFlags;
47 static AttributeDescription     *ad_olmDbConnURI;
48 static AttributeDescription     *ad_olmDbPeerAddress;
49
50 /*
51  * Stolen from back-monitor/operations.c
52  * We don't need the normalized rdn's though.
53  */
54 struct ldap_back_monitor_ops_t {
55         struct berval           rdn;
56 } ldap_back_monitor_op[] = {
57         { BER_BVC( "cn=Bind" ) },
58         { BER_BVC( "cn=Unbind" ) },
59         { BER_BVC( "cn=Search" ) },
60         { BER_BVC( "cn=Compare" ) },
61         { BER_BVC( "cn=Modify" ) },
62         { BER_BVC( "cn=Modrdn" ) },
63         { BER_BVC( "cn=Add" ) },
64         { BER_BVC( "cn=Delete" ) },
65         { BER_BVC( "cn=Abandon" ) },
66         { BER_BVC( "cn=Extended" ) },
67
68         { BER_BVNULL }
69 };
70
71 /* Corresponds to connection flags in back-ldap.h */
72 static struct {
73         unsigned        flag;
74         struct berval   name;
75 }               s_flag[] = {
76         { LDAP_BACK_FCONN_ISBOUND,      BER_BVC( "bound" ) },
77         { LDAP_BACK_FCONN_ISANON,       BER_BVC( "anonymous" ) },
78         { LDAP_BACK_FCONN_ISPRIV,       BER_BVC( "privileged" ) },
79         { LDAP_BACK_FCONN_ISTLS,        BER_BVC( "TLS" ) },
80         { LDAP_BACK_FCONN_BINDING,      BER_BVC( "binding" ) },
81         { LDAP_BACK_FCONN_TAINTED,      BER_BVC( "tainted" ) },
82         { LDAP_BACK_FCONN_ABANDON,      BER_BVC( "abandon" ) },
83         { LDAP_BACK_FCONN_ISIDASR,      BER_BVC( "idassert" ) },
84         { LDAP_BACK_FCONN_CACHED,       BER_BVC( "cached" ) },
85
86         { 0 }
87 };
88
89
90 /*
91  * NOTE: there's some confusion in monitor OID arc;
92  * by now, let's consider:
93  * 
94  * Subsystems monitor attributes        1.3.6.1.4.1.4203.666.1.55.0
95  * Databases monitor attributes         1.3.6.1.4.1.4203.666.1.55.0.1
96  * LDAP database monitor attributes     1.3.6.1.4.1.4203.666.1.55.0.1.2
97  *
98  * Subsystems monitor objectclasses     1.3.6.1.4.1.4203.666.3.16.0
99  * Databases monitor objectclasses      1.3.6.1.4.1.4203.666.3.16.0.1
100  * LDAP database monitor objectclasses  1.3.6.1.4.1.4203.666.3.16.0.1.2
101  */
102
103 static struct {
104         char                    *name;
105         char                    *oid;
106 }               s_oid[] = {
107         { "olmLDAPAttributes",                  "olmDatabaseAttributes:2" },
108         { "olmLDAPObjectClasses",               "olmDatabaseObjectClasses:2" },
109
110         { NULL }
111 };
112
113 static struct {
114         char                    *desc;
115         AttributeDescription    **ad;
116 }               s_at[] = {
117         { "( olmLDAPAttributes:1 "
118                 "NAME ( 'olmDbURIList' ) "
119                 "DESC 'List of URIs a proxy is serving; can be modified run-time' "
120                 "SUP managedInfo )",
121                 &ad_olmDbURIList },
122         { "( olmLDAPAttributes:2 "
123                 "NAME ( 'olmDbOperation' ) "
124                 "DESC 'monitor operations performed' "
125                 "SUP monitorCounter "
126                 "NO-USER-MODIFICATION "
127                 "USAGE dSAOperation )",
128                 &ad_olmDbOperations },
129         { "( olmLDAPAttributes:3 "
130                 "NAME ( 'olmDbBoundDN' ) "
131                 "DESC 'monitor connection authorization DN' "
132                 "SUP monitorConnectionAuthzDN "
133                 "NO-USER-MODIFICATION "
134                 "USAGE dSAOperation )",
135                 &ad_olmDbBoundDN },
136         { "( olmLDAPAttributes:4 "
137                 "NAME ( 'olmDbConnFlags' ) "
138                 "DESC 'monitor connection flags' "
139                 "SUP monitoredInfo "
140                 "NO-USER-MODIFICATION "
141                 "USAGE dSAOperation )",
142                 &ad_olmDbConnFlags },
143         { "( olmLDAPAttributes:5 "
144                 "NAME ( 'olmDbConnURI' ) "
145                 "DESC 'monitor connection URI' "
146                 "SUP monitorConnectionPeerAddress "
147                 "NO-USER-MODIFICATION "
148                 "USAGE dSAOperation )",
149                 &ad_olmDbConnURI },
150         { "( olmLDAPAttributes:6 "
151                 "NAME ( 'olmDbConnPeerAddress' ) "
152                 "DESC 'monitor connection peer address' "
153                 "SUP monitorConnectionPeerAddress "
154                 "NO-USER-MODIFICATION "
155                 "USAGE dSAOperation )",
156                 &ad_olmDbPeerAddress },
157
158         { NULL }
159 };
160
161 static struct {
162         char            *name;
163         ObjectClass     **oc;
164 }               s_moc[] = {
165         { "monitorContainer", &oc_monitorContainer },
166         { "monitorCounterObject", &oc_monitorCounterObject },
167
168         { NULL }
169 };
170
171 static struct {
172         char            *desc;
173         ObjectClass     **oc;
174 }               s_oc[] = {
175         /* augments an existing object, so it must be AUXILIARY
176          * FIXME: derive from some ABSTRACT "monitoredEntity"? */
177         { "( olmLDAPObjectClasses:1 "
178                 "NAME ( 'olmLDAPDatabase' ) "
179                 "SUP top AUXILIARY "
180                 "MAY ( "
181                         "olmDbURIList "
182                         ") )",
183                 &oc_olmLDAPDatabase },
184         { "( olmLDAPObjectClasses:2 "
185                 "NAME ( 'olmLDAPConnection' ) "
186                 "SUP monitorConnection STRUCTURAL "
187                 "MAY ( "
188                         "olmDbBoundDN "
189                         "$ olmDbConnFlags "
190                         "$ olmDbConnURI "
191                         "$ olmDbConnPeerAddress "
192                         ") )",
193                 &oc_olmLDAPConnection },
194
195         { NULL }
196 };
197
198 static int
199 ldap_back_monitor_update(
200         Operation       *op,
201         SlapReply       *rs,
202         Entry           *e,
203         void            *priv )
204 {
205         ldapinfo_t              *li = (ldapinfo_t *)priv;
206
207         Attribute               *a;
208
209         /* update olmDbURIList */
210         a = attr_find( e->e_attrs, ad_olmDbURIList );
211         if ( a != NULL ) {
212                 struct berval   bv;
213
214                 assert( a->a_vals != NULL );
215                 assert( !BER_BVISNULL( &a->a_vals[ 0 ] ) );
216                 assert( BER_BVISNULL( &a->a_vals[ 1 ] ) );
217
218                 ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
219                 if ( li->li_uri ) {
220                         ber_str2bv( li->li_uri, 0, 0, &bv );
221                         if ( !bvmatch( &a->a_vals[ 0 ], &bv ) ) {
222                                 ber_bvreplace( &a->a_vals[ 0 ], &bv );
223                         }
224                 }
225                 ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
226         }
227
228         return SLAP_CB_CONTINUE;
229 }
230
231 static int
232 ldap_back_monitor_modify(
233         Operation       *op,
234         SlapReply       *rs,
235         Entry           *e,
236         void            *priv )
237 {
238         ldapinfo_t              *li = (ldapinfo_t *) priv;
239         
240         Attribute               *save_attrs = NULL;
241         Modifications           *ml,
242                                 *ml_olmDbURIList = NULL;
243         struct berval           ul = BER_BVNULL;
244         int                     got = 0;
245
246         for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
247                 if ( ml->sml_desc == ad_olmDbURIList ) {
248                         if ( ml_olmDbURIList != NULL ) {
249                                 rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
250                                 rs->sr_text = "conflicting modifications";
251                                 goto done;
252                         }
253
254                         if ( ml->sml_op != LDAP_MOD_REPLACE ) {
255                                 rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
256                                 rs->sr_text = "modification not allowed";
257                                 goto done;
258                         }
259
260                         ml_olmDbURIList = ml;
261                         got++;
262                         continue;
263                 }
264         }
265
266         if ( got == 0 ) {
267                 return SLAP_CB_CONTINUE;
268         }
269
270         save_attrs = attrs_dup( e->e_attrs );
271
272         if ( ml_olmDbURIList != NULL ) {
273                 Attribute       *a = NULL;
274                 LDAPURLDesc     *ludlist = NULL;
275                 int             rc;
276
277                 ml = ml_olmDbURIList;
278                 assert( ml->sml_nvalues != NULL );
279
280                 if ( BER_BVISNULL( &ml->sml_nvalues[ 0 ] ) ) {
281                         rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
282                         rs->sr_text = "no value provided";
283                         goto done;
284                 }
285
286                 if ( !BER_BVISNULL( &ml->sml_nvalues[ 1 ] ) ) {
287                         rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
288                         rs->sr_text = "multiple values provided";
289                         goto done;
290                 }
291
292                 rc = ldap_url_parselist_ext( &ludlist,
293                         ml->sml_nvalues[ 0 ].bv_val, NULL,
294                         LDAP_PVT_URL_PARSE_NOEMPTY_HOST
295                                 | LDAP_PVT_URL_PARSE_DEF_PORT );
296                 if ( rc != LDAP_URL_SUCCESS ) {
297                         rs->sr_err = LDAP_INVALID_SYNTAX;
298                         rs->sr_text = "unable to parse URI list";
299                         goto done;
300                 }
301
302                 ul.bv_val = ldap_url_list2urls( ludlist );
303                 ldap_free_urllist( ludlist );
304                 if ( ul.bv_val == NULL ) {
305                         rs->sr_err = LDAP_OTHER;
306                         goto done;
307                 }
308                 ul.bv_len = strlen( ul.bv_val );
309                 
310                 a = attr_find( e->e_attrs, ad_olmDbURIList );
311                 if ( a != NULL ) {
312                         if ( a->a_nvals == a->a_vals ) {
313                                 a->a_nvals = ch_calloc( sizeof( struct berval ), 2 );
314                         }
315
316                         ber_bvreplace( &a->a_vals[ 0 ], &ul );
317                         ber_bvreplace( &a->a_nvals[ 0 ], &ul );
318
319                 } else {
320                         attr_merge_normalize_one( e, ad_olmDbURIList, &ul, NULL );
321                 }
322         }
323
324         /* apply changes */
325         if ( !BER_BVISNULL( &ul ) ) {
326                 ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
327                 if ( li->li_uri ) {
328                         ch_free( li->li_uri );
329                 }
330                 li->li_uri = ul.bv_val;
331                 ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
332
333                 BER_BVZERO( &ul );
334         }
335
336 done:;
337         if ( !BER_BVISNULL( &ul ) ) {
338                 ldap_memfree( ul.bv_val );
339         }
340
341         if ( rs->sr_err == LDAP_SUCCESS ) {
342                 attrs_free( save_attrs );
343                 return SLAP_CB_CONTINUE;
344         }
345
346         attrs_free( e->e_attrs );
347         e->e_attrs = save_attrs;
348
349         return rs->sr_err;
350 }
351
352 static int
353 ldap_back_monitor_free(
354         Entry           *e,
355         void            **priv )
356 {
357         ldapinfo_t              *li = (ldapinfo_t *)(*priv);
358
359         *priv = NULL;
360
361         if ( !slapd_shutdown ) {
362                 memset( &li->li_monitor_info, 0, sizeof( li->li_monitor_info ) );
363         }
364
365         return SLAP_CB_CONTINUE;
366 }
367
368 static int
369 ldap_back_monitor_subsystem_destroy(
370         BackendDB               *be,
371         monitor_subsys_t        *ms)
372 {
373         free(ms->mss_dn.bv_val);
374         BER_BVZERO(&ms->mss_dn);
375
376         free(ms->mss_ndn.bv_val);
377         BER_BVZERO(&ms->mss_ndn);
378
379         return LDAP_SUCCESS;
380 }
381
382 /*
383  * Connection monitoring subsystem:
384  * Tries to mimick what the cn=connections,cn=monitor subsystem does
385  * by creating volatile entries for each connection and populating them
386  * according to the information attached to the connection.
387  * At this moment the only exposed information is the DN used to bind it.
388  * Also note that the connection IDs are not and probably never will be
389  * stable.
390  */
391
392 struct ldap_back_monitor_conn_arg {
393         Operation *op;
394         monitor_subsys_t *ms;
395         Entry **ep;
396 };
397
398 /* code stolen from daemon.c */
399 static int
400 ldap_back_monitor_conn_peername(
401         LDAP            *ld,
402         struct berval   *bv)
403 {
404         Sockbuf *sockbuf;
405         ber_socket_t socket;
406         Sockaddr sa;
407         socklen_t salen = sizeof(sa);
408         const char *peeraddr = NULL;
409         /* we assume INET6_ADDRSTRLEN > INET_ADDRSTRLEN */
410         char addr[INET6_ADDRSTRLEN];
411 #ifdef LDAP_PF_LOCAL
412         char peername[MAXPATHLEN + sizeof("PATH=")];
413 #elif defined(LDAP_PF_INET6)
414         char peername[sizeof("IP=[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]:65535")];
415 #else /* ! LDAP_PF_LOCAL && ! LDAP_PF_INET6 */
416         char peername[sizeof("IP=255.255.255.255:65336")];
417 #endif /* LDAP_PF_LOCAL */
418
419         assert( bv != NULL );
420
421         ldap_get_option( ld, LDAP_OPT_SOCKBUF, (void **)&sockbuf );
422         ber_sockbuf_ctrl( sockbuf, LBER_SB_OPT_GET_FD, &socket );
423         getpeername( socket, (struct sockaddr *)&sa, &salen );
424
425         switch ( sa.sa_addr.sa_family ) {
426 #ifdef LDAP_PF_LOCAL
427                 case AF_LOCAL:
428                         sprintf( peername, "PATH=%s", sa.sa_un_addr.sun_path );
429                         break;
430 #endif /* LDAP_PF_LOCAL */
431
432 #ifdef LDAP_PF_INET6
433                 case AF_INET6:
434                         if ( IN6_IS_ADDR_V4MAPPED(&sa.sa_in6_addr.sin6_addr) ) {
435 #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP )
436                                 peeraddr = inet_ntop( AF_INET,
437                                                 ((struct in_addr *)&sa.sa_in6_addr.sin6_addr.s6_addr[12]),
438                                                 addr, sizeof(addr) );
439 #else /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */
440                                 peeraddr = inet_ntoa( *((struct in_addr *)
441                                                         &sa.sa_in6_addr.sin6_addr.s6_addr[12]) );
442 #endif /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */
443                                 if ( !peeraddr ) peeraddr = SLAP_STRING_UNKNOWN;
444                                 sprintf( peername, "IP=%s:%d", peeraddr,
445                                                 (unsigned) ntohs( sa.sa_in6_addr.sin6_port ) );
446                         } else {
447                                 peeraddr = inet_ntop( AF_INET6,
448                                                 &sa.sa_in6_addr.sin6_addr,
449                                                 addr, sizeof addr );
450                                 if ( !peeraddr ) peeraddr = SLAP_STRING_UNKNOWN;
451                                 sprintf( peername, "IP=[%s]:%d", peeraddr,
452                                                 (unsigned) ntohs( sa.sa_in6_addr.sin6_port ) );
453                         }
454                         break;
455 #endif /* LDAP_PF_INET6 */
456
457                 case AF_INET: {
458 #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP )
459                                       peeraddr = inet_ntop( AF_INET, &sa.sa_in_addr.sin_addr,
460                                                       addr, sizeof(addr) );
461 #else /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */
462                                       peeraddr = inet_ntoa( sa.sa_in_addr.sin_addr );
463 #endif /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */
464                                       if ( !peeraddr ) peeraddr = SLAP_STRING_UNKNOWN;
465                                       sprintf( peername, "IP=%s:%d", peeraddr,
466                                                       (unsigned) ntohs( sa.sa_in_addr.sin_port ) );
467                               } break;
468
469                 default:
470                               sprintf( peername, SLAP_STRING_UNKNOWN );
471         }
472
473         ber_str2bv( peername, 0, 1, bv );
474         return LDAP_SUCCESS;
475 }
476
477 static int
478 ldap_back_monitor_conn_entry(
479         ldapconn_t *lc,
480         struct ldap_back_monitor_conn_arg *arg )
481 {
482         Entry *e;
483         monitor_entry_t         *mp;
484         monitor_extra_t *mbe;
485         char buf[SLAP_TEXT_BUFLEN];
486         char *ptr;
487         struct berval bv, dn, ndn;
488         int i;
489
490         e = entry_alloc();
491
492         bv.bv_val = buf;
493         bv.bv_len = snprintf( bv.bv_val, SLAP_TEXT_BUFLEN,
494                 "cn=Connection %lu", lc->lc_connid );
495
496         build_new_dn( &dn, &arg->ms->mss_dn, &bv, NULL );
497         build_new_dn( &ndn, &arg->ms->mss_ndn, &bv, NULL );
498
499         e->e_name = dn;
500         e->e_nname = ndn;
501
502         bv.bv_val += 3;
503         bv.bv_len -= 3;
504         attr_merge_normalize_one( e, slap_schema.si_ad_cn, &bv, NULL );
505
506         BER_BVSTR( &bv, "monitorContainer" );
507         attr_merge_normalize_one( e, slap_schema.si_ad_objectClass, &bv, NULL );
508
509         attr_merge_normalize_one( e, ad_olmDbBoundDN, &lc->lc_bound_ndn, NULL );
510
511         for ( i = 0; s_flag[i].flag; i++ )
512         {
513                 if ( lc->lc_flags & s_flag[i].flag )
514                 {
515                         attr_merge_normalize_one( e, ad_olmDbConnFlags, &s_flag[i].name, NULL );
516                 }
517         }
518
519         ldap_get_option( lc->lc_ld, LDAP_OPT_URI, &bv.bv_val );
520         ptr = strchr( bv.bv_val, ' ' );
521         bv.bv_len = ptr ? ptr - bv.bv_val : strlen(bv.bv_val);
522         attr_merge_normalize_one( e, ad_olmDbConnURI, &bv, NULL );
523         ch_free( bv.bv_val );
524
525         ldap_back_monitor_conn_peername( lc->lc_ld, &bv );
526         attr_merge_normalize_one( e, ad_olmDbPeerAddress, &bv, NULL );
527         ch_free( bv.bv_val );
528
529         mbe = (monitor_extra_t *) arg->op->o_bd->bd_info->bi_extra;
530         mp = mbe->entrypriv_create();
531         e->e_private = mp;
532         mp->mp_info = arg->ms;
533         mp->mp_flags = MONITOR_F_SUB | MONITOR_F_VOLATILE;
534
535         *arg->ep = e;
536         arg->ep = &mp->mp_next;
537
538         return 0;
539 }
540
541 static int
542 ldap_back_monitor_conn_create(
543         Operation       *op,
544         SlapReply       *rs,
545         struct berval   *ndn,
546         Entry           *e_parent,
547         Entry           **ep )
548 {
549         monitor_entry_t         *mp_parent;
550         monitor_subsys_t        *ms;
551         ldapinfo_t              *li;
552         ldapconn_t              *lc;
553
554         struct ldap_back_monitor_conn_arg *arg;
555         int conn_type;
556
557         assert( e_parent->e_private != NULL );
558
559         mp_parent = e_parent->e_private;
560         ms = (monitor_subsys_t *)mp_parent->mp_info;
561         li = (ldapinfo_t *)ms->mss_private;
562
563         arg = ch_calloc( 1, sizeof(struct ldap_back_monitor_conn_arg) );
564         arg->op = op;
565         arg->ep = ep;
566         arg->ms = ms;
567
568         for ( conn_type = LDAP_BACK_PCONN_FIRST;
569                 conn_type < LDAP_BACK_PCONN_LAST;
570                 conn_type++ )
571         {
572                 LDAP_TAILQ_FOREACH( lc,
573                         &li->li_conn_priv[ conn_type ].lic_priv,
574                         lc_q )
575                 {
576                         ldap_back_monitor_conn_entry( lc, arg );
577                 }
578         }
579
580         avl_apply( li->li_conninfo.lai_tree, (AVL_APPLY)ldap_back_monitor_conn_entry,
581                 arg, -1, AVL_INORDER );
582
583         ch_free( arg );
584
585         return 0;
586 }
587
588 static int
589 ldap_back_monitor_conn_init(
590         BackendDB               *be,
591         monitor_subsys_t        *ms )
592 {
593         ldapinfo_t      *li = (ldapinfo_t *) ms->mss_private;
594         monitor_extra_t *mbe;
595
596         Entry           *e;
597         int             rc;
598
599         assert( be != NULL );
600         mbe = (monitor_extra_t *) be->bd_info->bi_extra;
601
602         ms->mss_dn = ms->mss_ndn = li->li_monitor_info.lmi_ndn;
603         ms->mss_rdn = li->li_monitor_info.lmi_conn_rdn;
604         ms->mss_create = ldap_back_monitor_conn_create;
605         ms->mss_destroy = ldap_back_monitor_subsystem_destroy;
606
607         e = mbe->entry_stub( &ms->mss_dn, &ms->mss_ndn,
608                 &ms->mss_rdn, oc_monitorContainer, NULL, NULL );
609         if ( e == NULL ) {
610                 Debug( LDAP_DEBUG_ANY,
611                         "ldap_back_monitor_conn_init: "
612                         "unable to create entry \"%s,%s\"\n",
613                         li->li_monitor_info.lmi_conn_rdn.bv_val,
614                         ms->mss_ndn.bv_val, 0 );
615                 return( -1 );
616         }
617
618         ber_dupbv( &ms->mss_dn, &e->e_name );
619         ber_dupbv( &ms->mss_ndn, &e->e_nname );
620
621         rc = mbe->register_entry( e, NULL, ms, MONITOR_F_VOLATILE_CH );
622
623         /* add labeledURI and special, modifiable URI value */
624         if ( rc == LDAP_SUCCESS && li->li_uri != NULL ) {
625                 struct berval           bv;
626                 Attribute               *a;
627                 LDAPURLDesc             *ludlist = NULL;
628                 monitor_callback_t      *cb = NULL;
629
630                 a = attr_alloc( ad_olmDbURIList );
631
632                 ber_str2bv( li->li_uri, 0, 0, &bv );
633                 attr_valadd( a, &bv, NULL, 1 );
634                 attr_normalize( a->a_desc, a->a_vals, &a->a_nvals, NULL );
635
636                 rc = ldap_url_parselist_ext( &ludlist,
637                         li->li_uri, NULL,
638                         LDAP_PVT_URL_PARSE_NOEMPTY_HOST
639                                 | LDAP_PVT_URL_PARSE_DEF_PORT );
640                 if ( rc != LDAP_URL_SUCCESS ) {
641                         Debug( LDAP_DEBUG_ANY,
642                                 "ldap_back_monitor_db_open: "
643                                 "unable to parse URI list (ignored)\n",
644                                 0, 0, 0 );
645                 } else {
646                         Attribute *a2 = attr_alloc( slap_schema.si_ad_labeledURI );
647
648                         a->a_next = a2;
649
650                         for ( ; ludlist != NULL; ) {
651                                 LDAPURLDesc     *next = ludlist->lud_next;
652
653                                 bv.bv_val = ldap_url_desc2str( ludlist );
654                                 assert( bv.bv_val != NULL );
655                                 ldap_free_urldesc( ludlist );
656                                 bv.bv_len = strlen( bv.bv_val );
657                                 attr_valadd( a2, &bv, NULL, 1 );
658                                 ch_free( bv.bv_val );
659
660                                 ludlist = next;
661                         }
662
663                         attr_normalize( a2->a_desc, a2->a_vals, &a2->a_nvals, NULL );
664                 }
665
666                 cb = ch_calloc( sizeof( monitor_callback_t ), 1 );
667                 cb->mc_update = ldap_back_monitor_update;
668                 cb->mc_modify = ldap_back_monitor_modify;
669                 cb->mc_free = ldap_back_monitor_free;
670                 cb->mc_private = (void *)li;
671
672                 rc = mbe->register_entry_attrs( &ms->mss_ndn, a, cb, NULL, -1, NULL );
673
674                 attr_free( a->a_next );
675                 attr_free( a );
676
677                 if ( rc != LDAP_SUCCESS )
678                 {
679                         ch_free( cb );
680                 }
681         }
682
683         entry_free( e );
684
685         return rc;
686 }
687
688 /*
689  * Operation monitoring subsystem:
690  * Looks a lot like the cn=operations,cn=monitor subsystem except that at this
691  * moment, only completed operations are counted. Each entry has a separate
692  * callback with all the needed information linked there in the structure
693  * below so that the callback need not locate it over and over again.
694  */
695
696 struct ldap_back_monitor_op_counter {
697         ldap_pvt_mp_t           *data;
698         ldap_pvt_thread_mutex_t *mutex;
699 };
700
701 static void
702 ldap_back_monitor_ops_dispose(
703         void    **priv)
704 {
705         struct ldap_back_monitor_op_counter *counter = *priv;
706
707         ch_free( counter );
708         counter = NULL;
709 }
710
711 static int
712 ldap_back_monitor_ops_free(
713         Entry *e,
714         void **priv)
715 {
716         ldap_back_monitor_ops_dispose( priv );
717         return LDAP_SUCCESS;
718 }
719
720 static int
721 ldap_back_monitor_ops_update(
722         Operation       *op,
723         SlapReply       *rs,
724         Entry           *e,
725         void            *priv )
726 {
727         struct ldap_back_monitor_op_counter *counter = priv;
728         Attribute *a;
729
730         /*TODO
731          * what about initiated/completed?
732          */
733         a = attr_find( e->e_attrs, ad_olmDbOperations );
734         assert( a != NULL );
735
736         ldap_pvt_thread_mutex_lock( counter->mutex );
737         UI2BV( &a->a_vals[ 0 ], *counter->data );
738         ldap_pvt_thread_mutex_unlock( counter->mutex );
739
740         return SLAP_CB_CONTINUE;
741 }
742
743 static int
744 ldap_back_monitor_ops_init(
745         BackendDB               *be,
746         monitor_subsys_t        *ms )
747 {
748         ldapinfo_t      *li = (ldapinfo_t *) ms->mss_private;
749
750         monitor_extra_t *mbe;
751         Entry           *e, *parent;
752         int             rc;
753         slap_op_t       op;
754         struct berval   value = BER_BVC( "0" );
755
756         assert( be != NULL );
757
758         mbe = (monitor_extra_t *) be->bd_info->bi_extra;
759
760         ms->mss_dn = ms->mss_ndn = li->li_monitor_info.lmi_ndn;
761         ms->mss_rdn = li->li_monitor_info.lmi_ops_rdn;
762         ms->mss_destroy = ldap_back_monitor_subsystem_destroy;
763
764         parent = mbe->entry_stub( &ms->mss_dn, &ms->mss_ndn,
765                 &ms->mss_rdn, oc_monitorContainer, NULL, NULL );
766         if ( parent == NULL ) {
767                 Debug( LDAP_DEBUG_ANY,
768                         "ldap_back_monitor_ops_init: "
769                         "unable to create entry \"%s,%s\"\n",
770                         li->li_monitor_info.lmi_ops_rdn.bv_val,
771                         ms->mss_ndn.bv_val, 0 );
772                 return( -1 );
773         }
774
775         ber_dupbv( &ms->mss_dn, &parent->e_name );
776         ber_dupbv( &ms->mss_ndn, &parent->e_nname );
777
778         rc = mbe->register_entry( parent, NULL, ms, MONITOR_F_PERSISTENT_CH );
779         if ( rc != LDAP_SUCCESS )
780         {
781                 Debug( LDAP_DEBUG_ANY,
782                         "ldap_back_monitor_ops_init: "
783                         "unable to register entry \"%s\" for monitoring\n",
784                         parent->e_name.bv_val, 0, 0 );
785                 goto done;
786         }
787
788         for ( op = 0; op < SLAP_OP_LAST; op++ )
789         {
790                 monitor_callback_t *cb;
791                 struct ldap_back_monitor_op_counter *counter;
792
793                 e = mbe->entry_stub( &parent->e_name, &parent->e_nname,
794                         &ldap_back_monitor_op[op].rdn,
795                         oc_monitorCounterObject, NULL, NULL );
796                 if ( e == NULL ) {
797                         Debug( LDAP_DEBUG_ANY,
798                                 "ldap_back_monitor_ops_init: "
799                                 "unable to create entry \"%s,%s\"\n",
800                                 ldap_back_monitor_op[op].rdn.bv_val,
801                                 parent->e_nname.bv_val, 0 );
802                         return( -1 );
803                 }
804
805                 attr_merge_normalize_one( e, ad_olmDbOperations, &value, NULL );
806
807                 counter = ch_malloc( sizeof( struct ldap_back_monitor_op_counter ) );
808                 counter->data = &li->li_ops_completed[ op ];
809                 counter->mutex = &li->li_counter_mutex;
810
811                 /*
812                  * We cannot share a single callback between entries.
813                  *
814                  * monitor_cache_destroy() tries to free all callbacks and it's called
815                  * before mss_destroy() so we have no chance of handling it ourselves
816                  */
817                 cb = ch_calloc( sizeof( monitor_callback_t ), 1 );
818                 cb->mc_update = ldap_back_monitor_ops_update;
819                 cb->mc_free = ldap_back_monitor_ops_free;
820                 cb->mc_dispose = ldap_back_monitor_ops_dispose;
821                 cb->mc_private = (void *)counter;
822
823                 rc = mbe->register_entry( e, cb, ms, 0 );
824
825                 /* TODO: register_entry has stored a duplicate so we might actually reuse it
826                  * instead of recreating it every time... */
827                 entry_free( e );
828
829                 if ( rc != LDAP_SUCCESS )
830                 {
831                         Debug( LDAP_DEBUG_ANY,
832                                 "ldap_back_monitor_ops_init: "
833                                 "unable to register entry \"%s\" for monitoring\n",
834                                 e->e_name.bv_val, 0, 0 );
835                         ch_free( cb );
836                         break;
837                 }
838         }
839
840 done:
841         entry_free( parent );
842
843         return rc;
844 }
845
846 /*
847  * call from within ldap_back_initialize()
848  */
849 static int
850 ldap_back_monitor_initialize( void )
851 {
852         int             i, code;
853         ConfigArgs c;
854         char    *argv[ 3 ];
855
856         static int      ldap_back_monitor_initialized = 0;
857
858         /* set to 0 when successfully initialized; otherwise, remember failure */
859         static int      ldap_back_monitor_initialized_failure = 1;
860
861         /* register schema here; if compiled as dynamic object,
862          * must be loaded __after__ back_monitor.la */
863
864         if ( ldap_back_monitor_initialized++ ) {
865                 return ldap_back_monitor_initialized_failure;
866         }
867
868         if ( backend_info( "monitor" ) == NULL ) {
869                 return -1;
870         }
871
872         argv[ 0 ] = "back-ldap monitor";
873         c.argv = argv;
874         c.argc = 3;
875         c.fname = argv[0];
876         for ( i = 0; s_oid[ i ].name; i++ ) {
877         
878                 argv[ 1 ] = s_oid[ i ].name;
879                 argv[ 2 ] = s_oid[ i ].oid;
880
881                 if ( parse_oidm( &c, 0, NULL ) != 0 ) {
882                         Debug( LDAP_DEBUG_ANY,
883                                 "ldap_back_monitor_initialize: unable to add "
884                                 "objectIdentifier \"%s=%s\"\n",
885                                 s_oid[ i ].name, s_oid[ i ].oid, 0 );
886                         return 2;
887                 }
888         }
889
890         for ( i = 0; s_at[ i ].desc != NULL; i++ ) {
891                 code = register_at( s_at[ i ].desc, s_at[ i ].ad, 1 );
892                 if ( code != LDAP_SUCCESS ) {
893                         Debug( LDAP_DEBUG_ANY,
894                                 "ldap_back_monitor_initialize: register_at failed for attributeType (%s)\n",
895                                 s_at[ i ].desc, 0, 0 );
896                         return 3;
897
898                 } else {
899                         (*s_at[ i ].ad)->ad_type->sat_flags |= SLAP_AT_HIDE;
900                 }
901         }
902
903         for ( i = 0; s_oc[ i ].desc != NULL; i++ ) {
904                 code = register_oc( s_oc[ i ].desc, s_oc[ i ].oc, 1 );
905                 if ( code != LDAP_SUCCESS ) {
906                         Debug( LDAP_DEBUG_ANY,
907                                 "ldap_back_monitor_initialize: register_oc failed for objectClass (%s)\n",
908                                 s_oc[ i ].desc, 0, 0 );
909                         return 4;
910
911                 } else {
912                         (*s_oc[ i ].oc)->soc_flags |= SLAP_OC_HIDE;
913                 }
914         }
915
916         for ( i = 0; s_moc[ i ].name != NULL; i++ ) {
917                 *s_moc[i].oc = oc_find( s_moc[ i ].name );
918                 if ( ! *s_moc[i].oc ) {
919                         Debug( LDAP_DEBUG_ANY,
920                                 "ldap_back_monitor_initialize: failed to find objectClass (%s)\n",
921                                 s_moc[ i ].name, 0, 0 );
922                         return 5;
923
924                 }
925         }
926
927         return ( ldap_back_monitor_initialized_failure = LDAP_SUCCESS );
928 }
929
930 /*
931  * call from within ldap_back_db_init()
932  */
933 int
934 ldap_back_monitor_db_init( BackendDB *be )
935 {
936         int     rc;
937
938         rc = ldap_back_monitor_initialize();
939         if ( rc != LDAP_SUCCESS ) {
940                 return rc;
941         }
942
943 #if 0   /* uncomment to turn monitoring on by default */
944         SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_MONITORING;
945 #endif
946
947         return 0;
948 }
949
950 /*
951  * call from within ldap_back_db_open()
952  */
953 int
954 ldap_back_monitor_db_open( BackendDB *be )
955 {
956         ldapinfo_t              *li = (ldapinfo_t *) be->be_private;
957         monitor_subsys_t        *mss = li->li_monitor_info.lmi_mss;
958         int                     rc = 0;
959         BackendInfo             *mi;
960         monitor_extra_t         *mbe;
961
962         if ( !SLAP_DBMONITORING( be ) ) {
963                 return 0;
964         }
965
966         /* check if monitor is configured and usable */
967         mi = backend_info( "monitor" );
968         if ( !mi || !mi->bi_extra ) {
969                 SLAP_DBFLAGS( be ) ^= SLAP_DBFLAG_MONITORING;
970                 return 0;
971         }
972         mbe = mi->bi_extra;
973
974         /* don't bother if monitor is not configured */
975         if ( !mbe->is_configured() ) {
976                 static int warning = 0;
977
978                 if ( warning++ == 0 ) {
979                         Debug( LDAP_DEBUG_ANY, "ldap_back_monitor_db_open: "
980                                 "monitoring disabled; "
981                                 "configure monitor database to enable\n",
982                                 0, 0, 0 );
983                 }
984
985                 return 0;
986         }
987
988         /* caller (e.g. an overlay based on back-ldap) may want to use
989          * a different DN and RDNs... */
990         if ( BER_BVISNULL( &li->li_monitor_info.lmi_ndn ) ) {
991                 rc = mbe->register_database( be, &li->li_monitor_info.lmi_ndn );
992                 if ( rc != 0 ) {
993                         Debug( LDAP_DEBUG_ANY, "ldap_back_monitor_db_open: "
994                                 "failed to register the databse with back-monitor\n",
995                                 0, 0, 0 );
996                 }
997         }
998         if ( BER_BVISNULL( &li->li_monitor_info.lmi_conn_rdn ) ) {
999                 ber_str2bv( "cn=Connections", 0, 1,
1000                         &li->li_monitor_info.lmi_conn_rdn );
1001         }
1002         if ( BER_BVISNULL( &li->li_monitor_info.lmi_ops_rdn ) ) {
1003                 ber_str2bv( "cn=Operations", 0, 1,
1004                         &li->li_monitor_info.lmi_ops_rdn );
1005         }
1006
1007         /* set up the subsystems used to create the operation and
1008          * volatile connection entries */
1009
1010         mss->mss_name = "back-ldap connections";
1011         mss->mss_flags = MONITOR_F_VOLATILE_CH;
1012         mss->mss_open = ldap_back_monitor_conn_init;
1013         mss->mss_private = li;
1014
1015         if ( mbe->register_subsys_late( mss ) )
1016         {
1017                 Debug( LDAP_DEBUG_ANY,
1018                         "ldap_back_monitor_db_open: "
1019                         "failed to register connection subsystem", 0, 0, 0 );
1020                 return -1;
1021         }
1022
1023         mss++;
1024
1025         mss->mss_name = "back-ldap operations";
1026         mss->mss_flags = MONITOR_F_PERSISTENT_CH;
1027         mss->mss_open = ldap_back_monitor_ops_init;
1028         mss->mss_private = li;
1029
1030         if ( mbe->register_subsys_late( mss ) )
1031         {
1032                 Debug( LDAP_DEBUG_ANY,
1033                         "ldap_back_monitor_db_open: "
1034                         "failed to register operation subsystem", 0, 0, 0 );
1035                 return -1;
1036         }
1037
1038         return rc;
1039 }
1040
1041 /*
1042  * call from within ldap_back_db_close()
1043  */
1044 int
1045 ldap_back_monitor_db_close( BackendDB *be )
1046 {
1047         ldapinfo_t              *li = (ldapinfo_t *) be->be_private;
1048
1049         if ( li && !BER_BVISNULL( &li->li_monitor_info.lmi_ndn ) ) {
1050                 BackendInfo             *mi;
1051                 monitor_extra_t         *mbe;
1052
1053                 /* check if monitor is configured and usable */
1054                 mi = backend_info( "monitor" );
1055                 if ( mi && mi->bi_extra ) {
1056                         mbe = mi->bi_extra;
1057
1058                         /*TODO
1059                          * Unregister all entries our subsystems have created.
1060                          * Will only really be necessary when
1061                          * SLAPD_CONFIG_DELETE is enabled.
1062                          *
1063                          * Might need a way to unregister subsystems instead.
1064                          */
1065                 }
1066         }
1067
1068         return 0;
1069 }
1070
1071 /*
1072  * call from within ldap_back_db_destroy()
1073  */
1074 int
1075 ldap_back_monitor_db_destroy( BackendDB *be )
1076 {
1077         ldapinfo_t              *li = (ldapinfo_t *) be->be_private;
1078
1079         if ( li ) {
1080                 memset( &li->li_monitor_info, 0, sizeof( li->li_monitor_info ) );
1081         }
1082
1083         return 0;
1084 }
1085