]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldap/monitor.c
Merge remote branch 'origin/mdb.master'
[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-2011 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
39 static AttributeDescription     *ad_olmDbURIList;
40
41 /*
42  * NOTE: there's some confusion in monitor OID arc;
43  * by now, let's consider:
44  * 
45  * Subsystems monitor attributes        1.3.6.1.4.1.4203.666.1.55.0
46  * Databases monitor attributes         1.3.6.1.4.1.4203.666.1.55.0.1
47  * LDAP database monitor attributes     1.3.6.1.4.1.4203.666.1.55.0.1.2
48  *
49  * Subsystems monitor objectclasses     1.3.6.1.4.1.4203.666.3.16.0
50  * Databases monitor objectclasses      1.3.6.1.4.1.4203.666.3.16.0.1
51  * LDAP database monitor objectclasses  1.3.6.1.4.1.4203.666.3.16.0.1.2
52  */
53
54 static struct {
55         char                    *name;
56         char                    *oid;
57 }               s_oid[] = {
58         { "olmLDAPAttributes",                  "olmDatabaseAttributes:2" },
59         { "olmLDAPObjectClasses",               "olmDatabaseObjectClasses:2" },
60
61         { NULL }
62 };
63
64 static struct {
65         char                    *desc;
66         AttributeDescription    **ad;
67 }               s_at[] = {
68         { "( olmLDAPAttributes:1 "
69                 "NAME ( 'olmDbURIList' ) "
70                 "DESC 'List of URIs a proxy is serving; can be modified run-time' "
71                 "SUP managedInfo )",
72                 &ad_olmDbURIList },
73
74         { NULL }
75 };
76
77 static struct {
78         char            *desc;
79         ObjectClass     **oc;
80 }               s_oc[] = {
81         /* augments an existing object, so it must be AUXILIARY
82          * FIXME: derive from some ABSTRACT "monitoredEntity"? */
83         { "( olmLDAPObjectClasses:1 "
84                 "NAME ( 'olmLDAPDatabase' ) "
85                 "SUP top AUXILIARY "
86                 "MAY ( "
87                         "olmDbURIList "
88                         ") )",
89                 &oc_olmLDAPDatabase },
90
91         { NULL }
92 };
93
94 static int
95 ldap_back_monitor_info_destroy( ldapinfo_t * li )
96 {
97         if ( !BER_BVISNULL( &li->li_monitor_info.lmi_rdn ) )
98                 ch_free( li->li_monitor_info.lmi_rdn.bv_val );
99         if ( !BER_BVISNULL( &li->li_monitor_info.lmi_nrdn ) )
100                 ch_free( li->li_monitor_info.lmi_nrdn.bv_val );
101         if ( !BER_BVISNULL( &li->li_monitor_info.lmi_filter ) )
102                 ch_free( li->li_monitor_info.lmi_filter.bv_val );
103         if ( !BER_BVISNULL( &li->li_monitor_info.lmi_more_filter ) )
104                 ch_free( li->li_monitor_info.lmi_more_filter.bv_val );
105
106         memset( &li->li_monitor_info, 0, sizeof( li->li_monitor_info ) );
107
108         return 0;
109 }
110
111 static int
112 ldap_back_monitor_update(
113         Operation       *op,
114         SlapReply       *rs,
115         Entry           *e,
116         void            *priv )
117 {
118         ldapinfo_t              *li = (ldapinfo_t *)priv;
119
120         Attribute               *a;
121
122         /* update olmDbURIList */
123         a = attr_find( e->e_attrs, ad_olmDbURIList );
124         if ( a != NULL ) {
125                 struct berval   bv;
126
127                 assert( a->a_vals != NULL );
128                 assert( !BER_BVISNULL( &a->a_vals[ 0 ] ) );
129                 assert( BER_BVISNULL( &a->a_vals[ 1 ] ) );
130
131                 ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
132                 if ( li->li_uri ) {
133                         ber_str2bv( li->li_uri, 0, 0, &bv );
134                         if ( !bvmatch( &a->a_vals[ 0 ], &bv ) ) {
135                                 ber_bvreplace( &a->a_vals[ 0 ], &bv );
136                         }
137                 }
138                 ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
139         }
140
141         return SLAP_CB_CONTINUE;
142 }
143
144 static int
145 ldap_back_monitor_modify(
146         Operation       *op,
147         SlapReply       *rs,
148         Entry           *e,
149         void            *priv )
150 {
151         ldapinfo_t              *li = (ldapinfo_t *) priv;
152         
153         Attribute               *save_attrs = NULL;
154         Modifications           *ml,
155                                 *ml_olmDbURIList = NULL;
156         struct berval           ul = BER_BVNULL;
157         int                     got = 0;
158
159         for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
160                 if ( ml->sml_desc == ad_olmDbURIList ) {
161                         if ( ml_olmDbURIList != NULL ) {
162                                 rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
163                                 rs->sr_text = "conflicting modifications";
164                                 goto done;
165                         }
166
167                         if ( ml->sml_op != LDAP_MOD_REPLACE ) {
168                                 rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
169                                 rs->sr_text = "modification not allowed";
170                                 goto done;
171                         }
172
173                         ml_olmDbURIList = ml;
174                         got++;
175                         continue;
176                 }
177         }
178
179         if ( got == 0 ) {
180                 return SLAP_CB_CONTINUE;
181         }
182
183         save_attrs = attrs_dup( e->e_attrs );
184
185         if ( ml_olmDbURIList != NULL ) {
186                 Attribute       *a = NULL;
187                 LDAPURLDesc     *ludlist = NULL;
188                 int             rc;
189
190                 ml = ml_olmDbURIList;
191                 assert( ml->sml_nvalues != NULL );
192
193                 if ( BER_BVISNULL( &ml->sml_nvalues[ 0 ] ) ) {
194                         rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
195                         rs->sr_text = "no value provided";
196                         goto done;
197                 }
198
199                 if ( !BER_BVISNULL( &ml->sml_nvalues[ 1 ] ) ) {
200                         rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
201                         rs->sr_text = "multiple values provided";
202                         goto done;
203                 }
204
205                 rc = ldap_url_parselist_ext( &ludlist,
206                         ml->sml_nvalues[ 0 ].bv_val, NULL,
207                         LDAP_PVT_URL_PARSE_NOEMPTY_HOST
208                                 | LDAP_PVT_URL_PARSE_DEF_PORT );
209                 if ( rc != LDAP_URL_SUCCESS ) {
210                         rs->sr_err = LDAP_INVALID_SYNTAX;
211                         rs->sr_text = "unable to parse URI list";
212                         goto done;
213                 }
214
215                 ul.bv_val = ldap_url_list2urls( ludlist );
216                 ldap_free_urllist( ludlist );
217                 if ( ul.bv_val == NULL ) {
218                         rs->sr_err = LDAP_OTHER;
219                         goto done;
220                 }
221                 ul.bv_len = strlen( ul.bv_val );
222                 
223                 a = attr_find( e->e_attrs, ad_olmDbURIList );
224                 if ( a != NULL ) {
225                         if ( a->a_nvals == a->a_vals ) {
226                                 a->a_nvals = ch_calloc( sizeof( struct berval ), 2 );
227                         }
228
229                         ber_bvreplace( &a->a_vals[ 0 ], &ul );
230                         ber_bvreplace( &a->a_nvals[ 0 ], &ul );
231
232                 } else {
233                         attr_merge_normalize_one( e, ad_olmDbURIList, &ul, NULL );
234                 }
235         }
236
237         /* apply changes */
238         if ( !BER_BVISNULL( &ul ) ) {
239                 ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
240                 if ( li->li_uri ) {
241                         ch_free( li->li_uri );
242                 }
243                 li->li_uri = ul.bv_val;
244                 ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
245
246                 BER_BVZERO( &ul );
247         }
248
249 done:;
250         if ( !BER_BVISNULL( &ul ) ) {
251                 ldap_memfree( ul.bv_val );
252         }
253
254         if ( rs->sr_err == LDAP_SUCCESS ) {
255                 attrs_free( save_attrs );
256                 return SLAP_CB_CONTINUE;
257         }
258
259         attrs_free( e->e_attrs );
260         e->e_attrs = save_attrs;
261
262         return rs->sr_err;
263 }
264
265 static int
266 ldap_back_monitor_free(
267         Entry           *e,
268         void            **priv )
269 {
270         ldapinfo_t              *li = (ldapinfo_t *)(*priv);
271
272         *priv = NULL;
273
274         if ( !slapd_shutdown && !BER_BVISNULL( &li->li_monitor_info.lmi_rdn ) ) {
275                 ldap_back_monitor_info_destroy( li );
276         }
277
278         return SLAP_CB_CONTINUE;
279 }
280
281 static int
282 ldap_back_monitor_conn_create(
283         Operation       *op,
284         SlapReply       *rs,
285         struct berval   *ndn,
286         Entry           *e_parent,
287         Entry           **ep )
288 {
289         monitor_entry_t         *mp_parent;
290         ldap_monitor_info_t     *lmi;
291         ldapinfo_t              *li;
292
293         assert( e_parent->e_private != NULL );
294
295         mp_parent = e_parent->e_private;
296         lmi = (ldap_monitor_info_t *)mp_parent->mp_info;
297         li = lmi->lmi_li;
298
299         /* do the hard work! */
300
301         return 1;
302 }
303
304 /*
305  * call from within ldap_back_initialize()
306  */
307 static int
308 ldap_back_monitor_initialize( void )
309 {
310         int             i, code;
311         ConfigArgs c;
312         char    *argv[ 3 ];
313
314         static int      ldap_back_monitor_initialized = 0;
315
316         /* set to 0 when successfully initialized; otherwise, remember failure */
317         static int      ldap_back_monitor_initialized_failure = 1;
318
319         /* register schema here; if compiled as dynamic object,
320          * must be loaded __after__ back_monitor.la */
321
322         if ( ldap_back_monitor_initialized++ ) {
323                 return ldap_back_monitor_initialized_failure;
324         }
325
326         if ( backend_info( "monitor" ) == NULL ) {
327                 return -1;
328         }
329
330         argv[ 0 ] = "back-ldap monitor";
331         c.argv = argv;
332         c.argc = 3;
333         c.fname = argv[0];
334         for ( i = 0; s_oid[ i ].name; i++ ) {
335         
336                 argv[ 1 ] = s_oid[ i ].name;
337                 argv[ 2 ] = s_oid[ i ].oid;
338
339                 if ( parse_oidm( &c, 0, NULL ) != 0 ) {
340                         Debug( LDAP_DEBUG_ANY,
341                                 "ldap_back_monitor_initialize: unable to add "
342                                 "objectIdentifier \"%s=%s\"\n",
343                                 s_oid[ i ].name, s_oid[ i ].oid, 0 );
344                         return 2;
345                 }
346         }
347
348         for ( i = 0; s_at[ i ].desc != NULL; i++ ) {
349                 code = register_at( s_at[ i ].desc, s_at[ i ].ad, 1 );
350                 if ( code != LDAP_SUCCESS ) {
351                         Debug( LDAP_DEBUG_ANY,
352                                 "ldap_back_monitor_initialize: register_at failed for attributeType (%s)\n",
353                                 s_at[ i ].desc, 0, 0 );
354                         return 3;
355
356                 } else {
357                         (*s_at[ i ].ad)->ad_type->sat_flags |= SLAP_AT_HIDE;
358                 }
359         }
360
361         for ( i = 0; s_oc[ i ].desc != NULL; i++ ) {
362                 code = register_oc( s_oc[ i ].desc, s_oc[ i ].oc, 1 );
363                 if ( code != LDAP_SUCCESS ) {
364                         Debug( LDAP_DEBUG_ANY,
365                                 "ldap_back_monitor_initialize: register_oc failed for objectClass (%s)\n",
366                                 s_oc[ i ].desc, 0, 0 );
367                         return 4;
368
369                 } else {
370                         (*s_oc[ i ].oc)->soc_flags |= SLAP_OC_HIDE;
371                 }
372         }
373
374         return ( ldap_back_monitor_initialized_failure = LDAP_SUCCESS );
375 }
376
377 /*
378  * call from within ldap_back_db_init()
379  */
380 int
381 ldap_back_monitor_db_init( BackendDB *be )
382 {
383         int     rc;
384
385         rc = ldap_back_monitor_initialize();
386         if ( rc != LDAP_SUCCESS ) {
387                 return rc;
388         }
389
390 #if 0   /* uncomment to turn monitoring on by default */
391         SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_MONITORING;
392 #endif
393
394         return 0;
395 }
396
397 /*
398  * call from within ldap_back_db_open()
399  */
400 int
401 ldap_back_monitor_db_open( BackendDB *be )
402 {
403         ldapinfo_t              *li = (ldapinfo_t *) be->be_private;
404         char                    buf[ BACKMONITOR_BUFSIZE ];
405         Entry                   *e = NULL;
406         monitor_callback_t      *cb = NULL;
407         struct berval           suffix, *filter, *base;
408         char                    *ptr;
409         time_t                  now;
410         char                    timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
411         struct berval           timestamp;
412         int                     rc = 0;
413         BackendInfo             *mi;
414         monitor_extra_t         *mbe;
415
416         if ( !SLAP_DBMONITORING( be ) ) {
417                 return 0;
418         }
419
420         /* check if monitor is configured and usable */
421         mi = backend_info( "monitor" );
422         if ( !mi || !mi->bi_extra ) {
423                 SLAP_DBFLAGS( be ) ^= SLAP_DBFLAG_MONITORING;
424                 return 0;
425         }
426         mbe = mi->bi_extra;
427
428         /* don't bother if monitor is not configured */
429         if ( !mbe->is_configured() ) {
430                 static int warning = 0;
431
432                 if ( warning++ == 0 ) {
433                         Debug( LDAP_DEBUG_ANY, "ldap_back_monitor_db_open: "
434                                 "monitoring disabled; "
435                                 "configure monitor database to enable\n",
436                                 0, 0, 0 );
437                 }
438
439                 return 0;
440         }
441
442         /* set up the fake subsystem that is used to create
443          * the volatile connection entries */
444         li->li_monitor_info.lmi_mss.mss_name = "back-ldap";
445         li->li_monitor_info.lmi_mss.mss_flags = MONITOR_F_VOLATILE_CH;
446         li->li_monitor_info.lmi_mss.mss_create = ldap_back_monitor_conn_create;
447
448         li->li_monitor_info.lmi_li = li;
449         li->li_monitor_info.lmi_scope = LDAP_SCOPE_SUBORDINATE;
450         base = &li->li_monitor_info.lmi_base;
451         BER_BVSTR( base, "cn=databases,cn=monitor" );
452         filter = &li->li_monitor_info.lmi_filter;
453         BER_BVZERO( filter );
454
455         suffix.bv_len = ldap_bv2escaped_filter_value_len( &be->be_nsuffix[ 0 ] );
456         if ( suffix.bv_len == be->be_nsuffix[ 0 ].bv_len ) {
457                 suffix = be->be_nsuffix[ 0 ];
458
459         } else {
460                 ldap_bv2escaped_filter_value( &be->be_nsuffix[ 0 ], &suffix );
461         }
462         
463         filter->bv_len = STRLENOF( "(&" )
464                 + li->li_monitor_info.lmi_more_filter.bv_len
465                 + STRLENOF( "(monitoredInfo=" )
466                 + strlen( be->bd_info->bi_type )
467                 + STRLENOF( ")(!(monitorOverlay=" )
468                 + strlen( be->bd_info->bi_type )
469                 + STRLENOF( "))(namingContexts:distinguishedNameMatch:=" )
470                 + suffix.bv_len + STRLENOF( "))" );
471         ptr = filter->bv_val = ch_malloc( filter->bv_len + 1 );
472         ptr = lutil_strcopy( ptr, "(&" );
473         ptr = lutil_strncopy( ptr, li->li_monitor_info.lmi_more_filter.bv_val,
474                 li->li_monitor_info.lmi_more_filter.bv_len );
475         ptr = lutil_strcopy( ptr, "(monitoredInfo=" );
476         ptr = lutil_strcopy( ptr, be->bd_info->bi_type );
477         ptr = lutil_strcopy( ptr, ")(!(monitorOverlay=" );
478         ptr = lutil_strcopy( ptr, be->bd_info->bi_type );
479         ptr = lutil_strcopy( ptr, "))(namingContexts:distinguishedNameMatch:=" );
480         ptr = lutil_strncopy( ptr, suffix.bv_val, suffix.bv_len );
481         ptr = lutil_strcopy( ptr, "))" );
482         ptr[ 0 ] = '\0';
483         assert( ptr == &filter->bv_val[ filter->bv_len ] );
484
485         if ( suffix.bv_val != be->be_nsuffix[ 0 ].bv_val ) {
486                 ch_free( suffix.bv_val );
487         }
488
489         now = slap_get_time();
490         timestamp.bv_val = timebuf;
491         timestamp.bv_len = sizeof( timebuf );
492         slap_timestamp( &now, &timestamp );
493
494         /* caller (e.g. an overlay based on back-ldap) may want to use
495          * a different RDN... */
496         if ( BER_BVISNULL( &li->li_monitor_info.lmi_rdn ) ) {
497                 ber_str2bv( "cn=Connections", 0, 1, &li->li_monitor_info.lmi_rdn );
498         }
499
500         ptr = ber_bvchr( &li->li_monitor_info.lmi_rdn, '=' );
501         assert( ptr != NULL );
502         ptr[ 0 ] = '\0';
503         ptr++;
504
505         snprintf( buf, sizeof( buf ),
506                 "dn: %s=%s\n"
507                 "objectClass: monitorContainer\n"
508                 "%s: %s\n"
509                 "creatorsName: %s\n"
510                 "createTimestamp: %s\n"
511                 "modifiersName: %s\n"
512                 "modifyTimestamp: %s\n",
513                 li->li_monitor_info.lmi_rdn.bv_val,
514                         ptr,
515                 li->li_monitor_info.lmi_rdn.bv_val,
516                         ptr,
517                 BER_BVISNULL( &be->be_rootdn ) ? SLAPD_ANONYMOUS : be->be_rootdn.bv_val,
518                 timestamp.bv_val,
519                 BER_BVISNULL( &be->be_rootdn ) ? SLAPD_ANONYMOUS : be->be_rootdn.bv_val,
520                 timestamp.bv_val );
521         e = str2entry( buf );
522         if ( e == NULL ) {
523                 rc = -1;
524                 goto cleanup;
525         }
526
527         ptr[ -1 ] = '=';
528
529         /* add labeledURI and special, modifiable URI value */
530         if ( li->li_uri != NULL ) {
531                 struct berval   bv;
532                 LDAPURLDesc     *ludlist = NULL;
533                 int             rc;
534
535                 rc = ldap_url_parselist_ext( &ludlist,
536                         li->li_uri, NULL,
537                         LDAP_PVT_URL_PARSE_NOEMPTY_HOST
538                                 | LDAP_PVT_URL_PARSE_DEF_PORT );
539                 if ( rc != LDAP_URL_SUCCESS ) {
540                         Debug( LDAP_DEBUG_ANY,
541                                 "ldap_back_monitor_db_open: "
542                                 "unable to parse URI list (ignored)\n",
543                                 0, 0, 0 );
544                 } else {
545                         for ( ; ludlist != NULL; ) {
546                                 LDAPURLDesc     *next = ludlist->lud_next;
547
548                                 bv.bv_val = ldap_url_desc2str( ludlist );
549                                 assert( bv.bv_val != NULL );
550                                 ldap_free_urldesc( ludlist );
551                                 bv.bv_len = strlen( bv.bv_val );
552                                 attr_merge_normalize_one( e, slap_schema.si_ad_labeledURI,
553                                         &bv, NULL );
554                                 ch_free( bv.bv_val );
555
556                                 ludlist = next;
557                         }
558                 }
559                 
560                 ber_str2bv( li->li_uri, 0, 0, &bv );
561                 attr_merge_normalize_one( e, ad_olmDbURIList,
562                         &bv, NULL );
563         }
564
565         ber_dupbv( &li->li_monitor_info.lmi_nrdn, &e->e_nname );
566
567         cb = ch_calloc( sizeof( monitor_callback_t ), 1 );
568         cb->mc_update = ldap_back_monitor_update;
569         cb->mc_modify = ldap_back_monitor_modify;
570         cb->mc_free = ldap_back_monitor_free;
571         cb->mc_private = (void *)li;
572
573         rc = mbe->register_entry_parent( e, cb,
574                 (monitor_subsys_t *)&li->li_monitor_info,
575                 MONITOR_F_VOLATILE_CH,
576                 base, LDAP_SCOPE_SUBORDINATE, filter );
577
578 cleanup:;
579         if ( rc != 0 ) {
580                 if ( cb != NULL ) {
581                         ch_free( cb );
582                         cb = NULL;
583                 }
584
585                 if ( e != NULL ) {
586                         entry_free( e );
587                         e = NULL;
588                 }
589
590                 if ( !BER_BVISNULL( filter ) ) {
591                         ch_free( filter->bv_val );
592                         BER_BVZERO( filter );
593                 }
594         }
595
596         /* store for cleanup */
597         li->li_monitor_info.lmi_cb = (void *)cb;
598
599         if ( e != NULL ) {
600                 entry_free( e );
601         }
602
603         return rc;
604 }
605
606 /*
607  * call from within ldap_back_db_close()
608  */
609 int
610 ldap_back_monitor_db_close( BackendDB *be )
611 {
612         ldapinfo_t              *li = (ldapinfo_t *) be->be_private;
613
614         if ( li && !BER_BVISNULL( &li->li_monitor_info.lmi_filter ) ) {
615                 BackendInfo             *mi;
616                 monitor_extra_t         *mbe;
617
618                 /* check if monitor is configured and usable */
619                 mi = backend_info( "monitor" );
620                 if ( mi && mi->bi_extra ) {
621                         mbe = mi->bi_extra;
622
623                         mbe->unregister_entry_parent(
624                                 &li->li_monitor_info.lmi_nrdn,
625                                 (monitor_callback_t *)li->li_monitor_info.lmi_cb,
626                                 &li->li_monitor_info.lmi_base,
627                                 li->li_monitor_info.lmi_scope,
628                                 &li->li_monitor_info.lmi_filter );
629                 }
630         }
631
632         return 0;
633 }
634
635 /*
636  * call from within ldap_back_db_destroy()
637  */
638 int
639 ldap_back_monitor_db_destroy( BackendDB *be )
640 {
641         ldapinfo_t              *li = (ldapinfo_t *) be->be_private;
642
643         if ( li ) {
644                 (void)ldap_back_monitor_info_destroy( li );
645         }
646
647         return 0;
648 }
649