1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * 3*0Sstevel@tonic-gate * Portions Copyright %G% Sun Microsystems, Inc. 4*0Sstevel@tonic-gate * All Rights Reserved 5*0Sstevel@tonic-gate * 6*0Sstevel@tonic-gate */ 7*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 8*0Sstevel@tonic-gate /* 9*0Sstevel@tonic-gate * Copyright (c) 1993 The Regents of the University of Michigan. 10*0Sstevel@tonic-gate * All rights reserved. 11*0Sstevel@tonic-gate * 12*0Sstevel@tonic-gate * cache.c - local caching support for LDAP 13*0Sstevel@tonic-gate */ 14*0Sstevel@tonic-gate 15*0Sstevel@tonic-gate #ifndef NO_CACHE 16*0Sstevel@tonic-gate 17*0Sstevel@tonic-gate #ifndef lint 18*0Sstevel@tonic-gate static char copyright[] = "@(#) Copyright (c) 1993 The Regents of the University of Michigan.\nAll rights reserved.\n"; 19*0Sstevel@tonic-gate #endif 20*0Sstevel@tonic-gate 21*0Sstevel@tonic-gate #include <stdio.h> 22*0Sstevel@tonic-gate #include <string.h> 23*0Sstevel@tonic-gate #ifdef MACOS 24*0Sstevel@tonic-gate #include <stdlib.h> 25*0Sstevel@tonic-gate #include <time.h> 26*0Sstevel@tonic-gate #include "macos.h" 27*0Sstevel@tonic-gate #else /* MACOS */ 28*0Sstevel@tonic-gate #if defined( DOS ) || defined( _WIN32 ) 29*0Sstevel@tonic-gate #include <malloc.h> 30*0Sstevel@tonic-gate #include "msdos.h" 31*0Sstevel@tonic-gate #ifdef NCSA 32*0Sstevel@tonic-gate #include "externs.h" 33*0Sstevel@tonic-gate #endif /* NCSA */ 34*0Sstevel@tonic-gate #ifdef WINSOCK 35*0Sstevel@tonic-gate #include <time.h> 36*0Sstevel@tonic-gate #endif /* WINSOCK */ 37*0Sstevel@tonic-gate #else /* DOS */ 38*0Sstevel@tonic-gate #include <sys/types.h> 39*0Sstevel@tonic-gate #include <sys/socket.h> 40*0Sstevel@tonic-gate #endif /* DOS */ 41*0Sstevel@tonic-gate #endif /* MACOS */ 42*0Sstevel@tonic-gate #include "lber.h" 43*0Sstevel@tonic-gate #include "ldap.h" 44*0Sstevel@tonic-gate #include "ldap-private.h" 45*0Sstevel@tonic-gate #include "ldap-int.h" 46*0Sstevel@tonic-gate 47*0Sstevel@tonic-gate #ifdef NEEDPROTOS 48*0Sstevel@tonic-gate static int cache_hash( BerElement *ber ); 49*0Sstevel@tonic-gate static LDAPMessage *msg_dup( LDAPMessage *msg ); 50*0Sstevel@tonic-gate static int request_cmp( BerElement *req1, BerElement *req2 ); 51*0Sstevel@tonic-gate static int chain_contains_dn( LDAPMessage *msg, char *dn ); 52*0Sstevel@tonic-gate static ssize_t msg_size( LDAPMessage *msg ); 53*0Sstevel@tonic-gate static void check_cache_memused( LDAPCache *lc ); 54*0Sstevel@tonic-gate static void uncache_entry_or_req( LDAP *ld, char *dn, int msgid ); 55*0Sstevel@tonic-gate #else /* NEEDPROTOS */ 56*0Sstevel@tonic-gate static int cache_hash(); 57*0Sstevel@tonic-gate static LDAPMessage *msg_dup(); 58*0Sstevel@tonic-gate static int request_cmp(); 59*0Sstevel@tonic-gate static int chain_contains_dn(); 60*0Sstevel@tonic-gate static ssize_t msg_size(); 61*0Sstevel@tonic-gate static void check_cache_memused(); 62*0Sstevel@tonic-gate static void uncache_entry_or_req(); 63*0Sstevel@tonic-gate #endif /* NEEDPROTOS */ 64*0Sstevel@tonic-gate 65*0Sstevel@tonic-gate 66*0Sstevel@tonic-gate int 67*0Sstevel@tonic-gate ldap_enable_cache( LDAP *ld, time_t timeout, ssize_t maxmem ) 68*0Sstevel@tonic-gate { 69*0Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 70*0Sstevel@tonic-gate LOCK_LDAP(ld); 71*0Sstevel@tonic-gate #endif 72*0Sstevel@tonic-gate if ( ld->ld_cache == NULLLDCACHE ) { 73*0Sstevel@tonic-gate if (( ld->ld_cache = (LDAPCache *)malloc( sizeof( LDAPCache ))) 74*0Sstevel@tonic-gate == NULLLDCACHE ) { 75*0Sstevel@tonic-gate ld->ld_errno = LDAP_NO_MEMORY; 76*0Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 77*0Sstevel@tonic-gate UNLOCK_LDAP(ld); 78*0Sstevel@tonic-gate #endif 79*0Sstevel@tonic-gate return( -1 ); 80*0Sstevel@tonic-gate } 81*0Sstevel@tonic-gate (void) memset( ld->ld_cache, 0, sizeof( LDAPCache )); 82*0Sstevel@tonic-gate ld->ld_cache->lc_memused = sizeof( LDAPCache ); 83*0Sstevel@tonic-gate } 84*0Sstevel@tonic-gate 85*0Sstevel@tonic-gate ld->ld_cache->lc_timeout = timeout; 86*0Sstevel@tonic-gate ld->ld_cache->lc_maxmem = maxmem; 87*0Sstevel@tonic-gate check_cache_memused( ld->ld_cache ); 88*0Sstevel@tonic-gate ld->ld_cache->lc_enabled = 1; 89*0Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 90*0Sstevel@tonic-gate UNLOCK_LDAP(ld); 91*0Sstevel@tonic-gate #endif 92*0Sstevel@tonic-gate return( 0 ); 93*0Sstevel@tonic-gate } 94*0Sstevel@tonic-gate 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gate void 97*0Sstevel@tonic-gate ldap_disable_cache( LDAP *ld ) 98*0Sstevel@tonic-gate { 99*0Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 100*0Sstevel@tonic-gate LOCK_LDAP(ld); 101*0Sstevel@tonic-gate #endif 102*0Sstevel@tonic-gate if ( ld->ld_cache != NULLLDCACHE ) { 103*0Sstevel@tonic-gate ld->ld_cache->lc_enabled = 0; 104*0Sstevel@tonic-gate } 105*0Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 106*0Sstevel@tonic-gate UNLOCK_LDAP(ld); 107*0Sstevel@tonic-gate #endif 108*0Sstevel@tonic-gate } 109*0Sstevel@tonic-gate 110*0Sstevel@tonic-gate 111*0Sstevel@tonic-gate 112*0Sstevel@tonic-gate void 113*0Sstevel@tonic-gate ldap_set_cache_options( LDAP *ld, unsigned int opts ) 114*0Sstevel@tonic-gate { 115*0Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 116*0Sstevel@tonic-gate LOCK_LDAP(ld); 117*0Sstevel@tonic-gate #endif 118*0Sstevel@tonic-gate if ( ld->ld_cache != NULLLDCACHE ) { 119*0Sstevel@tonic-gate ld->ld_cache->lc_options = opts; 120*0Sstevel@tonic-gate } 121*0Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 122*0Sstevel@tonic-gate UNLOCK_LDAP(ld); 123*0Sstevel@tonic-gate #endif 124*0Sstevel@tonic-gate } 125*0Sstevel@tonic-gate 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gate void 128*0Sstevel@tonic-gate ldap_destroy_cache( LDAP *ld ) 129*0Sstevel@tonic-gate { 130*0Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 131*0Sstevel@tonic-gate LOCK_LDAP(ld); 132*0Sstevel@tonic-gate #endif 133*0Sstevel@tonic-gate if ( ld->ld_cache != NULLLDCACHE ) { 134*0Sstevel@tonic-gate ldap_flush_cache( ld ); 135*0Sstevel@tonic-gate free( (char *)ld->ld_cache ); 136*0Sstevel@tonic-gate ld->ld_cache = NULLLDCACHE; 137*0Sstevel@tonic-gate } 138*0Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 139*0Sstevel@tonic-gate UNLOCK_LDAP(ld); 140*0Sstevel@tonic-gate #endif 141*0Sstevel@tonic-gate } 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate 144*0Sstevel@tonic-gate void 145*0Sstevel@tonic-gate ldap_flush_cache( LDAP *ld ) 146*0Sstevel@tonic-gate { 147*0Sstevel@tonic-gate int i; 148*0Sstevel@tonic-gate LDAPMessage *m, *next; 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 151*0Sstevel@tonic-gate LOCK_LDAP(ld); 152*0Sstevel@tonic-gate #endif 153*0Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 90, "ldap_flush_cache\n"), 0, 0, 0 ); 154*0Sstevel@tonic-gate 155*0Sstevel@tonic-gate if ( ld->ld_cache != NULLLDCACHE ) { 156*0Sstevel@tonic-gate /* delete all requests in the queue */ 157*0Sstevel@tonic-gate for ( m = ld->ld_cache->lc_requests; m != NULLMSG; m = next ) { 158*0Sstevel@tonic-gate next = m->lm_next; 159*0Sstevel@tonic-gate ldap_msgfree( m ); 160*0Sstevel@tonic-gate } 161*0Sstevel@tonic-gate ld->ld_cache->lc_requests = NULLMSG; 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gate /* delete all messages in the cache */ 164*0Sstevel@tonic-gate for ( i = 0; i < LDAP_CACHE_BUCKETS; ++i ) { 165*0Sstevel@tonic-gate for ( m = ld->ld_cache->lc_buckets[ i ]; 166*0Sstevel@tonic-gate m != NULLMSG; m = next ) { 167*0Sstevel@tonic-gate next = m->lm_next; 168*0Sstevel@tonic-gate ldap_msgfree( m ); 169*0Sstevel@tonic-gate } 170*0Sstevel@tonic-gate ld->ld_cache->lc_buckets[ i ] = NULLMSG; 171*0Sstevel@tonic-gate } 172*0Sstevel@tonic-gate ld->ld_cache->lc_memused = sizeof( LDAPCache ); 173*0Sstevel@tonic-gate } 174*0Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 175*0Sstevel@tonic-gate UNLOCK_LDAP(ld); 176*0Sstevel@tonic-gate #endif 177*0Sstevel@tonic-gate } 178*0Sstevel@tonic-gate 179*0Sstevel@tonic-gate 180*0Sstevel@tonic-gate void 181*0Sstevel@tonic-gate ldap_uncache_request( LDAP *ld, int msgid ) 182*0Sstevel@tonic-gate { 183*0Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 184*0Sstevel@tonic-gate LOCK_LDAP(ld); 185*0Sstevel@tonic-gate #endif 186*0Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 91, "ldap_uncache_request %1$d ld_cache %2$x\n"), 187*0Sstevel@tonic-gate msgid, ld->ld_cache, 0 ); 188*0Sstevel@tonic-gate 189*0Sstevel@tonic-gate uncache_entry_or_req( ld, NULL, msgid ); 190*0Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 191*0Sstevel@tonic-gate UNLOCK_LDAP(ld); 192*0Sstevel@tonic-gate #endif 193*0Sstevel@tonic-gate } 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gate 196*0Sstevel@tonic-gate void 197*0Sstevel@tonic-gate ldap_uncache_entry( LDAP *ld, char *dn ) 198*0Sstevel@tonic-gate { 199*0Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 200*0Sstevel@tonic-gate LOCK_LDAP(ld); 201*0Sstevel@tonic-gate #endif 202*0Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 92, "ldap_uncache_entry %1$s ld_cache %2$x\n"), 203*0Sstevel@tonic-gate dn, ld->ld_cache, 0 ); 204*0Sstevel@tonic-gate 205*0Sstevel@tonic-gate uncache_entry_or_req( ld, dn, 0 ); 206*0Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 207*0Sstevel@tonic-gate UNLOCK_LDAP(ld); 208*0Sstevel@tonic-gate #endif 209*0Sstevel@tonic-gate } 210*0Sstevel@tonic-gate 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate static void 213*0Sstevel@tonic-gate uncache_entry_or_req( LDAP *ld, 214*0Sstevel@tonic-gate char *dn, /* if non-NULL, uncache entry */ 215*0Sstevel@tonic-gate int msgid ) /* request to uncache (if dn == NULL) */ 216*0Sstevel@tonic-gate { 217*0Sstevel@tonic-gate int i; 218*0Sstevel@tonic-gate LDAPMessage *m, *prev, *next; 219*0Sstevel@tonic-gate 220*0Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, 221*0Sstevel@tonic-gate catgets(slapdcat, 1, 93, "ldap_uncache_entry_or_req dn %1$s msgid %2$d ld_cache %3$x\n"), 222*0Sstevel@tonic-gate dn, msgid, ld->ld_cache ); 223*0Sstevel@tonic-gate 224*0Sstevel@tonic-gate if ( ld->ld_cache == NULLLDCACHE ) { 225*0Sstevel@tonic-gate return; 226*0Sstevel@tonic-gate } 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gate /* first check the request queue */ 229*0Sstevel@tonic-gate prev = NULLMSG; 230*0Sstevel@tonic-gate for ( m = ld->ld_cache->lc_requests; m != NULLMSG; m = next ) { 231*0Sstevel@tonic-gate next = m->lm_next; 232*0Sstevel@tonic-gate if (( dn != NULL && chain_contains_dn( m, dn )) || 233*0Sstevel@tonic-gate ( dn == NULL && m->lm_msgid == msgid )) { 234*0Sstevel@tonic-gate if ( prev == NULLMSG ) { 235*0Sstevel@tonic-gate ld->ld_cache->lc_requests = next; 236*0Sstevel@tonic-gate } else { 237*0Sstevel@tonic-gate prev->lm_next = next; 238*0Sstevel@tonic-gate } 239*0Sstevel@tonic-gate ld->ld_cache->lc_memused -= msg_size( m ); 240*0Sstevel@tonic-gate ldap_msgfree( m ); 241*0Sstevel@tonic-gate } else { 242*0Sstevel@tonic-gate prev = m; 243*0Sstevel@tonic-gate } 244*0Sstevel@tonic-gate } 245*0Sstevel@tonic-gate 246*0Sstevel@tonic-gate /* now check the rest of the cache */ 247*0Sstevel@tonic-gate for ( i = 0; i < LDAP_CACHE_BUCKETS; ++i ) { 248*0Sstevel@tonic-gate prev = NULLMSG; 249*0Sstevel@tonic-gate for ( m = ld->ld_cache->lc_buckets[ i ]; m != NULLMSG; 250*0Sstevel@tonic-gate m = next ) { 251*0Sstevel@tonic-gate next = m->lm_next; 252*0Sstevel@tonic-gate if (( dn != NULL && chain_contains_dn( m, dn )) || 253*0Sstevel@tonic-gate ( dn == NULL && m->lm_msgid == msgid )) { 254*0Sstevel@tonic-gate if ( prev == NULLMSG ) { 255*0Sstevel@tonic-gate ld->ld_cache->lc_buckets[ i ] = next; 256*0Sstevel@tonic-gate } else { 257*0Sstevel@tonic-gate prev->lm_next = next; 258*0Sstevel@tonic-gate } 259*0Sstevel@tonic-gate ld->ld_cache->lc_memused -= msg_size( m ); 260*0Sstevel@tonic-gate ldap_msgfree( m ); 261*0Sstevel@tonic-gate } else { 262*0Sstevel@tonic-gate prev = m; 263*0Sstevel@tonic-gate } 264*0Sstevel@tonic-gate } 265*0Sstevel@tonic-gate } 266*0Sstevel@tonic-gate } 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gate 269*0Sstevel@tonic-gate void 270*0Sstevel@tonic-gate add_request_to_cache( LDAP *ld, unsigned int msgtype, BerElement *request ) 271*0Sstevel@tonic-gate { 272*0Sstevel@tonic-gate LDAPMessage *new; 273*0Sstevel@tonic-gate size_t len; 274*0Sstevel@tonic-gate 275*0Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 94, "add_request_to_cache\n"), 0, 0, 0 ); 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate ld->ld_errno = LDAP_SUCCESS; 278*0Sstevel@tonic-gate if ( ld->ld_cache == NULLLDCACHE || 279*0Sstevel@tonic-gate ( ld->ld_cache->lc_enabled == 0 )) { 280*0Sstevel@tonic-gate return; 281*0Sstevel@tonic-gate } 282*0Sstevel@tonic-gate 283*0Sstevel@tonic-gate if (( new = (LDAPMessage *) calloc( 1, sizeof(LDAPMessage) )) 284*0Sstevel@tonic-gate != NULL ) { 285*0Sstevel@tonic-gate if (( new->lm_ber = alloc_ber_with_options( ld )) == NULLBER ) { 286*0Sstevel@tonic-gate free( (char *)new ); 287*0Sstevel@tonic-gate return; 288*0Sstevel@tonic-gate } 289*0Sstevel@tonic-gate len = request->ber_ptr - request->ber_buf; 290*0Sstevel@tonic-gate if (( new->lm_ber->ber_buf = (char *) malloc( len )) 291*0Sstevel@tonic-gate == NULL ) { 292*0Sstevel@tonic-gate ber_free( new->lm_ber, 0 ); 293*0Sstevel@tonic-gate free( (char *)new ); 294*0Sstevel@tonic-gate ld->ld_errno = LDAP_NO_MEMORY; 295*0Sstevel@tonic-gate return; 296*0Sstevel@tonic-gate } 297*0Sstevel@tonic-gate SAFEMEMCPY( new->lm_ber->ber_buf, request->ber_buf, len ); 298*0Sstevel@tonic-gate new->lm_ber->ber_ptr = new->lm_ber->ber_buf; 299*0Sstevel@tonic-gate new->lm_ber->ber_end = new->lm_ber->ber_buf + len; 300*0Sstevel@tonic-gate new->lm_msgid = ld->ld_msgid; 301*0Sstevel@tonic-gate new->lm_msgtype = (int) msgtype;; 302*0Sstevel@tonic-gate new->lm_next = ld->ld_cache->lc_requests; 303*0Sstevel@tonic-gate ld->ld_cache->lc_requests = new; 304*0Sstevel@tonic-gate } else { 305*0Sstevel@tonic-gate ld->ld_errno = LDAP_NO_MEMORY; 306*0Sstevel@tonic-gate } 307*0Sstevel@tonic-gate } 308*0Sstevel@tonic-gate 309*0Sstevel@tonic-gate 310*0Sstevel@tonic-gate void 311*0Sstevel@tonic-gate add_result_to_cache( LDAP *ld, LDAPMessage *result ) 312*0Sstevel@tonic-gate { 313*0Sstevel@tonic-gate LDAPMessage *m, **mp, *req, *new, *prev; 314*0Sstevel@tonic-gate int err, keep; 315*0Sstevel@tonic-gate 316*0Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 95, "add_result_to_cache: id %1$d, type %2$d\n"), 317*0Sstevel@tonic-gate result->lm_msgid, result->lm_msgtype, 0 ); 318*0Sstevel@tonic-gate 319*0Sstevel@tonic-gate if ( ld->ld_cache == NULLLDCACHE || 320*0Sstevel@tonic-gate ( ld->ld_cache->lc_enabled == 0 )) { 321*0Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 96, "artc: cache disabled\n"), 0, 0, 0 ); 322*0Sstevel@tonic-gate return; 323*0Sstevel@tonic-gate } 324*0Sstevel@tonic-gate 325*0Sstevel@tonic-gate if ( result->lm_msgtype != LDAP_RES_SEARCH_ENTRY && 326*0Sstevel@tonic-gate result->lm_msgtype != LDAP_RES_SEARCH_RESULT && 327*0Sstevel@tonic-gate result->lm_msgtype != LDAP_RES_SEARCH_REFERENCE && 328*0Sstevel@tonic-gate result->lm_msgtype != LDAP_RES_COMPARE ) { 329*0Sstevel@tonic-gate /* 330*0Sstevel@tonic-gate * only cache search and compare operations 331*0Sstevel@tonic-gate */ 332*0Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, 333*0Sstevel@tonic-gate catgets(slapdcat, 1, 97, "artc: only caching search & compare operations\n"), 0, 0, 0 ); 334*0Sstevel@tonic-gate return; 335*0Sstevel@tonic-gate } 336*0Sstevel@tonic-gate 337*0Sstevel@tonic-gate /* 338*0Sstevel@tonic-gate * if corresponding request is in the lc_requests list, add this 339*0Sstevel@tonic-gate * result to it. if this result completes the results for the 340*0Sstevel@tonic-gate * request, add the request/result chain to the cache proper. 341*0Sstevel@tonic-gate */ 342*0Sstevel@tonic-gate prev = NULLMSG; 343*0Sstevel@tonic-gate for ( m = ld->ld_cache->lc_requests; m != NULL; m = m->lm_next ) { 344*0Sstevel@tonic-gate if ( m->lm_msgid == result->lm_msgid ) { 345*0Sstevel@tonic-gate break; 346*0Sstevel@tonic-gate } 347*0Sstevel@tonic-gate prev = m; 348*0Sstevel@tonic-gate } 349*0Sstevel@tonic-gate 350*0Sstevel@tonic-gate if ( m != NULLMSG ) { /* found request; add to end of chain */ 351*0Sstevel@tonic-gate req = m; 352*0Sstevel@tonic-gate for ( ; m->lm_chain != NULLMSG; m = m->lm_chain ) 353*0Sstevel@tonic-gate ; 354*0Sstevel@tonic-gate if (( new = msg_dup( result )) != NULLMSG ) { 355*0Sstevel@tonic-gate new->lm_chain = NULLMSG; 356*0Sstevel@tonic-gate m->lm_chain = new; 357*0Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, 358*0Sstevel@tonic-gate catgets(slapdcat, 1, 98, "artc: result added to cache request chain\n"), 359*0Sstevel@tonic-gate 0, 0, 0 ); 360*0Sstevel@tonic-gate } 361*0Sstevel@tonic-gate if ( result->lm_msgtype == LDAP_RES_SEARCH_RESULT || 362*0Sstevel@tonic-gate result->lm_msgtype == LDAP_RES_COMPARE ) { 363*0Sstevel@tonic-gate /* 364*0Sstevel@tonic-gate * this result completes the chain of results 365*0Sstevel@tonic-gate * add to cache proper if appropriate 366*0Sstevel@tonic-gate */ 367*0Sstevel@tonic-gate keep = 0; /* pessimistic */ 368*0Sstevel@tonic-gate err = ldap_result2error( ld, result, 0 ); 369*0Sstevel@tonic-gate if ( err == LDAP_SUCCESS || 370*0Sstevel@tonic-gate ( result->lm_msgtype == LDAP_RES_COMPARE && 371*0Sstevel@tonic-gate ( err == LDAP_COMPARE_FALSE || 372*0Sstevel@tonic-gate err == LDAP_COMPARE_TRUE || 373*0Sstevel@tonic-gate err == LDAP_NO_SUCH_ATTRIBUTE ))) { 374*0Sstevel@tonic-gate keep = 1; 375*0Sstevel@tonic-gate } 376*0Sstevel@tonic-gate 377*0Sstevel@tonic-gate if ( ld->ld_cache->lc_options == 0 ) { 378*0Sstevel@tonic-gate if ( err == LDAP_SIZELIMIT_EXCEEDED ) { 379*0Sstevel@tonic-gate keep = 1; 380*0Sstevel@tonic-gate } 381*0Sstevel@tonic-gate } else if (( ld->ld_cache->lc_options & 382*0Sstevel@tonic-gate LDAP_CACHE_OPT_CACHEALLERRS ) != 0 ) { 383*0Sstevel@tonic-gate keep = 1; 384*0Sstevel@tonic-gate } 385*0Sstevel@tonic-gate 386*0Sstevel@tonic-gate if ( prev == NULLMSG ) { 387*0Sstevel@tonic-gate ld->ld_cache->lc_requests = req->lm_next; 388*0Sstevel@tonic-gate } else { 389*0Sstevel@tonic-gate prev->lm_next = req->lm_next; 390*0Sstevel@tonic-gate } 391*0Sstevel@tonic-gate 392*0Sstevel@tonic-gate if ( !keep ) { 393*0Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, 394*0Sstevel@tonic-gate catgets(slapdcat, 1, 99, "artc: not caching result with error %d\n"), 395*0Sstevel@tonic-gate err, 0, 0 ); 396*0Sstevel@tonic-gate ldap_msgfree( req ); 397*0Sstevel@tonic-gate } else { 398*0Sstevel@tonic-gate mp = &ld->ld_cache->lc_buckets[ 399*0Sstevel@tonic-gate cache_hash( req->lm_ber ) ]; 400*0Sstevel@tonic-gate req->lm_next = *mp; 401*0Sstevel@tonic-gate *mp = req; 402*0Sstevel@tonic-gate req->lm_time = time( NULL ); 403*0Sstevel@tonic-gate ld->ld_cache->lc_memused += msg_size( req ); 404*0Sstevel@tonic-gate check_cache_memused( ld->ld_cache ); 405*0Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, 406*0Sstevel@tonic-gate catgets(slapdcat, 1, 100, "artc: cached result with error %d\n"), 407*0Sstevel@tonic-gate err, 0, 0 ); 408*0Sstevel@tonic-gate } 409*0Sstevel@tonic-gate } 410*0Sstevel@tonic-gate } else { 411*0Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 101, "artc: msgid not in request list\n"), 412*0Sstevel@tonic-gate 0, 0, 0 ); 413*0Sstevel@tonic-gate } 414*0Sstevel@tonic-gate } 415*0Sstevel@tonic-gate 416*0Sstevel@tonic-gate 417*0Sstevel@tonic-gate /* 418*0Sstevel@tonic-gate * look in the cache for this request 419*0Sstevel@tonic-gate * return 0 if found, -1 if not 420*0Sstevel@tonic-gate * if found, the corresponding result messages are added to the incoming 421*0Sstevel@tonic-gate * queue with the correct (new) msgid so that subsequent ldap_result calls 422*0Sstevel@tonic-gate * will find them. 423*0Sstevel@tonic-gate */ 424*0Sstevel@tonic-gate int 425*0Sstevel@tonic-gate check_cache( LDAP *ld, unsigned int msgtype, BerElement *request ) 426*0Sstevel@tonic-gate { 427*0Sstevel@tonic-gate LDAPMessage *m, *new, *prev, *next; 428*0Sstevel@tonic-gate BerElement reqber; 429*0Sstevel@tonic-gate int first, hash; 430*0Sstevel@tonic-gate unsigned long validtime; 431*0Sstevel@tonic-gate 432*0Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 102, "check_cache\n"), 0, 0, 0 ); 433*0Sstevel@tonic-gate 434*0Sstevel@tonic-gate if ( ld->ld_cache == NULLLDCACHE || 435*0Sstevel@tonic-gate ( ld->ld_cache->lc_enabled == 0 )) { 436*0Sstevel@tonic-gate return( -1 ); 437*0Sstevel@tonic-gate } 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate reqber.ber_buf = reqber.ber_ptr = request->ber_buf; 440*0Sstevel@tonic-gate reqber.ber_end = request->ber_ptr; 441*0Sstevel@tonic-gate 442*0Sstevel@tonic-gate validtime = time( NULL ) - ld->ld_cache->lc_timeout; 443*0Sstevel@tonic-gate 444*0Sstevel@tonic-gate prev = NULLMSG; 445*0Sstevel@tonic-gate hash = cache_hash( &reqber ); 446*0Sstevel@tonic-gate for ( m = ld->ld_cache->lc_buckets[ hash ]; m != NULLMSG; m = next ) { 447*0Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE,catgets(slapdcat, 1, 103, "cc: examining id %1$d,type %2$d\n"), 448*0Sstevel@tonic-gate m->lm_msgid, m->lm_msgtype, 0 ); 449*0Sstevel@tonic-gate if ( m->lm_time < validtime ) { 450*0Sstevel@tonic-gate /* delete expired message */ 451*0Sstevel@tonic-gate next = m->lm_next; 452*0Sstevel@tonic-gate if ( prev == NULL ) { 453*0Sstevel@tonic-gate ld->ld_cache->lc_buckets[ hash ] = next; 454*0Sstevel@tonic-gate } else { 455*0Sstevel@tonic-gate prev->lm_next = next; 456*0Sstevel@tonic-gate } 457*0Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 104, "cc: expired id %d\n"), 458*0Sstevel@tonic-gate m->lm_msgid, 0, 0 ); 459*0Sstevel@tonic-gate ld->ld_cache->lc_memused -= msg_size( m ); 460*0Sstevel@tonic-gate ldap_msgfree( m ); 461*0Sstevel@tonic-gate } else { 462*0Sstevel@tonic-gate if ( m->lm_msgtype == msgtype && 463*0Sstevel@tonic-gate request_cmp( m->lm_ber, &reqber ) == 0 ) { 464*0Sstevel@tonic-gate break; 465*0Sstevel@tonic-gate } 466*0Sstevel@tonic-gate next = m->lm_next; 467*0Sstevel@tonic-gate prev = m; 468*0Sstevel@tonic-gate } 469*0Sstevel@tonic-gate } 470*0Sstevel@tonic-gate 471*0Sstevel@tonic-gate if ( m == NULLMSG ) { 472*0Sstevel@tonic-gate return( -1 ); 473*0Sstevel@tonic-gate } 474*0Sstevel@tonic-gate 475*0Sstevel@tonic-gate /* 476*0Sstevel@tonic-gate * add duplicates of responses to incoming queue 477*0Sstevel@tonic-gate */ 478*0Sstevel@tonic-gate first = 1; 479*0Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 480*0Sstevel@tonic-gate LOCK_RESPONSE(ld); 481*0Sstevel@tonic-gate #endif 482*0Sstevel@tonic-gate for ( m = m->lm_chain; m != NULLMSG; m = m->lm_chain ) { 483*0Sstevel@tonic-gate if (( new = msg_dup( m )) == NULLMSG ) { 484*0Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 485*0Sstevel@tonic-gate UNLOCK_RESPONSE(ld); 486*0Sstevel@tonic-gate #endif 487*0Sstevel@tonic-gate return( -1 ); 488*0Sstevel@tonic-gate } 489*0Sstevel@tonic-gate 490*0Sstevel@tonic-gate new->lm_msgid = ld->ld_msgid; 491*0Sstevel@tonic-gate new->lm_chain = NULLMSG; 492*0Sstevel@tonic-gate if ( first ) { 493*0Sstevel@tonic-gate new->lm_next = ld->ld_responses; 494*0Sstevel@tonic-gate ld->ld_responses = new; 495*0Sstevel@tonic-gate first = 0; 496*0Sstevel@tonic-gate } else { 497*0Sstevel@tonic-gate prev->lm_chain = new; 498*0Sstevel@tonic-gate } 499*0Sstevel@tonic-gate prev = new; 500*0Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 105, "cc: added type %d\n"), 501*0Sstevel@tonic-gate new->lm_msgtype, 0, 0 ); 502*0Sstevel@tonic-gate } 503*0Sstevel@tonic-gate 504*0Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 106, "cc: result returned from cache\n"), 0, 0, 0 ); 505*0Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 506*0Sstevel@tonic-gate UNLOCK_RESPONSE(ld); 507*0Sstevel@tonic-gate #endif 508*0Sstevel@tonic-gate return( 0 ); 509*0Sstevel@tonic-gate } 510*0Sstevel@tonic-gate 511*0Sstevel@tonic-gate 512*0Sstevel@tonic-gate static int 513*0Sstevel@tonic-gate cache_hash( BerElement *ber ) 514*0Sstevel@tonic-gate { 515*0Sstevel@tonic-gate BerElement bercpy; 516*0Sstevel@tonic-gate unsigned int len; 517*0Sstevel@tonic-gate 518*0Sstevel@tonic-gate /* 519*0Sstevel@tonic-gate * just take the length of the packet and mod with # of buckets 520*0Sstevel@tonic-gate */ 521*0Sstevel@tonic-gate bercpy = *ber; 522*0Sstevel@tonic-gate if ( ber_skip_tag( &bercpy, &len ) == LBER_ERROR 523*0Sstevel@tonic-gate || ber_scanf( &bercpy, "x" ) == LBER_ERROR ) { 524*0Sstevel@tonic-gate len = 0; /* punt: just return zero */ 525*0Sstevel@tonic-gate } else { 526*0Sstevel@tonic-gate len = (int) ( bercpy.ber_end - bercpy.ber_ptr ); 527*0Sstevel@tonic-gate } 528*0Sstevel@tonic-gate 529*0Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 107, "cache_hash: len is %1$ld, returning %2$ld\n"), 530*0Sstevel@tonic-gate len, len % LDAP_CACHE_BUCKETS, 0 ); 531*0Sstevel@tonic-gate return ( len % LDAP_CACHE_BUCKETS ); 532*0Sstevel@tonic-gate } 533*0Sstevel@tonic-gate 534*0Sstevel@tonic-gate 535*0Sstevel@tonic-gate static LDAPMessage * 536*0Sstevel@tonic-gate msg_dup( LDAPMessage *msg ) 537*0Sstevel@tonic-gate { 538*0Sstevel@tonic-gate LDAPMessage *new; 539*0Sstevel@tonic-gate size_t len; 540*0Sstevel@tonic-gate 541*0Sstevel@tonic-gate if (( new = (LDAPMessage *)malloc( sizeof(LDAPMessage))) != NULL ) { 542*0Sstevel@tonic-gate *new = *msg; /* struct copy */ 543*0Sstevel@tonic-gate if (( new->lm_ber = ber_dup( msg->lm_ber )) == NULLBER ) { 544*0Sstevel@tonic-gate free( (char *)new ); 545*0Sstevel@tonic-gate return( NULLMSG ); 546*0Sstevel@tonic-gate } 547*0Sstevel@tonic-gate len = msg->lm_ber->ber_end - msg->lm_ber->ber_buf; 548*0Sstevel@tonic-gate if (( new->lm_ber->ber_buf = (char *) malloc( len )) == NULL ) { 549*0Sstevel@tonic-gate ber_free( new->lm_ber, 0 ); 550*0Sstevel@tonic-gate free( (char *)new ); 551*0Sstevel@tonic-gate return( NULLMSG ); 552*0Sstevel@tonic-gate } 553*0Sstevel@tonic-gate SAFEMEMCPY( new->lm_ber->ber_buf, msg->lm_ber->ber_buf, len ); 554*0Sstevel@tonic-gate 555*0Sstevel@tonic-gate new->lm_ber->ber_ptr = new->lm_ber->ber_buf + 556*0Sstevel@tonic-gate ( msg->lm_ber->ber_ptr - msg->lm_ber->ber_buf ); 557*0Sstevel@tonic-gate new->lm_ber->ber_end = new->lm_ber->ber_buf + len; 558*0Sstevel@tonic-gate } 559*0Sstevel@tonic-gate 560*0Sstevel@tonic-gate return( new ); 561*0Sstevel@tonic-gate } 562*0Sstevel@tonic-gate 563*0Sstevel@tonic-gate 564*0Sstevel@tonic-gate static int 565*0Sstevel@tonic-gate request_cmp( BerElement *req1, BerElement *req2 ) 566*0Sstevel@tonic-gate { 567*0Sstevel@tonic-gate unsigned int len; 568*0Sstevel@tonic-gate size_t slen; 569*0Sstevel@tonic-gate BerElement r1, r2; 570*0Sstevel@tonic-gate 571*0Sstevel@tonic-gate r1 = *req1; /* struct copies */ 572*0Sstevel@tonic-gate r2 = *req2; 573*0Sstevel@tonic-gate 574*0Sstevel@tonic-gate /* 575*0Sstevel@tonic-gate * skip the enclosing tags (sequence markers) and the msg ids 576*0Sstevel@tonic-gate */ 577*0Sstevel@tonic-gate if ( ber_skip_tag( &r1, &len ) == LBER_ERROR || ber_scanf( &r1, "x" ) 578*0Sstevel@tonic-gate == LBER_ERROR ) { 579*0Sstevel@tonic-gate return( -1 ); 580*0Sstevel@tonic-gate } 581*0Sstevel@tonic-gate if ( ber_skip_tag( &r2, &len ) == LBER_ERROR || ber_scanf( &r2, "x" ) 582*0Sstevel@tonic-gate == LBER_ERROR ) { 583*0Sstevel@tonic-gate return( -1 ); 584*0Sstevel@tonic-gate } 585*0Sstevel@tonic-gate 586*0Sstevel@tonic-gate /* 587*0Sstevel@tonic-gate * check remaining length and bytes if necessary 588*0Sstevel@tonic-gate */ 589*0Sstevel@tonic-gate if (( slen = r1.ber_end - r1.ber_ptr ) != r2.ber_end - r2.ber_ptr ) { 590*0Sstevel@tonic-gate return( -1 ); /* different lengths */ 591*0Sstevel@tonic-gate } 592*0Sstevel@tonic-gate return( memcmp( r1.ber_ptr, r2.ber_ptr, slen )); 593*0Sstevel@tonic-gate } 594*0Sstevel@tonic-gate 595*0Sstevel@tonic-gate 596*0Sstevel@tonic-gate static int 597*0Sstevel@tonic-gate chain_contains_dn( LDAPMessage *msg, char *dn ) 598*0Sstevel@tonic-gate { 599*0Sstevel@tonic-gate LDAPMessage *m; 600*0Sstevel@tonic-gate BerElement ber; 601*0Sstevel@tonic-gate int msgid; 602*0Sstevel@tonic-gate char *s; 603*0Sstevel@tonic-gate int rc; 604*0Sstevel@tonic-gate 605*0Sstevel@tonic-gate 606*0Sstevel@tonic-gate /* 607*0Sstevel@tonic-gate * first check the base or dn of the request 608*0Sstevel@tonic-gate */ 609*0Sstevel@tonic-gate ber = *msg->lm_ber; /* struct copy */ 610*0Sstevel@tonic-gate if ( ber_scanf( &ber, "{i{a", &msgid, &s ) != LBER_ERROR ) { 611*0Sstevel@tonic-gate rc = ( strcasecmp( dn, s ) == 0 ) ? 1 : 0; 612*0Sstevel@tonic-gate free( s ); 613*0Sstevel@tonic-gate if ( rc != 0 ) { 614*0Sstevel@tonic-gate return( rc ); 615*0Sstevel@tonic-gate } 616*0Sstevel@tonic-gate } 617*0Sstevel@tonic-gate 618*0Sstevel@tonic-gate if ( msg->lm_msgtype == LDAP_REQ_COMPARE ) { 619*0Sstevel@tonic-gate return( 0 ); 620*0Sstevel@tonic-gate } 621*0Sstevel@tonic-gate 622*0Sstevel@tonic-gate /* 623*0Sstevel@tonic-gate * now check the dn of each search result 624*0Sstevel@tonic-gate */ 625*0Sstevel@tonic-gate rc = 0; 626*0Sstevel@tonic-gate for ( m = msg->lm_chain; m != NULLMSG && rc == 0 ; m = m->lm_chain ) { 627*0Sstevel@tonic-gate if ( m->lm_msgtype != LDAP_RES_SEARCH_ENTRY ) { 628*0Sstevel@tonic-gate continue; 629*0Sstevel@tonic-gate } 630*0Sstevel@tonic-gate ber = *m->lm_ber; /* struct copy */ 631*0Sstevel@tonic-gate if ( ber_scanf( &ber, "{a", &s ) != LBER_ERROR ) { 632*0Sstevel@tonic-gate rc = ( strcasecmp( dn, s ) == 0 ) ? 1 : 0; 633*0Sstevel@tonic-gate free( s ); 634*0Sstevel@tonic-gate } 635*0Sstevel@tonic-gate } 636*0Sstevel@tonic-gate 637*0Sstevel@tonic-gate return( rc ); 638*0Sstevel@tonic-gate } 639*0Sstevel@tonic-gate 640*0Sstevel@tonic-gate 641*0Sstevel@tonic-gate static ssize_t 642*0Sstevel@tonic-gate msg_size( LDAPMessage *msg ) 643*0Sstevel@tonic-gate { 644*0Sstevel@tonic-gate LDAPMessage *m; 645*0Sstevel@tonic-gate ssize_t size; 646*0Sstevel@tonic-gate 647*0Sstevel@tonic-gate size = 0; 648*0Sstevel@tonic-gate for ( m = msg; m != NULLMSG; m = m->lm_chain ) { 649*0Sstevel@tonic-gate size += sizeof( LDAPMessage ) + m->lm_ber->ber_end - 650*0Sstevel@tonic-gate m->lm_ber->ber_buf; 651*0Sstevel@tonic-gate } 652*0Sstevel@tonic-gate 653*0Sstevel@tonic-gate return( size ); 654*0Sstevel@tonic-gate } 655*0Sstevel@tonic-gate 656*0Sstevel@tonic-gate 657*0Sstevel@tonic-gate #define THRESHOLD_FACTOR 3 / 4 658*0Sstevel@tonic-gate #define SIZE_FACTOR 2 / 3 659*0Sstevel@tonic-gate 660*0Sstevel@tonic-gate static void 661*0Sstevel@tonic-gate check_cache_memused( LDAPCache *lc ) 662*0Sstevel@tonic-gate { 663*0Sstevel@tonic-gate /* 664*0Sstevel@tonic-gate * this routine is called to check if the cache is too big (lc_maxmem > 665*0Sstevel@tonic-gate * minimum cache size and lc_memused > lc_maxmem). If too big, it reduces 666*0Sstevel@tonic-gate * the cache size to < SIZE_FACTOR * lc_maxmem. The algorithm is as follows: 667*0Sstevel@tonic-gate * remove_threshold = lc_timeout seconds; 668*0Sstevel@tonic-gate * do { 669*0Sstevel@tonic-gate * remove everything older than remove_threshold seconds; 670*0Sstevel@tonic-gate * remove_threshold = remove_threshold * THRESHOLD_FACTOR; 671*0Sstevel@tonic-gate * } while ( cache size is > SIZE_FACTOR * lc_maxmem ) 672*0Sstevel@tonic-gate */ 673*0Sstevel@tonic-gate int i; 674*0Sstevel@tonic-gate unsigned long remove_threshold, validtime; 675*0Sstevel@tonic-gate LDAPMessage *m, *prev, *next; 676*0Sstevel@tonic-gate 677*0Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 108, "check_cache_memused: %1$ld bytes in use (%2$ld max)\n"), 678*0Sstevel@tonic-gate lc->lc_memused, lc->lc_maxmem, 0 ); 679*0Sstevel@tonic-gate 680*0Sstevel@tonic-gate if ( lc->lc_maxmem <= sizeof( LDAPCache ) 681*0Sstevel@tonic-gate || lc->lc_memused <= lc->lc_maxmem * SIZE_FACTOR ) { 682*0Sstevel@tonic-gate return; 683*0Sstevel@tonic-gate } 684*0Sstevel@tonic-gate 685*0Sstevel@tonic-gate remove_threshold = lc->lc_timeout; 686*0Sstevel@tonic-gate while ( lc->lc_memused > lc->lc_maxmem * SIZE_FACTOR ) { 687*0Sstevel@tonic-gate validtime = time( NULL ) - remove_threshold; 688*0Sstevel@tonic-gate for ( i = 0; i < LDAP_CACHE_BUCKETS; ++i ) { 689*0Sstevel@tonic-gate prev = NULLMSG; 690*0Sstevel@tonic-gate for ( m = lc->lc_buckets[ i ]; m != NULLMSG; 691*0Sstevel@tonic-gate m = next ) { 692*0Sstevel@tonic-gate next = m->lm_next; 693*0Sstevel@tonic-gate if ( m->lm_time < validtime ) { 694*0Sstevel@tonic-gate if ( prev == NULLMSG ) { 695*0Sstevel@tonic-gate lc->lc_buckets[ i ] = next; 696*0Sstevel@tonic-gate } else { 697*0Sstevel@tonic-gate prev->lm_next = next; 698*0Sstevel@tonic-gate } 699*0Sstevel@tonic-gate lc->lc_memused -= msg_size( m ); 700*0Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, 701*0Sstevel@tonic-gate catgets(slapdcat, 1, 109, "ccm: removed %d\n"), 702*0Sstevel@tonic-gate m->lm_msgid, 0, 0 ); 703*0Sstevel@tonic-gate ldap_msgfree( m ); 704*0Sstevel@tonic-gate } else { 705*0Sstevel@tonic-gate prev = m; 706*0Sstevel@tonic-gate } 707*0Sstevel@tonic-gate } 708*0Sstevel@tonic-gate } 709*0Sstevel@tonic-gate remove_threshold *= THRESHOLD_FACTOR; 710*0Sstevel@tonic-gate } 711*0Sstevel@tonic-gate 712*0Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 110, "ccm: reduced usage to %ld bytes\n"), 713*0Sstevel@tonic-gate lc->lc_memused, 0, 0 ); 714*0Sstevel@tonic-gate } 715*0Sstevel@tonic-gate 716*0Sstevel@tonic-gate #endif /* !NO_CACHE */ 717