]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldap/monitor.c
happy new year
[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-2007 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         /* register schema here; if compiled as dynamic object,
317          * must be loaded __after__ back_monitor.la */
318
319         if ( ldap_back_monitor_initialized++ ) {
320                 return 0;
321         }
322
323         if ( backend_info( "monitor" ) == NULL ) {
324                 return -1;
325         }
326
327         argv[ 0 ] = "back-ldap monitor";
328         c.argv = argv;
329         c.argc = 3;
330         c.fname = argv[0];
331         for ( i = 0; s_oid[ i ].name; i++ ) {
332         
333                 argv[ 1 ] = s_oid[ i ].name;
334                 argv[ 2 ] = s_oid[ i ].oid;
335
336                 if ( parse_oidm( &c, 0, NULL ) != 0 ) {
337                         Debug( LDAP_DEBUG_ANY,
338                                 "ldap_back_monitor_initialize: unable to add "
339                                 "objectIdentifier \"%s=%s\"\n",
340                                 s_oid[ i ].name, s_oid[ i ].oid, 0 );
341                         return 1;
342                 }
343         }
344
345         for ( i = 0; s_at[ i ].desc != NULL; i++ ) {
346                 code = register_at( s_at[ i ].desc, s_at[ i ].ad, 1 );
347                 if ( code != LDAP_SUCCESS ) {
348                         Debug( LDAP_DEBUG_ANY,
349                                 "ldap_back_monitor_initialize: register_at failed\n",
350                                 0, 0, 0 );
351                 }
352         }
353
354         for ( i = 0; s_oc[ i ].desc != NULL; i++ ) {
355                 code = register_oc( s_oc[ i ].desc, s_oc[ i ].oc, 1 );
356                 if ( code != LDAP_SUCCESS ) {
357                         Debug( LDAP_DEBUG_ANY,
358                                 "ldap_back_monitor_initialize: register_oc failed\n",
359                                 0, 0, 0 );
360                 }
361         }
362
363         return 0;
364 }
365
366 /*
367  * call from within ldap_back_db_init()
368  */
369 int
370 ldap_back_monitor_db_init( BackendDB *be )
371 {
372         int     rc;
373
374         rc = ldap_back_monitor_initialize();
375         if ( rc != LDAP_SUCCESS ) {
376                 return rc;
377         }
378
379 #if 0   /* uncomment to turn monitoring on by default */
380         SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_MONITORING;
381 #endif
382
383         return 0;
384 }
385
386 /*
387  * call from within ldap_back_db_open()
388  */
389 int
390 ldap_back_monitor_db_open( BackendDB *be )
391 {
392         ldapinfo_t              *li = (ldapinfo_t *) be->be_private;
393         char                    buf[ BACKMONITOR_BUFSIZE ];
394         Entry                   *e = NULL;
395         monitor_callback_t      *cb = NULL;
396         struct berval           suffix, *filter, *base;
397         char                    *ptr;
398         time_t                  now;
399         char                    timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
400         struct berval           timestamp;
401         int                     rc = 0;
402         BackendInfo             *mi;
403         monitor_extra_t         *mbe;
404
405         if ( !SLAP_DBMONITORING( be ) ) {
406                 return 0;
407         }
408
409         /* check if monitor is configured and usable */
410         mi = backend_info( "monitor" );
411         if ( !mi || !mi->bi_extra ) {
412                 SLAP_DBFLAGS( be ) ^= SLAP_DBFLAG_MONITORING;
413                 return 0;
414         }
415         mbe = mi->bi_extra;
416
417         /* don't bother if monitor is not configured */
418         if ( !mbe->is_configured() ) {
419                 static int warning = 0;
420
421                 if ( warning++ == 0 ) {
422                         Debug( LDAP_DEBUG_ANY, "ldap_back_monitor_db_open: "
423                                 "monitoring disabled; "
424                                 "configure monitor database to enable\n",
425                                 0, 0, 0 );
426                 }
427
428                 return 0;
429         }
430
431         /* set up the fake subsystem that is used to create
432          * the volatile connection entries */
433         li->li_monitor_info.lmi_mss.mss_name = "back-ldap";
434         li->li_monitor_info.lmi_mss.mss_flags = MONITOR_F_VOLATILE_CH;
435         li->li_monitor_info.lmi_mss.mss_create = ldap_back_monitor_conn_create;
436
437         li->li_monitor_info.lmi_li = li;
438         li->li_monitor_info.lmi_scope = LDAP_SCOPE_SUBORDINATE;
439         base = &li->li_monitor_info.lmi_base;
440         BER_BVSTR( base, "cn=databases,cn=monitor" );
441         filter = &li->li_monitor_info.lmi_filter;
442         BER_BVZERO( filter );
443
444         suffix.bv_len = ldap_bv2escaped_filter_value_len( &be->be_nsuffix[ 0 ] );
445         if ( suffix.bv_len == be->be_nsuffix[ 0 ].bv_len ) {
446                 suffix = be->be_nsuffix[ 0 ];
447
448         } else {
449                 ldap_bv2escaped_filter_value( &be->be_nsuffix[ 0 ], &suffix );
450         }
451         
452         filter->bv_len = STRLENOF( "(&" )
453                 + li->li_monitor_info.lmi_more_filter.bv_len
454                 + STRLENOF( "(monitoredInfo=" )
455                 + strlen( be->bd_info->bi_type )
456                 + STRLENOF( ")(!(monitorOverlay=" )
457                 + strlen( be->bd_info->bi_type )
458                 + STRLENOF( "))(namingContexts:distinguishedNameMatch:=" )
459                 + suffix.bv_len + STRLENOF( "))" );
460         ptr = filter->bv_val = ch_malloc( filter->bv_len + 1 );
461         ptr = lutil_strcopy( ptr, "(&" );
462         ptr = lutil_strncopy( ptr, li->li_monitor_info.lmi_more_filter.bv_val,
463                 li->li_monitor_info.lmi_more_filter.bv_len );
464         ptr = lutil_strcopy( ptr, "(monitoredInfo=" );
465         ptr = lutil_strcopy( ptr, be->bd_info->bi_type );
466         ptr = lutil_strcopy( ptr, ")(!(monitorOverlay=" );
467         ptr = lutil_strcopy( ptr, be->bd_info->bi_type );
468         ptr = lutil_strcopy( ptr, "))(namingContexts:distinguishedNameMatch:=" );
469         ptr = lutil_strncopy( ptr, suffix.bv_val, suffix.bv_len );
470         ptr = lutil_strcopy( ptr, "))" );
471         ptr[ 0 ] = '\0';
472         assert( filter->bv_len == ptr - filter->bv_val );
473
474         if ( suffix.bv_val != be->be_nsuffix[ 0 ].bv_val ) {
475                 ch_free( suffix.bv_val );
476         }
477
478         now = slap_get_time();
479         timestamp.bv_val = timebuf;
480         timestamp.bv_len = sizeof( timebuf );
481         slap_timestamp( &now, &timestamp );
482
483         /* caller (e.g. an overlay based on back-ldap) may want to use
484          * a different RDN... */
485         if ( BER_BVISNULL( &li->li_monitor_info.lmi_rdn ) ) {
486                 ber_str2bv( "cn=Connections", 0, 1, &li->li_monitor_info.lmi_rdn );
487         }
488
489         ptr = ber_bvchr( &li->li_monitor_info.lmi_rdn, '=' );
490         assert( ptr != NULL );
491         ptr[ 0 ] = '\0';
492         ptr++;
493
494         snprintf( buf, sizeof( buf ),
495                 "dn: %s=%s\n"
496                 "objectClass: monitorContainer\n"
497                 "%s: %s\n"
498                 "creatorsName: %s\n"
499                 "createTimestamp: %s\n"
500                 "modifiersName: %s\n"
501                 "modifyTimestamp: %s\n",
502                 li->li_monitor_info.lmi_rdn.bv_val,
503                         ptr,
504                 li->li_monitor_info.lmi_rdn.bv_val,
505                         ptr,
506                 BER_BVISNULL( &be->be_rootdn ) ? SLAPD_ANONYMOUS : be->be_rootdn.bv_val,
507                 timestamp.bv_val,
508                 BER_BVISNULL( &be->be_rootdn ) ? SLAPD_ANONYMOUS : be->be_rootdn.bv_val,
509                 timestamp.bv_val );
510         e = str2entry( buf );
511         if ( e == NULL ) {
512                 rc = -1;
513                 goto cleanup;
514         }
515
516         ptr[ -1 ] = '=';
517
518         /* add labeledURI and special, modifiable URI value */
519         if ( li->li_uri != NULL ) {
520                 struct berval   bv;
521                 LDAPURLDesc     *ludlist = NULL;
522                 int             rc;
523
524                 rc = ldap_url_parselist_ext( &ludlist,
525                         li->li_uri, NULL,
526                         LDAP_PVT_URL_PARSE_NOEMPTY_HOST
527                                 | LDAP_PVT_URL_PARSE_DEF_PORT );
528                 if ( rc != LDAP_URL_SUCCESS ) {
529                         Debug( LDAP_DEBUG_ANY,
530                                 "ldap_back_monitor_db_open: "
531                                 "unable to parse URI list (ignored)\n",
532                                 0, 0, 0 );
533                 } else {
534                         for ( ; ludlist != NULL; ) {
535                                 LDAPURLDesc     *next = ludlist->lud_next;
536
537                                 bv.bv_val = ldap_url_desc2str( ludlist );
538                                 assert( bv.bv_val != NULL );
539                                 ldap_free_urldesc( ludlist );
540                                 bv.bv_len = strlen( bv.bv_val );
541                                 attr_merge_normalize_one( e, slap_schema.si_ad_labeledURI,
542                                         &bv, NULL );
543                                 ch_free( bv.bv_val );
544
545                                 ludlist = next;
546                         }
547                 }
548                 
549                 ber_str2bv( li->li_uri, 0, 0, &bv );
550                 attr_merge_normalize_one( e, ad_olmDbURIList,
551                         &bv, NULL );
552         }
553
554         ber_dupbv( &li->li_monitor_info.lmi_nrdn, &e->e_nname );
555
556         cb = ch_calloc( sizeof( monitor_callback_t ), 1 );
557         cb->mc_update = ldap_back_monitor_update;
558         cb->mc_modify = ldap_back_monitor_modify;
559         cb->mc_free = ldap_back_monitor_free;
560         cb->mc_private = (void *)li;
561
562         rc = mbe->register_entry_parent( e, cb,
563                 (monitor_subsys_t *)&li->li_monitor_info,
564                 MONITOR_F_VOLATILE_CH,
565                 base, LDAP_SCOPE_SUBORDINATE, filter );
566
567 cleanup:;
568         if ( rc != 0 ) {
569                 if ( cb != NULL ) {
570                         ch_free( cb );
571                         cb = NULL;
572                 }
573
574                 if ( e != NULL ) {
575                         entry_free( e );
576                         e = NULL;
577                 }
578
579                 if ( !BER_BVISNULL( filter ) ) {
580                         ch_free( filter->bv_val );
581                         BER_BVZERO( filter );
582                 }
583         }
584
585         /* store for cleanup */
586         li->li_monitor_info.lmi_cb = (void *)cb;
587
588         if ( e != NULL ) {
589                 entry_free( e );
590         }
591
592         return rc;
593 }
594
595 /*
596  * call from within ldap_back_db_close()
597  */
598 int
599 ldap_back_monitor_db_close( BackendDB *be )
600 {
601         ldapinfo_t              *li = (ldapinfo_t *) be->be_private;
602
603         if ( li && !BER_BVISNULL( &li->li_monitor_info.lmi_filter ) ) {
604                 BackendInfo             *mi;
605                 monitor_extra_t         *mbe;
606
607                 /* check if monitor is configured and usable */
608                 mi = backend_info( "monitor" );
609                 if ( mi && mi->bi_extra ) {
610                         mbe = mi->bi_extra;
611
612                         mbe->unregister_entry_parent(
613                                 &li->li_monitor_info.lmi_nrdn,
614                                 (monitor_callback_t *)li->li_monitor_info.lmi_cb,
615                                 &li->li_monitor_info.lmi_base,
616                                 li->li_monitor_info.lmi_scope,
617                                 &li->li_monitor_info.lmi_filter );
618                 }
619         }
620
621         return 0;
622 }
623
624 /*
625  * call from within ldap_back_db_destroy()
626  */
627 int
628 ldap_back_monitor_db_destroy( BackendDB *be )
629 {
630         ldapinfo_t              *li = (ldapinfo_t *) be->be_private;
631
632         if ( li ) {
633                 (void)ldap_back_monitor_info_destroy( li );
634         }
635
636         return 0;
637 }
638