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