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