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