1 /* conn.c - deal with connection subsystem */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2001-2021 The OpenLDAP Foundation.
6  * Portions Copyright 2001-2003 Pierangelo Masarati.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* ACKNOWLEDGEMENTS:
18  * This work was initially developed by Pierangelo Masarati for inclusion
19  * in OpenLDAP Software.
20  */
21 
22 #include "portable.h"
23 
24 #include <stdio.h>
25 #include <ac/string.h>
26 
27 #include "slap.h"
28 #include "lutil.h"
29 #include "back-monitor.h"
30 
31 static int
32 monitor_subsys_conn_update(
33 	Operation		*op,
34 	SlapReply		*rs,
35 	Entry                   *e );
36 
37 static int
38 monitor_subsys_conn_create(
39 	Operation		*op,
40 	SlapReply		*rs,
41 	struct berval		*ndn,
42 	Entry 			*e_parent,
43 	Entry			**ep );
44 
45 int
monitor_subsys_conn_init(BackendDB * be,monitor_subsys_t * ms)46 monitor_subsys_conn_init(
47 	BackendDB		*be,
48 	monitor_subsys_t	*ms )
49 {
50 	monitor_info_t	*mi;
51 	Entry		*e, *e_conn;
52 	monitor_entry_t	*mp;
53 	char		buf[ BACKMONITOR_BUFSIZE ];
54 	struct berval	bv;
55 
56 	assert( be != NULL );
57 
58 	ms->mss_update = monitor_subsys_conn_update;
59 	ms->mss_create = monitor_subsys_conn_create;
60 
61 	mi = ( monitor_info_t * )be->be_private;
62 
63 	if ( monitor_cache_get( mi, &ms->mss_ndn, &e_conn ) ) {
64 		Debug( LDAP_DEBUG_ANY,
65 			"monitor_subsys_conn_init: "
66 			"unable to get entry \"%s\"\n",
67 			ms->mss_ndn.bv_val );
68 		return( -1 );
69 	}
70 
71 	mp = ( monitor_entry_t * )e_conn->e_private;
72 
73 	/*
74 	 * Max file descriptors
75 	 */
76 	BER_BVSTR( &bv, "cn=Max File Descriptors" );
77 	e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, &bv,
78 		mi->mi_oc_monitorCounterObject, NULL, NULL );
79 
80 	if ( e == NULL ) {
81 		Debug( LDAP_DEBUG_ANY,
82 			"monitor_subsys_conn_init: "
83 			"unable to create entry \"%s,%s\"\n",
84 			bv.bv_val, ms->mss_ndn.bv_val );
85 		return( -1 );
86 	}
87 
88 	if ( dtblsize ) {
89 		bv.bv_val = buf;
90 		bv.bv_len = snprintf( buf, sizeof( buf ), "%d", dtblsize );
91 
92 	} else {
93 		BER_BVSTR( &bv, "0" );
94 	}
95 	attr_merge_one( e, mi->mi_ad_monitorCounter, &bv, NULL );
96 
97 	mp = monitor_entrypriv_create();
98 	if ( mp == NULL ) {
99 		return -1;
100 	}
101 	e->e_private = ( void * )mp;
102 	mp->mp_info = ms;
103 	mp->mp_flags = ms->mss_flags \
104 		| MONITOR_F_SUB | MONITOR_F_PERSISTENT;
105 	mp->mp_flags &= ~MONITOR_F_VOLATILE_CH;
106 
107 	if ( monitor_cache_add( mi, e, e_conn ) ) {
108 		Debug( LDAP_DEBUG_ANY,
109 			"monitor_subsys_conn_init: "
110 			"unable to add entry \"cn=Total,%s\"\n",
111 			ms->mss_ndn.bv_val );
112 		return( -1 );
113 	}
114 
115 	/*
116 	 * Total conns
117 	 */
118 	BER_BVSTR( &bv, "cn=Total" );
119 	e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, &bv,
120 		mi->mi_oc_monitorCounterObject, NULL, NULL );
121 
122 	if ( e == NULL ) {
123 		Debug( LDAP_DEBUG_ANY,
124 			"monitor_subsys_conn_init: "
125 			"unable to create entry \"cn=Total,%s\"\n",
126 			ms->mss_ndn.bv_val );
127 		return( -1 );
128 	}
129 
130 	BER_BVSTR( &bv, "-1" );
131 	attr_merge_one( e, mi->mi_ad_monitorCounter, &bv, NULL );
132 
133 	mp = monitor_entrypriv_create();
134 	if ( mp == NULL ) {
135 		return -1;
136 	}
137 	e->e_private = ( void * )mp;
138 	mp->mp_info = ms;
139 	mp->mp_flags = ms->mss_flags \
140 		| MONITOR_F_SUB | MONITOR_F_PERSISTENT;
141 	mp->mp_flags &= ~MONITOR_F_VOLATILE_CH;
142 
143 	if ( monitor_cache_add( mi, e, e_conn ) ) {
144 		Debug( LDAP_DEBUG_ANY,
145 			"monitor_subsys_conn_init: "
146 			"unable to add entry \"cn=Total,%s\"\n",
147 			ms->mss_ndn.bv_val );
148 		return( -1 );
149 	}
150 
151 	/*
152 	 * Current conns
153 	 */
154 	BER_BVSTR( &bv, "cn=Current" );
155 	e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, &bv,
156 		mi->mi_oc_monitorCounterObject, NULL, NULL );
157 
158 	if ( e == NULL ) {
159 		Debug( LDAP_DEBUG_ANY,
160 			"monitor_subsys_conn_init: "
161 			"unable to create entry \"cn=Current,%s\"\n",
162 			ms->mss_ndn.bv_val );
163 		return( -1 );
164 	}
165 
166 	BER_BVSTR( &bv, "0" );
167 	attr_merge_one( e, mi->mi_ad_monitorCounter, &bv, NULL );
168 
169 	mp = monitor_entrypriv_create();
170 	if ( mp == NULL ) {
171 		return -1;
172 	}
173 	e->e_private = ( void * )mp;
174 	mp->mp_info = ms;
175 	mp->mp_flags = ms->mss_flags \
176 		| MONITOR_F_SUB | MONITOR_F_PERSISTENT;
177 	mp->mp_flags &= ~MONITOR_F_VOLATILE_CH;
178 
179 	if ( monitor_cache_add( mi, e, e_conn ) ) {
180 		Debug( LDAP_DEBUG_ANY,
181 			"monitor_subsys_conn_init: "
182 			"unable to add entry \"cn=Current,%s\"\n",
183 			ms->mss_ndn.bv_val );
184 		return( -1 );
185 	}
186 
187 	monitor_cache_release( mi, e_conn );
188 
189 	return( 0 );
190 }
191 
192 static int
monitor_subsys_conn_update(Operation * op,SlapReply * rs,Entry * e)193 monitor_subsys_conn_update(
194 	Operation		*op,
195 	SlapReply		*rs,
196 	Entry                   *e )
197 {
198 	monitor_info_t	*mi = ( monitor_info_t * )op->o_bd->be_private;
199 
200 	long 			n = -1;
201 	static struct berval	total_bv = BER_BVC( "cn=total" ),
202 				current_bv = BER_BVC( "cn=current" );
203 	struct berval		rdn;
204 
205 	assert( mi != NULL );
206 	assert( e != NULL );
207 
208 	dnRdn( &e->e_nname, &rdn );
209 
210 	if ( dn_match( &rdn, &total_bv ) ) {
211 		n = connections_nextid() - SLAPD_SYNC_SYNCCONN_OFFSET;
212 
213 	} else if ( dn_match( &rdn, &current_bv ) ) {
214 		Connection	*c;
215 		ber_socket_t	connindex;
216 
217 		for ( n = 0, c = connection_first( &connindex );
218 				c != NULL;
219 				n++, c = connection_next( c, &connindex ) )
220 		{
221 			/* Ignore outbound connections */
222 			if ( c->c_conn_state == SLAP_C_CLIENT )
223 				n--;
224 		}
225 		connection_done( c );
226 	}
227 
228 	if ( n != -1 ) {
229 		Attribute	*a;
230 		char		buf[LDAP_PVT_INTTYPE_CHARS(long)];
231 		ber_len_t	len;
232 
233 		a = attr_find( e->e_attrs, mi->mi_ad_monitorCounter );
234 		if ( a == NULL ) {
235 			return( -1 );
236 		}
237 
238 		snprintf( buf, sizeof( buf ), "%ld", n );
239 		len = strlen( buf );
240 		if ( len > a->a_vals[ 0 ].bv_len ) {
241 			a->a_vals[ 0 ].bv_val = ber_memrealloc( a->a_vals[ 0 ].bv_val, len + 1 );
242 		}
243 		a->a_vals[ 0 ].bv_len = len;
244 		AC_MEMCPY( a->a_vals[ 0 ].bv_val, buf, len + 1 );
245 
246 		/* FIXME: touch modifyTimestamp? */
247 	}
248 
249 	return SLAP_CB_CONTINUE;
250 }
251 
252 static int
conn_create(monitor_info_t * mi,Connection * c,Entry ** ep,monitor_subsys_t * ms)253 conn_create(
254 	monitor_info_t		*mi,
255 	Connection		*c,
256 	Entry			**ep,
257 	monitor_subsys_t	*ms )
258 {
259 	monitor_entry_t *mp;
260 	struct tm	tm;
261 	char		buf[ BACKMONITOR_BUFSIZE ];
262 	char		buf2[ LDAP_LUTIL_GENTIME_BUFSIZE ];
263 	char		buf3[ LDAP_LUTIL_GENTIME_BUFSIZE ];
264 
265 	struct berval bv, ctmbv, mtmbv;
266 	struct berval bv_unknown= BER_BVC("unknown");
267 
268 	Entry		*e;
269 
270 	assert( c != NULL );
271 	assert( ep != NULL );
272 
273 	ldap_pvt_gmtime( &c->c_starttime, &tm );
274 
275 	ctmbv.bv_len = lutil_gentime( buf2, sizeof( buf2 ), &tm );
276 	ctmbv.bv_val = buf2;
277 
278 	ldap_pvt_gmtime( &c->c_activitytime, &tm );
279 	mtmbv.bv_len = lutil_gentime( buf3, sizeof( buf3 ), &tm );
280 	mtmbv.bv_val = buf3;
281 
282 	bv.bv_len = snprintf( buf, sizeof( buf ),
283 		"cn=Connection %ld", c->c_connid );
284 	bv.bv_val = buf;
285 	e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, &bv,
286 		mi->mi_oc_monitorConnection, &ctmbv, &mtmbv );
287 
288 	if ( e == NULL) {
289 		Debug( LDAP_DEBUG_ANY,
290 			"monitor_subsys_conn_create: "
291 			"unable to create entry "
292 			"\"cn=Connection %ld,%s\"\n",
293 			c->c_connid,
294 			ms->mss_dn.bv_val );
295 		return( -1 );
296 	}
297 
298 #ifdef MONITOR_LEGACY_CONN
299 	/* NOTE: this will disappear, as the exploded data
300 	 * has been moved to dedicated attributes */
301 	bv.bv_len = snprintf( buf, sizeof( buf ),
302 			"%ld "
303 			": %ld "
304 			": %ld/%ld/%ld/%ld "
305 			": %ld/%ld/%ld "
306 			": %s%s%s%s%s%s "
307 			": %s "
308 			": %s "
309 			": %s "
310 			": %s "
311 			": %s "
312 			": %s "
313 			": %s",
314 			c->c_connid,
315 			(long) c->c_protocol,
316 			c->c_n_ops_received, c->c_n_ops_executing,
317 				c->c_n_ops_pending, c->c_n_ops_completed,
318 
319 			/* add low-level counters here */
320 			c->c_n_get, c->c_n_read, c->c_n_write,
321 
322 			c->c_currentber ? "r" : "",
323 			c->c_writewaiter ? "w" : "",
324 			LDAP_STAILQ_EMPTY( &c->c_ops ) ? "" : "x",
325 			LDAP_STAILQ_EMPTY( &c->c_pending_ops ) ? "" : "p",
326 			connection_state2str( c->c_conn_state ),
327 			c->c_sasl_bind_in_progress ? "S" : "",
328 
329 			c->c_dn.bv_len ? c->c_dn.bv_val : SLAPD_ANONYMOUS,
330 
331 			c->c_listener_url.bv_val,
332 			BER_BVISNULL( &c->c_peer_domain )
333 				? "" : c->c_peer_domain.bv_val,
334 			BER_BVISNULL( &c->c_peer_name )
335 				? "" : c->c_peer_name.bv_val,
336 			c->c_sock_name.bv_val,
337 
338 			buf2,
339 			buf3 );
340 	attr_merge_normalize_one( e, mi->mi_ad_monitoredInfo, &bv, NULL );
341 #endif /* MONITOR_LEGACY_CONN */
342 
343 	bv.bv_len = snprintf( buf, sizeof( buf ), "%lu", c->c_connid );
344 	attr_merge_one( e, mi->mi_ad_monitorConnectionNumber, &bv, NULL );
345 
346 	bv.bv_len = snprintf( buf, sizeof( buf ), "%ld", (long) c->c_protocol );
347 	attr_merge_normalize_one( e, mi->mi_ad_monitorConnectionProtocol, &bv, NULL );
348 
349 	bv.bv_len = snprintf( buf, sizeof( buf ), "%ld", c->c_n_ops_received );
350 	attr_merge_one( e, mi->mi_ad_monitorConnectionOpsReceived, &bv, NULL );
351 
352 	bv.bv_len = snprintf( buf, sizeof( buf ), "%ld", c->c_n_ops_executing );
353 	attr_merge_one( e, mi->mi_ad_monitorConnectionOpsExecuting, &bv, NULL );
354 
355 	bv.bv_len = snprintf( buf, sizeof( buf ), "%ld", c->c_n_ops_pending );
356 	attr_merge_one( e, mi->mi_ad_monitorConnectionOpsPending, &bv, NULL );
357 
358 	bv.bv_len = snprintf( buf, sizeof( buf ), "%ld", c->c_n_ops_completed );
359 	attr_merge_one( e, mi->mi_ad_monitorConnectionOpsCompleted, &bv, NULL );
360 
361 	bv.bv_len = snprintf( buf, sizeof( buf ), "%ld", c->c_n_ops_async );
362 	attr_merge_one( e, mi->mi_ad_monitorConnectionOpsAsync, &bv, NULL );
363 
364 	bv.bv_len = snprintf( buf, sizeof( buf ), "%ld", c->c_n_get );
365 	attr_merge_one( e, mi->mi_ad_monitorConnectionGet, &bv, NULL );
366 
367 	bv.bv_len = snprintf( buf, sizeof( buf ), "%ld", c->c_n_read );
368 	attr_merge_one( e, mi->mi_ad_monitorConnectionRead, &bv, NULL );
369 
370 	bv.bv_len = snprintf( buf, sizeof( buf ), "%ld", c->c_n_write );
371 	attr_merge_one( e, mi->mi_ad_monitorConnectionWrite, &bv, NULL );
372 
373 	bv.bv_len = snprintf( buf, sizeof( buf ), "%s%s%s%s%s%s",
374 			c->c_currentber ? "r" : "",
375 			c->c_writewaiter ? "w" : "",
376 			LDAP_STAILQ_EMPTY( &c->c_ops ) ? "" : "x",
377 			LDAP_STAILQ_EMPTY( &c->c_pending_ops ) ? "" : "p",
378 			connection_state2str( c->c_conn_state ),
379 			c->c_sasl_bind_in_progress ? "S" : "" );
380 	attr_merge_normalize_one( e, mi->mi_ad_monitorConnectionMask, &bv, NULL );
381 
382 	attr_merge_one( e, mi->mi_ad_monitorConnectionAuthzDN,
383 		&c->c_dn, &c->c_ndn );
384 
385 	/* NOTE: client connections leave the c_peer_* fields NULL */
386 	assert( !BER_BVISNULL( &c->c_listener_url ) );
387 	attr_merge_normalize_one( e, mi->mi_ad_monitorConnectionListener,
388 		&c->c_listener_url, NULL );
389 
390 	attr_merge_normalize_one( e, mi->mi_ad_monitorConnectionPeerDomain,
391 		BER_BVISNULL( &c->c_peer_domain ) ? &bv_unknown : &c->c_peer_domain,
392 		NULL );
393 
394 	attr_merge_normalize_one( e, mi->mi_ad_monitorConnectionPeerAddress,
395 		BER_BVISNULL( &c->c_peer_name ) ? &bv_unknown : &c->c_peer_name,
396 		NULL );
397 
398 	assert( !BER_BVISNULL( &c->c_sock_name ) );
399 	attr_merge_normalize_one( e, mi->mi_ad_monitorConnectionLocalAddress,
400 		&c->c_sock_name, NULL );
401 
402 	attr_merge_normalize_one( e, mi->mi_ad_monitorConnectionStartTime, &ctmbv, NULL );
403 
404 	attr_merge_normalize_one( e, mi->mi_ad_monitorConnectionActivityTime, &mtmbv, NULL );
405 
406 	mp = monitor_entrypriv_create();
407 	if ( mp == NULL ) {
408 		return LDAP_OTHER;
409 	}
410 	e->e_private = ( void * )mp;
411 	mp->mp_info = ms;
412 	mp->mp_flags = MONITOR_F_SUB | MONITOR_F_VOLATILE;
413 
414 	*ep = e;
415 
416 	return SLAP_CB_CONTINUE;
417 }
418 
419 static int
monitor_subsys_conn_create(Operation * op,SlapReply * rs,struct berval * ndn,Entry * e_parent,Entry ** ep)420 monitor_subsys_conn_create(
421 	Operation		*op,
422 	SlapReply		*rs,
423 	struct berval		*ndn,
424 	Entry 			*e_parent,
425 	Entry			**ep )
426 {
427 	monitor_info_t	*mi = ( monitor_info_t * )op->o_bd->be_private;
428 
429 	int			rc = SLAP_CB_CONTINUE;
430 	monitor_subsys_t	*ms;
431 
432 	assert( mi != NULL );
433 	assert( e_parent != NULL );
434 	assert( ep != NULL );
435 
436 	ms = (( monitor_entry_t *)e_parent->e_private)->mp_info;
437 
438 	*ep = NULL;
439 
440 	if ( ndn == NULL ) {
441 		Connection	*c;
442 		ber_socket_t	connindex;
443 		Entry		*e = NULL,
444 				*e_tmp = NULL;
445 
446 		/* create all the children of e_parent */
447 		for ( c = connection_first( &connindex );
448 				c != NULL;
449 				c = connection_next( c, &connindex ) )
450 		{
451 			monitor_entry_t 	*mp;
452 
453 			/* ignore outbound for now, nothing to show */
454 			if ( c->c_conn_state == SLAP_C_CLIENT )
455 				continue;
456 
457 			if ( conn_create( mi, c, &e, ms ) != SLAP_CB_CONTINUE
458 					|| e == NULL )
459 			{
460 				for ( ; e_tmp != NULL; ) {
461 					mp = ( monitor_entry_t * )e_tmp->e_private;
462 					e = mp->mp_next;
463 
464 					ch_free( mp );
465 					e_tmp->e_private = NULL;
466 					entry_free( e_tmp );
467 
468 					e_tmp = e;
469 				}
470 				rc = rs->sr_err = LDAP_OTHER;
471 				break;
472 			}
473 			mp = ( monitor_entry_t * )e->e_private;
474 			mp->mp_next = e_tmp;
475 			e_tmp = e;
476 		}
477 		connection_done( c );
478 		*ep = e;
479 
480 	} else {
481 		Connection		*c;
482 		ber_socket_t		connindex;
483 		unsigned long 		connid;
484 		char			*next = NULL;
485 		static struct berval	nconn_bv = BER_BVC( "cn=connection " );
486 
487 		rc = LDAP_NO_SUCH_OBJECT;
488 
489 		/* create exactly the required entry;
490 		 * the normalized DN must start with "cn=connection ",
491 		 * followed by the connection id, followed by
492 		 * the RDN separator "," */
493 		if ( ndn->bv_len <= nconn_bv.bv_len
494 				|| strncmp( ndn->bv_val, nconn_bv.bv_val, nconn_bv.bv_len ) != 0 )
495 		{
496 			return -1;
497 		}
498 
499 		connid = strtol( &ndn->bv_val[ nconn_bv.bv_len ], &next, 10 );
500 		if ( next[ 0 ] != ',' ) {
501 			return ( rs->sr_err = LDAP_OTHER );
502 		}
503 
504 		for ( c = connection_first( &connindex );
505 				c != NULL;
506 				c = connection_next( c, &connindex ) )
507 		{
508 			if ( c->c_connid == connid ) {
509 				rc = conn_create( mi, c, ep, ms );
510 				if ( rc != SLAP_CB_CONTINUE ) {
511 					rs->sr_err = rc;
512 
513 				} else if ( *ep == NULL ) {
514 					rc = rs->sr_err = LDAP_OTHER;
515 				}
516 
517 				break;
518 			}
519 		}
520 
521 		connection_done( c );
522 	}
523 
524 	return rc;
525 }
526 
527