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