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