]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldap/monitor.c
Merge remote-tracking branch 'origin/mdb.RE/0.9'
[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-2015 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 = arg->op->o_bd->bd_info->bi_extra;
485         char buf[SLAP_TEXT_BUFLEN];
486         char *ptr;
487         struct berval bv;
488         int i;
489
490         bv.bv_val = buf;
491         bv.bv_len = snprintf( bv.bv_val, SLAP_TEXT_BUFLEN,
492                 "cn=Connection %lu", lc->lc_connid );
493
494         e = mbe->entry_stub( &arg->ms->mss_dn, &arg->ms->mss_ndn, &bv,
495                 oc_monitorContainer, NULL, NULL );
496
497         attr_merge_normalize_one( e, ad_olmDbBoundDN, &lc->lc_bound_ndn, NULL );
498
499         for ( i = 0; s_flag[i].flag; i++ )
500         {
501                 if ( lc->lc_flags & s_flag[i].flag )
502                 {
503                         attr_merge_normalize_one( e, ad_olmDbConnFlags, &s_flag[i].name, NULL );
504                 }
505         }
506
507         ldap_get_option( lc->lc_ld, LDAP_OPT_URI, &bv.bv_val );
508         ptr = strchr( bv.bv_val, ' ' );
509         bv.bv_len = ptr ? ptr - bv.bv_val : strlen(bv.bv_val);
510         attr_merge_normalize_one( e, ad_olmDbConnURI, &bv, NULL );
511         ch_free( bv.bv_val );
512
513         ldap_back_monitor_conn_peername( lc->lc_ld, &bv );
514         attr_merge_normalize_one( e, ad_olmDbPeerAddress, &bv, NULL );
515         ch_free( bv.bv_val );
516
517         mp = mbe->entrypriv_create();
518         e->e_private = mp;
519         mp->mp_info = arg->ms;
520         mp->mp_flags = MONITOR_F_SUB | MONITOR_F_VOLATILE;
521
522         *arg->ep = e;
523         arg->ep = &mp->mp_next;
524
525         return 0;
526 }
527
528 static int
529 ldap_back_monitor_conn_create(
530         Operation       *op,
531         SlapReply       *rs,
532         struct berval   *ndn,
533         Entry           *e_parent,
534         Entry           **ep )
535 {
536         monitor_entry_t         *mp_parent;
537         monitor_subsys_t        *ms;
538         ldapinfo_t              *li;
539         ldapconn_t              *lc;
540
541         struct ldap_back_monitor_conn_arg *arg;
542         int conn_type;
543
544         assert( e_parent->e_private != NULL );
545
546         mp_parent = e_parent->e_private;
547         ms = (monitor_subsys_t *)mp_parent->mp_info;
548         li = (ldapinfo_t *)ms->mss_private;
549
550         arg = ch_calloc( 1, sizeof(struct ldap_back_monitor_conn_arg) );
551         arg->op = op;
552         arg->ep = ep;
553         arg->ms = ms;
554
555         for ( conn_type = LDAP_BACK_PCONN_FIRST;
556                 conn_type < LDAP_BACK_PCONN_LAST;
557                 conn_type++ )
558         {
559                 LDAP_TAILQ_FOREACH( lc,
560                         &li->li_conn_priv[ conn_type ].lic_priv,
561                         lc_q )
562                 {
563                         ldap_back_monitor_conn_entry( lc, arg );
564                 }
565         }
566
567         avl_apply( li->li_conninfo.lai_tree, (AVL_APPLY)ldap_back_monitor_conn_entry,
568                 arg, -1, AVL_INORDER );
569
570         ch_free( arg );
571
572         return 0;
573 }
574
575 static int
576 ldap_back_monitor_conn_init(
577         BackendDB               *be,
578         monitor_subsys_t        *ms )
579 {
580         ldapinfo_t      *li = (ldapinfo_t *) ms->mss_private;
581         monitor_extra_t *mbe;
582
583         Entry           *e;
584         int             rc;
585
586         assert( be != NULL );
587         mbe = (monitor_extra_t *) be->bd_info->bi_extra;
588
589         ms->mss_dn = ms->mss_ndn = li->li_monitor_info.lmi_ndn;
590         ms->mss_rdn = li->li_monitor_info.lmi_conn_rdn;
591         ms->mss_create = ldap_back_monitor_conn_create;
592         ms->mss_destroy = ldap_back_monitor_subsystem_destroy;
593
594         e = mbe->entry_stub( &ms->mss_dn, &ms->mss_ndn,
595                 &ms->mss_rdn, oc_monitorContainer, NULL, NULL );
596         if ( e == NULL ) {
597                 Debug( LDAP_DEBUG_ANY,
598                         "ldap_back_monitor_conn_init: "
599                         "unable to create entry \"%s,%s\"\n",
600                         li->li_monitor_info.lmi_conn_rdn.bv_val,
601                         ms->mss_ndn.bv_val, 0 );
602                 return( -1 );
603         }
604
605         ber_dupbv( &ms->mss_dn, &e->e_name );
606         ber_dupbv( &ms->mss_ndn, &e->e_nname );
607
608         rc = mbe->register_entry( e, NULL, ms, MONITOR_F_VOLATILE_CH );
609
610         /* add labeledURI and special, modifiable URI value */
611         if ( rc == LDAP_SUCCESS && li->li_uri != NULL ) {
612                 struct berval           bv;
613                 Attribute               *a;
614                 LDAPURLDesc             *ludlist = NULL;
615                 monitor_callback_t      *cb = NULL;
616
617                 a = attr_alloc( ad_olmDbURIList );
618
619                 ber_str2bv( li->li_uri, 0, 0, &bv );
620                 attr_valadd( a, &bv, NULL, 1 );
621                 attr_normalize( a->a_desc, a->a_vals, &a->a_nvals, NULL );
622
623                 rc = ldap_url_parselist_ext( &ludlist,
624                         li->li_uri, NULL,
625                         LDAP_PVT_URL_PARSE_NOEMPTY_HOST
626                                 | LDAP_PVT_URL_PARSE_DEF_PORT );
627                 if ( rc != LDAP_URL_SUCCESS ) {
628                         Debug( LDAP_DEBUG_ANY,
629                                 "ldap_back_monitor_db_open: "
630                                 "unable to parse URI list (ignored)\n",
631                                 0, 0, 0 );
632                 } else {
633                         Attribute *a2 = attr_alloc( slap_schema.si_ad_labeledURI );
634
635                         a->a_next = a2;
636
637                         for ( ; ludlist != NULL; ) {
638                                 LDAPURLDesc     *next = ludlist->lud_next;
639
640                                 bv.bv_val = ldap_url_desc2str( ludlist );
641                                 assert( bv.bv_val != NULL );
642                                 ldap_free_urldesc( ludlist );
643                                 bv.bv_len = strlen( bv.bv_val );
644                                 attr_valadd( a2, &bv, NULL, 1 );
645                                 ch_free( bv.bv_val );
646
647                                 ludlist = next;
648                         }
649
650                         attr_normalize( a2->a_desc, a2->a_vals, &a2->a_nvals, NULL );
651                 }
652
653                 cb = ch_calloc( sizeof( monitor_callback_t ), 1 );
654                 cb->mc_update = ldap_back_monitor_update;
655                 cb->mc_modify = ldap_back_monitor_modify;
656                 cb->mc_free = ldap_back_monitor_free;
657                 cb->mc_private = (void *)li;
658
659                 rc = mbe->register_entry_attrs( &ms->mss_ndn, a, cb, NULL, -1, NULL );
660
661                 attr_free( a->a_next );
662                 attr_free( a );
663
664                 if ( rc != LDAP_SUCCESS )
665                 {
666                         ch_free( cb );
667                 }
668         }
669
670         entry_free( e );
671
672         return rc;
673 }
674
675 /*
676  * Operation monitoring subsystem:
677  * Looks a lot like the cn=operations,cn=monitor subsystem except that at this
678  * moment, only completed operations are counted. Each entry has a separate
679  * callback with all the needed information linked there in the structure
680  * below so that the callback need not locate it over and over again.
681  */
682
683 struct ldap_back_monitor_op_counter {
684         ldap_pvt_mp_t           *data;
685         ldap_pvt_thread_mutex_t *mutex;
686 };
687
688 static void
689 ldap_back_monitor_ops_dispose(
690         void    **priv)
691 {
692         struct ldap_back_monitor_op_counter *counter = *priv;
693
694         ch_free( counter );
695         counter = NULL;
696 }
697
698 static int
699 ldap_back_monitor_ops_free(
700         Entry *e,
701         void **priv)
702 {
703         ldap_back_monitor_ops_dispose( priv );
704         return LDAP_SUCCESS;
705 }
706
707 static int
708 ldap_back_monitor_ops_update(
709         Operation       *op,
710         SlapReply       *rs,
711         Entry           *e,
712         void            *priv )
713 {
714         struct ldap_back_monitor_op_counter *counter = priv;
715         Attribute *a;
716
717         /*TODO
718          * what about initiated/completed?
719          */
720         a = attr_find( e->e_attrs, ad_olmDbOperations );
721         assert( a != NULL );
722
723         ldap_pvt_thread_mutex_lock( counter->mutex );
724         UI2BV( &a->a_vals[ 0 ], *counter->data );
725         ldap_pvt_thread_mutex_unlock( counter->mutex );
726
727         return SLAP_CB_CONTINUE;
728 }
729
730 static int
731 ldap_back_monitor_ops_init(
732         BackendDB               *be,
733         monitor_subsys_t        *ms )
734 {
735         ldapinfo_t      *li = (ldapinfo_t *) ms->mss_private;
736
737         monitor_extra_t *mbe;
738         Entry           *e, *parent;
739         int             rc;
740         slap_op_t       op;
741         struct berval   value = BER_BVC( "0" );
742
743         assert( be != NULL );
744
745         mbe = (monitor_extra_t *) be->bd_info->bi_extra;
746
747         ms->mss_dn = ms->mss_ndn = li->li_monitor_info.lmi_ndn;
748         ms->mss_rdn = li->li_monitor_info.lmi_ops_rdn;
749         ms->mss_destroy = ldap_back_monitor_subsystem_destroy;
750
751         parent = mbe->entry_stub( &ms->mss_dn, &ms->mss_ndn,
752                 &ms->mss_rdn, oc_monitorContainer, NULL, NULL );
753         if ( parent == NULL ) {
754                 Debug( LDAP_DEBUG_ANY,
755                         "ldap_back_monitor_ops_init: "
756                         "unable to create entry \"%s,%s\"\n",
757                         li->li_monitor_info.lmi_ops_rdn.bv_val,
758                         ms->mss_ndn.bv_val, 0 );
759                 return( -1 );
760         }
761
762         ber_dupbv( &ms->mss_dn, &parent->e_name );
763         ber_dupbv( &ms->mss_ndn, &parent->e_nname );
764
765         rc = mbe->register_entry( parent, NULL, ms, MONITOR_F_PERSISTENT_CH );
766         if ( rc != LDAP_SUCCESS )
767         {
768                 Debug( LDAP_DEBUG_ANY,
769                         "ldap_back_monitor_ops_init: "
770                         "unable to register entry \"%s\" for monitoring\n",
771                         parent->e_name.bv_val, 0, 0 );
772                 goto done;
773         }
774
775         for ( op = 0; op < SLAP_OP_LAST; op++ )
776         {
777                 monitor_callback_t *cb;
778                 struct ldap_back_monitor_op_counter *counter;
779
780                 e = mbe->entry_stub( &parent->e_name, &parent->e_nname,
781                         &ldap_back_monitor_op[op].rdn,
782                         oc_monitorCounterObject, NULL, NULL );
783                 if ( e == NULL ) {
784                         Debug( LDAP_DEBUG_ANY,
785                                 "ldap_back_monitor_ops_init: "
786                                 "unable to create entry \"%s,%s\"\n",
787                                 ldap_back_monitor_op[op].rdn.bv_val,
788                                 parent->e_nname.bv_val, 0 );
789                         return( -1 );
790                 }
791
792                 attr_merge_normalize_one( e, ad_olmDbOperations, &value, NULL );
793
794                 counter = ch_malloc( sizeof( struct ldap_back_monitor_op_counter ) );
795                 counter->data = &li->li_ops_completed[ op ];
796                 counter->mutex = &li->li_counter_mutex;
797
798                 /*
799                  * We cannot share a single callback between entries.
800                  *
801                  * monitor_cache_destroy() tries to free all callbacks and it's called
802                  * before mss_destroy() so we have no chance of handling it ourselves
803                  */
804                 cb = ch_calloc( sizeof( monitor_callback_t ), 1 );
805                 cb->mc_update = ldap_back_monitor_ops_update;
806                 cb->mc_free = ldap_back_monitor_ops_free;
807                 cb->mc_dispose = ldap_back_monitor_ops_dispose;
808                 cb->mc_private = (void *)counter;
809
810                 rc = mbe->register_entry( e, cb, ms, 0 );
811
812                 /* TODO: register_entry has stored a duplicate so we might actually reuse it
813                  * instead of recreating it every time... */
814                 entry_free( e );
815
816                 if ( rc != LDAP_SUCCESS )
817                 {
818                         Debug( LDAP_DEBUG_ANY,
819                                 "ldap_back_monitor_ops_init: "
820                                 "unable to register entry \"%s\" for monitoring\n",
821                                 e->e_name.bv_val, 0, 0 );
822                         ch_free( cb );
823                         break;
824                 }
825         }
826
827 done:
828         entry_free( parent );
829
830         return rc;
831 }
832
833 /*
834  * call from within ldap_back_initialize()
835  */
836 static int
837 ldap_back_monitor_initialize( void )
838 {
839         int             i, code;
840         ConfigArgs c;
841         char    *argv[ 3 ];
842
843         static int      ldap_back_monitor_initialized = 0;
844
845         /* set to 0 when successfully initialized; otherwise, remember failure */
846         static int      ldap_back_monitor_initialized_failure = 1;
847
848         /* register schema here; if compiled as dynamic object,
849          * must be loaded __after__ back_monitor.la */
850
851         if ( ldap_back_monitor_initialized++ ) {
852                 return ldap_back_monitor_initialized_failure;
853         }
854
855         if ( backend_info( "monitor" ) == NULL ) {
856                 return -1;
857         }
858
859         argv[ 0 ] = "back-ldap monitor";
860         c.argv = argv;
861         c.argc = 3;
862         c.fname = argv[0];
863         for ( i = 0; s_oid[ i ].name; i++ ) {
864         
865                 argv[ 1 ] = s_oid[ i ].name;
866                 argv[ 2 ] = s_oid[ i ].oid;
867
868                 if ( parse_oidm( &c, 0, NULL ) != 0 ) {
869                         Debug( LDAP_DEBUG_ANY,
870                                 "ldap_back_monitor_initialize: unable to add "
871                                 "objectIdentifier \"%s=%s\"\n",
872                                 s_oid[ i ].name, s_oid[ i ].oid, 0 );
873                         return 2;
874                 }
875         }
876
877         for ( i = 0; s_at[ i ].desc != NULL; i++ ) {
878                 code = register_at( s_at[ i ].desc, s_at[ i ].ad, 1 );
879                 if ( code != LDAP_SUCCESS ) {
880                         Debug( LDAP_DEBUG_ANY,
881                                 "ldap_back_monitor_initialize: register_at failed for attributeType (%s)\n",
882                                 s_at[ i ].desc, 0, 0 );
883                         return 3;
884
885                 } else {
886                         (*s_at[ i ].ad)->ad_type->sat_flags |= SLAP_AT_HIDE;
887                 }
888         }
889
890         for ( i = 0; s_oc[ i ].desc != NULL; i++ ) {
891                 code = register_oc( s_oc[ i ].desc, s_oc[ i ].oc, 1 );
892                 if ( code != LDAP_SUCCESS ) {
893                         Debug( LDAP_DEBUG_ANY,
894                                 "ldap_back_monitor_initialize: register_oc failed for objectClass (%s)\n",
895                                 s_oc[ i ].desc, 0, 0 );
896                         return 4;
897
898                 } else {
899                         (*s_oc[ i ].oc)->soc_flags |= SLAP_OC_HIDE;
900                 }
901         }
902
903         for ( i = 0; s_moc[ i ].name != NULL; i++ ) {
904                 *s_moc[i].oc = oc_find( s_moc[ i ].name );
905                 if ( ! *s_moc[i].oc ) {
906                         Debug( LDAP_DEBUG_ANY,
907                                 "ldap_back_monitor_initialize: failed to find objectClass (%s)\n",
908                                 s_moc[ i ].name, 0, 0 );
909                         return 5;
910
911                 }
912         }
913
914         return ( ldap_back_monitor_initialized_failure = LDAP_SUCCESS );
915 }
916
917 /*
918  * call from within ldap_back_db_init()
919  */
920 int
921 ldap_back_monitor_db_init( BackendDB *be )
922 {
923         int     rc;
924
925         rc = ldap_back_monitor_initialize();
926         if ( rc != LDAP_SUCCESS ) {
927                 return rc;
928         }
929
930 #if 0   /* uncomment to turn monitoring on by default */
931         SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_MONITORING;
932 #endif
933
934         return 0;
935 }
936
937 /*
938  * call from within ldap_back_db_open()
939  */
940 int
941 ldap_back_monitor_db_open( BackendDB *be )
942 {
943         ldapinfo_t              *li = (ldapinfo_t *) be->be_private;
944         monitor_subsys_t        *mss = li->li_monitor_info.lmi_mss;
945         int                     rc = 0;
946         BackendInfo             *mi;
947         monitor_extra_t         *mbe;
948
949         if ( !SLAP_DBMONITORING( be ) ) {
950                 return 0;
951         }
952
953         /* check if monitor is configured and usable */
954         mi = backend_info( "monitor" );
955         if ( !mi || !mi->bi_extra ) {
956                 SLAP_DBFLAGS( be ) ^= SLAP_DBFLAG_MONITORING;
957                 return 0;
958         }
959         mbe = mi->bi_extra;
960
961         /* don't bother if monitor is not configured */
962         if ( !mbe->is_configured() ) {
963                 static int warning = 0;
964
965                 if ( warning++ == 0 ) {
966                         Debug( LDAP_DEBUG_ANY, "ldap_back_monitor_db_open: "
967                                 "monitoring disabled; "
968                                 "configure monitor database to enable\n",
969                                 0, 0, 0 );
970                 }
971
972                 return 0;
973         }
974
975         /* caller (e.g. an overlay based on back-ldap) may want to use
976          * a different DN and RDNs... */
977         if ( BER_BVISNULL( &li->li_monitor_info.lmi_ndn ) ) {
978                 rc = mbe->register_database( be, &li->li_monitor_info.lmi_ndn );
979                 if ( rc != 0 ) {
980                         Debug( LDAP_DEBUG_ANY, "ldap_back_monitor_db_open: "
981                                 "failed to register the databse with back-monitor\n",
982                                 0, 0, 0 );
983                 }
984         }
985         if ( BER_BVISNULL( &li->li_monitor_info.lmi_conn_rdn ) ) {
986                 ber_str2bv( "cn=Connections", 0, 1,
987                         &li->li_monitor_info.lmi_conn_rdn );
988         }
989         if ( BER_BVISNULL( &li->li_monitor_info.lmi_ops_rdn ) ) {
990                 ber_str2bv( "cn=Operations", 0, 1,
991                         &li->li_monitor_info.lmi_ops_rdn );
992         }
993
994         /* set up the subsystems used to create the operation and
995          * volatile connection entries */
996
997         mss->mss_name = "back-ldap connections";
998         mss->mss_flags = MONITOR_F_VOLATILE_CH;
999         mss->mss_open = ldap_back_monitor_conn_init;
1000         mss->mss_private = li;
1001
1002         if ( mbe->register_subsys_late( mss ) )
1003         {
1004                 Debug( LDAP_DEBUG_ANY,
1005                         "ldap_back_monitor_db_open: "
1006                         "failed to register connection subsystem", 0, 0, 0 );
1007                 return -1;
1008         }
1009
1010         mss++;
1011
1012         mss->mss_name = "back-ldap operations";
1013         mss->mss_flags = MONITOR_F_PERSISTENT_CH;
1014         mss->mss_open = ldap_back_monitor_ops_init;
1015         mss->mss_private = li;
1016
1017         if ( mbe->register_subsys_late( mss ) )
1018         {
1019                 Debug( LDAP_DEBUG_ANY,
1020                         "ldap_back_monitor_db_open: "
1021                         "failed to register operation subsystem", 0, 0, 0 );
1022                 return -1;
1023         }
1024
1025         return rc;
1026 }
1027
1028 /*
1029  * call from within ldap_back_db_close()
1030  */
1031 int
1032 ldap_back_monitor_db_close( BackendDB *be )
1033 {
1034         ldapinfo_t              *li = (ldapinfo_t *) be->be_private;
1035
1036         if ( li && !BER_BVISNULL( &li->li_monitor_info.lmi_ndn ) ) {
1037                 BackendInfo             *mi;
1038                 monitor_extra_t         *mbe;
1039
1040                 /* check if monitor is configured and usable */
1041                 mi = backend_info( "monitor" );
1042                 if ( mi && mi->bi_extra ) {
1043                         mbe = mi->bi_extra;
1044
1045                         /*TODO
1046                          * Unregister all entries our subsystems have created.
1047                          * Will only really be necessary when
1048                          * SLAPD_CONFIG_DELETE is enabled.
1049                          *
1050                          * Might need a way to unregister subsystems instead.
1051                          */
1052                 }
1053         }
1054
1055         return 0;
1056 }
1057
1058 /*
1059  * call from within ldap_back_db_destroy()
1060  */
1061 int
1062 ldap_back_monitor_db_destroy( BackendDB *be )
1063 {
1064         ldapinfo_t              *li = (ldapinfo_t *) be->be_private;
1065
1066         if ( li ) {
1067                 memset( &li->li_monitor_info, 0, sizeof( li->li_monitor_info ) );
1068         }
1069
1070         return 0;
1071 }
1072