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