]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldap/monitor.c
1da4a57d5733f16690b90ace57abb19b3e0be7f4
[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-2012 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_update(
96         Operation       *op,
97         SlapReply       *rs,
98         Entry           *e,
99         void            *priv )
100 {
101         ldapinfo_t              *li = (ldapinfo_t *)priv;
102
103         Attribute               *a;
104
105         /* update olmDbURIList */
106         a = attr_find( e->e_attrs, ad_olmDbURIList );
107         if ( a != NULL ) {
108                 struct berval   bv;
109
110                 assert( a->a_vals != NULL );
111                 assert( !BER_BVISNULL( &a->a_vals[ 0 ] ) );
112                 assert( BER_BVISNULL( &a->a_vals[ 1 ] ) );
113
114                 ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
115                 if ( li->li_uri ) {
116                         ber_str2bv( li->li_uri, 0, 0, &bv );
117                         if ( !bvmatch( &a->a_vals[ 0 ], &bv ) ) {
118                                 ber_bvreplace( &a->a_vals[ 0 ], &bv );
119                         }
120                 }
121                 ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
122         }
123
124         return SLAP_CB_CONTINUE;
125 }
126
127 static int
128 ldap_back_monitor_modify(
129         Operation       *op,
130         SlapReply       *rs,
131         Entry           *e,
132         void            *priv )
133 {
134         ldapinfo_t              *li = (ldapinfo_t *) priv;
135         
136         Attribute               *save_attrs = NULL;
137         Modifications           *ml,
138                                 *ml_olmDbURIList = NULL;
139         struct berval           ul = BER_BVNULL;
140         int                     got = 0;
141
142         for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
143                 if ( ml->sml_desc == ad_olmDbURIList ) {
144                         if ( ml_olmDbURIList != NULL ) {
145                                 rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
146                                 rs->sr_text = "conflicting modifications";
147                                 goto done;
148                         }
149
150                         if ( ml->sml_op != LDAP_MOD_REPLACE ) {
151                                 rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
152                                 rs->sr_text = "modification not allowed";
153                                 goto done;
154                         }
155
156                         ml_olmDbURIList = ml;
157                         got++;
158                         continue;
159                 }
160         }
161
162         if ( got == 0 ) {
163                 return SLAP_CB_CONTINUE;
164         }
165
166         save_attrs = attrs_dup( e->e_attrs );
167
168         if ( ml_olmDbURIList != NULL ) {
169                 Attribute       *a = NULL;
170                 LDAPURLDesc     *ludlist = NULL;
171                 int             rc;
172
173                 ml = ml_olmDbURIList;
174                 assert( ml->sml_nvalues != NULL );
175
176                 if ( BER_BVISNULL( &ml->sml_nvalues[ 0 ] ) ) {
177                         rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
178                         rs->sr_text = "no value provided";
179                         goto done;
180                 }
181
182                 if ( !BER_BVISNULL( &ml->sml_nvalues[ 1 ] ) ) {
183                         rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
184                         rs->sr_text = "multiple values provided";
185                         goto done;
186                 }
187
188                 rc = ldap_url_parselist_ext( &ludlist,
189                         ml->sml_nvalues[ 0 ].bv_val, NULL,
190                         LDAP_PVT_URL_PARSE_NOEMPTY_HOST
191                                 | LDAP_PVT_URL_PARSE_DEF_PORT );
192                 if ( rc != LDAP_URL_SUCCESS ) {
193                         rs->sr_err = LDAP_INVALID_SYNTAX;
194                         rs->sr_text = "unable to parse URI list";
195                         goto done;
196                 }
197
198                 ul.bv_val = ldap_url_list2urls( ludlist );
199                 ldap_free_urllist( ludlist );
200                 if ( ul.bv_val == NULL ) {
201                         rs->sr_err = LDAP_OTHER;
202                         goto done;
203                 }
204                 ul.bv_len = strlen( ul.bv_val );
205                 
206                 a = attr_find( e->e_attrs, ad_olmDbURIList );
207                 if ( a != NULL ) {
208                         if ( a->a_nvals == a->a_vals ) {
209                                 a->a_nvals = ch_calloc( sizeof( struct berval ), 2 );
210                         }
211
212                         ber_bvreplace( &a->a_vals[ 0 ], &ul );
213                         ber_bvreplace( &a->a_nvals[ 0 ], &ul );
214
215                 } else {
216                         attr_merge_normalize_one( e, ad_olmDbURIList, &ul, NULL );
217                 }
218         }
219
220         /* apply changes */
221         if ( !BER_BVISNULL( &ul ) ) {
222                 ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
223                 if ( li->li_uri ) {
224                         ch_free( li->li_uri );
225                 }
226                 li->li_uri = ul.bv_val;
227                 ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
228
229                 BER_BVZERO( &ul );
230         }
231
232 done:;
233         if ( !BER_BVISNULL( &ul ) ) {
234                 ldap_memfree( ul.bv_val );
235         }
236
237         if ( rs->sr_err == LDAP_SUCCESS ) {
238                 attrs_free( save_attrs );
239                 return SLAP_CB_CONTINUE;
240         }
241
242         attrs_free( e->e_attrs );
243         e->e_attrs = save_attrs;
244
245         return rs->sr_err;
246 }
247
248 static int
249 ldap_back_monitor_free(
250         Entry           *e,
251         void            **priv )
252 {
253         ldapinfo_t              *li = (ldapinfo_t *)(*priv);
254
255         *priv = NULL;
256
257         if ( !slapd_shutdown ) {
258                 memset( &li->li_monitor_info, 0, sizeof( li->li_monitor_info ) );
259         }
260
261         return SLAP_CB_CONTINUE;
262 }
263
264 static int
265 ldap_back_monitor_conn_create(
266         Operation       *op,
267         SlapReply       *rs,
268         struct berval   *ndn,
269         Entry           *e_parent,
270         Entry           **ep )
271 {
272         monitor_entry_t         *mp_parent;
273         ldap_monitor_info_t     *lmi;
274         ldapinfo_t              *li;
275
276         assert( e_parent->e_private != NULL );
277
278         mp_parent = e_parent->e_private;
279         lmi = (ldap_monitor_info_t *)mp_parent->mp_info;
280         li = lmi->lmi_li;
281
282         /* do the hard work! */
283
284         return 1;
285 }
286
287 /*
288  * call from within ldap_back_initialize()
289  */
290 static int
291 ldap_back_monitor_initialize( void )
292 {
293         int             i, code;
294         ConfigArgs c;
295         char    *argv[ 3 ];
296
297         static int      ldap_back_monitor_initialized = 0;
298
299         /* set to 0 when successfully initialized; otherwise, remember failure */
300         static int      ldap_back_monitor_initialized_failure = 1;
301
302         /* register schema here; if compiled as dynamic object,
303          * must be loaded __after__ back_monitor.la */
304
305         if ( ldap_back_monitor_initialized++ ) {
306                 return ldap_back_monitor_initialized_failure;
307         }
308
309         if ( backend_info( "monitor" ) == NULL ) {
310                 return -1;
311         }
312
313         argv[ 0 ] = "back-ldap monitor";
314         c.argv = argv;
315         c.argc = 3;
316         c.fname = argv[0];
317         for ( i = 0; s_oid[ i ].name; i++ ) {
318         
319                 argv[ 1 ] = s_oid[ i ].name;
320                 argv[ 2 ] = s_oid[ i ].oid;
321
322                 if ( parse_oidm( &c, 0, NULL ) != 0 ) {
323                         Debug( LDAP_DEBUG_ANY,
324                                 "ldap_back_monitor_initialize: unable to add "
325                                 "objectIdentifier \"%s=%s\"\n",
326                                 s_oid[ i ].name, s_oid[ i ].oid, 0 );
327                         return 2;
328                 }
329         }
330
331         for ( i = 0; s_at[ i ].desc != NULL; i++ ) {
332                 code = register_at( s_at[ i ].desc, s_at[ i ].ad, 1 );
333                 if ( code != LDAP_SUCCESS ) {
334                         Debug( LDAP_DEBUG_ANY,
335                                 "ldap_back_monitor_initialize: register_at failed for attributeType (%s)\n",
336                                 s_at[ i ].desc, 0, 0 );
337                         return 3;
338
339                 } else {
340                         (*s_at[ i ].ad)->ad_type->sat_flags |= SLAP_AT_HIDE;
341                 }
342         }
343
344         for ( i = 0; s_oc[ i ].desc != NULL; i++ ) {
345                 code = register_oc( s_oc[ i ].desc, s_oc[ i ].oc, 1 );
346                 if ( code != LDAP_SUCCESS ) {
347                         Debug( LDAP_DEBUG_ANY,
348                                 "ldap_back_monitor_initialize: register_oc failed for objectClass (%s)\n",
349                                 s_oc[ i ].desc, 0, 0 );
350                         return 4;
351
352                 } else {
353                         (*s_oc[ i ].oc)->soc_flags |= SLAP_OC_HIDE;
354                 }
355         }
356
357         return ( ldap_back_monitor_initialized_failure = LDAP_SUCCESS );
358 }
359
360 /*
361  * call from within ldap_back_db_init()
362  */
363 int
364 ldap_back_monitor_db_init( BackendDB *be )
365 {
366         int     rc;
367
368         rc = ldap_back_monitor_initialize();
369         if ( rc != LDAP_SUCCESS ) {
370                 return rc;
371         }
372
373 #if 0   /* uncomment to turn monitoring on by default */
374         SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_MONITORING;
375 #endif
376
377         return 0;
378 }
379
380 /*
381  * call from within ldap_back_db_open()
382  */
383 int
384 ldap_back_monitor_db_open( BackendDB *be )
385 {
386         ldapinfo_t              *li = (ldapinfo_t *) be->be_private;
387         int                     rc = 0;
388         BackendInfo             *mi;
389         monitor_extra_t         *mbe;
390
391         if ( !SLAP_DBMONITORING( be ) ) {
392                 return 0;
393         }
394
395         /* check if monitor is configured and usable */
396         mi = backend_info( "monitor" );
397         if ( !mi || !mi->bi_extra ) {
398                 SLAP_DBFLAGS( be ) ^= SLAP_DBFLAG_MONITORING;
399                 return 0;
400         }
401         mbe = mi->bi_extra;
402
403         /* don't bother if monitor is not configured */
404         if ( !mbe->is_configured() ) {
405                 static int warning = 0;
406
407                 if ( warning++ == 0 ) {
408                         Debug( LDAP_DEBUG_ANY, "ldap_back_monitor_db_open: "
409                                 "monitoring disabled; "
410                                 "configure monitor database to enable\n",
411                                 0, 0, 0 );
412                 }
413
414                 return 0;
415         }
416
417         /* caller (e.g. an overlay based on back-ldap) may want to use
418          * a different DN and RDNs... */
419         if ( BER_BVISNULL( &li->li_monitor_info.lmi_ndn ) ) {
420                 rc = mbe->register_database( be, &li->li_monitor_info.lmi_ndn );
421                 if ( rc != 0 ) {
422                         Debug( LDAP_DEBUG_ANY, "ldap_back_monitor_db_open: "
423                                 "failed to register the databse with back-monitor\n",
424                                 0, 0, 0 );
425                 }
426         }
427         if ( BER_BVISNULL( &li->li_monitor_info.lmi_conn_rdn ) ) {
428                 ber_str2bv( "cn=Connections", 0, 1,
429                         &li->li_monitor_info.lmi_conn_rdn );
430         }
431         if ( BER_BVISNULL( &li->li_monitor_info.lmi_ops_rdn ) ) {
432                 ber_str2bv( "cn=Operations", 0, 1,
433                         &li->li_monitor_info.lmi_ops_rdn );
434         }
435
436         return rc;
437 }
438
439 /*
440  * call from within ldap_back_db_close()
441  */
442 int
443 ldap_back_monitor_db_close( BackendDB *be )
444 {
445         ldapinfo_t              *li = (ldapinfo_t *) be->be_private;
446
447         if ( li && !BER_BVISNULL( &li->li_monitor_info.lmi_ndn ) ) {
448                 BackendInfo             *mi;
449                 monitor_extra_t         *mbe;
450
451                 /* check if monitor is configured and usable */
452                 mi = backend_info( "monitor" );
453                 if ( mi && mi->bi_extra ) {
454                         mbe = mi->bi_extra;
455
456                         /*TODO
457                          * Unregister all entries our subsystems have created.
458                          * Will only really be necessary when
459                          * SLAPD_CONFIG_DELETE is enabled.
460                          *
461                          * Might need a way to unregister subsystems instead.
462                          */
463                 }
464         }
465
466         return 0;
467 }
468
469 /*
470  * call from within ldap_back_db_destroy()
471  */
472 int
473 ldap_back_monitor_db_destroy( BackendDB *be )
474 {
475         ldapinfo_t              *li = (ldapinfo_t *) be->be_private;
476
477         if ( li ) {
478                 memset( &li->li_monitor_info, 0, sizeof( li->li_monitor_info ) );
479         }
480
481         return 0;
482 }
483