10Sstevel@tonic-gate /* 2*3857Sstevel * Portions Copyright 1998 Sun Microsystems, Inc. All rights reserved. 3*3857Sstevel * Use is subject to license terms. 40Sstevel@tonic-gate */ 50Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 60Sstevel@tonic-gate /* 70Sstevel@tonic-gate * Copyright (c) 1993 The Regents of the University of Michigan. 80Sstevel@tonic-gate * All rights reserved. 90Sstevel@tonic-gate * 100Sstevel@tonic-gate * cache.c - local caching support for LDAP 110Sstevel@tonic-gate */ 120Sstevel@tonic-gate 130Sstevel@tonic-gate #ifndef NO_CACHE 140Sstevel@tonic-gate 150Sstevel@tonic-gate #ifndef lint 160Sstevel@tonic-gate static char copyright[] = "@(#) Copyright (c) 1993 The Regents of the University of Michigan.\nAll rights reserved.\n"; 170Sstevel@tonic-gate #endif 180Sstevel@tonic-gate 190Sstevel@tonic-gate #include <stdio.h> 200Sstevel@tonic-gate #include <string.h> 210Sstevel@tonic-gate #ifdef MACOS 220Sstevel@tonic-gate #include <stdlib.h> 230Sstevel@tonic-gate #include <time.h> 240Sstevel@tonic-gate #include "macos.h" 250Sstevel@tonic-gate #else /* MACOS */ 260Sstevel@tonic-gate #if defined( DOS ) || defined( _WIN32 ) 270Sstevel@tonic-gate #include <malloc.h> 280Sstevel@tonic-gate #include "msdos.h" 290Sstevel@tonic-gate #ifdef NCSA 300Sstevel@tonic-gate #include "externs.h" 310Sstevel@tonic-gate #endif /* NCSA */ 320Sstevel@tonic-gate #ifdef WINSOCK 330Sstevel@tonic-gate #include <time.h> 340Sstevel@tonic-gate #endif /* WINSOCK */ 350Sstevel@tonic-gate #else /* DOS */ 360Sstevel@tonic-gate #include <sys/types.h> 370Sstevel@tonic-gate #include <sys/socket.h> 380Sstevel@tonic-gate #endif /* DOS */ 390Sstevel@tonic-gate #endif /* MACOS */ 400Sstevel@tonic-gate #include "lber.h" 410Sstevel@tonic-gate #include "ldap.h" 420Sstevel@tonic-gate #include "ldap-private.h" 430Sstevel@tonic-gate #include "ldap-int.h" 440Sstevel@tonic-gate 450Sstevel@tonic-gate #ifdef NEEDPROTOS 460Sstevel@tonic-gate static int cache_hash( BerElement *ber ); 470Sstevel@tonic-gate static LDAPMessage *msg_dup( LDAPMessage *msg ); 480Sstevel@tonic-gate static int request_cmp( BerElement *req1, BerElement *req2 ); 490Sstevel@tonic-gate static int chain_contains_dn( LDAPMessage *msg, char *dn ); 500Sstevel@tonic-gate static ssize_t msg_size( LDAPMessage *msg ); 510Sstevel@tonic-gate static void check_cache_memused( LDAPCache *lc ); 520Sstevel@tonic-gate static void uncache_entry_or_req( LDAP *ld, char *dn, int msgid ); 530Sstevel@tonic-gate #else /* NEEDPROTOS */ 540Sstevel@tonic-gate static int cache_hash(); 550Sstevel@tonic-gate static LDAPMessage *msg_dup(); 560Sstevel@tonic-gate static int request_cmp(); 570Sstevel@tonic-gate static int chain_contains_dn(); 580Sstevel@tonic-gate static ssize_t msg_size(); 590Sstevel@tonic-gate static void check_cache_memused(); 600Sstevel@tonic-gate static void uncache_entry_or_req(); 610Sstevel@tonic-gate #endif /* NEEDPROTOS */ 620Sstevel@tonic-gate 630Sstevel@tonic-gate 640Sstevel@tonic-gate int 650Sstevel@tonic-gate ldap_enable_cache( LDAP *ld, time_t timeout, ssize_t maxmem ) 660Sstevel@tonic-gate { 670Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 680Sstevel@tonic-gate LOCK_LDAP(ld); 690Sstevel@tonic-gate #endif 700Sstevel@tonic-gate if ( ld->ld_cache == NULLLDCACHE ) { 710Sstevel@tonic-gate if (( ld->ld_cache = (LDAPCache *)malloc( sizeof( LDAPCache ))) 720Sstevel@tonic-gate == NULLLDCACHE ) { 730Sstevel@tonic-gate ld->ld_errno = LDAP_NO_MEMORY; 740Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 750Sstevel@tonic-gate UNLOCK_LDAP(ld); 760Sstevel@tonic-gate #endif 770Sstevel@tonic-gate return( -1 ); 780Sstevel@tonic-gate } 790Sstevel@tonic-gate (void) memset( ld->ld_cache, 0, sizeof( LDAPCache )); 800Sstevel@tonic-gate ld->ld_cache->lc_memused = sizeof( LDAPCache ); 810Sstevel@tonic-gate } 820Sstevel@tonic-gate 830Sstevel@tonic-gate ld->ld_cache->lc_timeout = timeout; 840Sstevel@tonic-gate ld->ld_cache->lc_maxmem = maxmem; 850Sstevel@tonic-gate check_cache_memused( ld->ld_cache ); 860Sstevel@tonic-gate ld->ld_cache->lc_enabled = 1; 870Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 880Sstevel@tonic-gate UNLOCK_LDAP(ld); 890Sstevel@tonic-gate #endif 900Sstevel@tonic-gate return( 0 ); 910Sstevel@tonic-gate } 920Sstevel@tonic-gate 930Sstevel@tonic-gate 940Sstevel@tonic-gate void 950Sstevel@tonic-gate ldap_disable_cache( LDAP *ld ) 960Sstevel@tonic-gate { 970Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 980Sstevel@tonic-gate LOCK_LDAP(ld); 990Sstevel@tonic-gate #endif 1000Sstevel@tonic-gate if ( ld->ld_cache != NULLLDCACHE ) { 1010Sstevel@tonic-gate ld->ld_cache->lc_enabled = 0; 1020Sstevel@tonic-gate } 1030Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 1040Sstevel@tonic-gate UNLOCK_LDAP(ld); 1050Sstevel@tonic-gate #endif 1060Sstevel@tonic-gate } 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate void 1110Sstevel@tonic-gate ldap_set_cache_options( LDAP *ld, unsigned int opts ) 1120Sstevel@tonic-gate { 1130Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 1140Sstevel@tonic-gate LOCK_LDAP(ld); 1150Sstevel@tonic-gate #endif 1160Sstevel@tonic-gate if ( ld->ld_cache != NULLLDCACHE ) { 1170Sstevel@tonic-gate ld->ld_cache->lc_options = opts; 1180Sstevel@tonic-gate } 1190Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 1200Sstevel@tonic-gate UNLOCK_LDAP(ld); 1210Sstevel@tonic-gate #endif 1220Sstevel@tonic-gate } 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate void 1260Sstevel@tonic-gate ldap_destroy_cache( LDAP *ld ) 1270Sstevel@tonic-gate { 1280Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 1290Sstevel@tonic-gate LOCK_LDAP(ld); 1300Sstevel@tonic-gate #endif 1310Sstevel@tonic-gate if ( ld->ld_cache != NULLLDCACHE ) { 1320Sstevel@tonic-gate ldap_flush_cache( ld ); 1330Sstevel@tonic-gate free( (char *)ld->ld_cache ); 1340Sstevel@tonic-gate ld->ld_cache = NULLLDCACHE; 1350Sstevel@tonic-gate } 1360Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 1370Sstevel@tonic-gate UNLOCK_LDAP(ld); 1380Sstevel@tonic-gate #endif 1390Sstevel@tonic-gate } 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate 1420Sstevel@tonic-gate void 1430Sstevel@tonic-gate ldap_flush_cache( LDAP *ld ) 1440Sstevel@tonic-gate { 1450Sstevel@tonic-gate int i; 1460Sstevel@tonic-gate LDAPMessage *m, *next; 1470Sstevel@tonic-gate 1480Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 1490Sstevel@tonic-gate LOCK_LDAP(ld); 1500Sstevel@tonic-gate #endif 1510Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 90, "ldap_flush_cache\n"), 0, 0, 0 ); 1520Sstevel@tonic-gate 1530Sstevel@tonic-gate if ( ld->ld_cache != NULLLDCACHE ) { 1540Sstevel@tonic-gate /* delete all requests in the queue */ 1550Sstevel@tonic-gate for ( m = ld->ld_cache->lc_requests; m != NULLMSG; m = next ) { 1560Sstevel@tonic-gate next = m->lm_next; 1570Sstevel@tonic-gate ldap_msgfree( m ); 1580Sstevel@tonic-gate } 1590Sstevel@tonic-gate ld->ld_cache->lc_requests = NULLMSG; 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate /* delete all messages in the cache */ 1620Sstevel@tonic-gate for ( i = 0; i < LDAP_CACHE_BUCKETS; ++i ) { 1630Sstevel@tonic-gate for ( m = ld->ld_cache->lc_buckets[ i ]; 1640Sstevel@tonic-gate m != NULLMSG; m = next ) { 1650Sstevel@tonic-gate next = m->lm_next; 1660Sstevel@tonic-gate ldap_msgfree( m ); 1670Sstevel@tonic-gate } 1680Sstevel@tonic-gate ld->ld_cache->lc_buckets[ i ] = NULLMSG; 1690Sstevel@tonic-gate } 1700Sstevel@tonic-gate ld->ld_cache->lc_memused = sizeof( LDAPCache ); 1710Sstevel@tonic-gate } 1720Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 1730Sstevel@tonic-gate UNLOCK_LDAP(ld); 1740Sstevel@tonic-gate #endif 1750Sstevel@tonic-gate } 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate void 1790Sstevel@tonic-gate ldap_uncache_request( LDAP *ld, int msgid ) 1800Sstevel@tonic-gate { 1810Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 1820Sstevel@tonic-gate LOCK_LDAP(ld); 1830Sstevel@tonic-gate #endif 1840Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 91, "ldap_uncache_request %1$d ld_cache %2$x\n"), 1850Sstevel@tonic-gate msgid, ld->ld_cache, 0 ); 1860Sstevel@tonic-gate 1870Sstevel@tonic-gate uncache_entry_or_req( ld, NULL, msgid ); 1880Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 1890Sstevel@tonic-gate UNLOCK_LDAP(ld); 1900Sstevel@tonic-gate #endif 1910Sstevel@tonic-gate } 1920Sstevel@tonic-gate 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate void 1950Sstevel@tonic-gate ldap_uncache_entry( LDAP *ld, char *dn ) 1960Sstevel@tonic-gate { 1970Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 1980Sstevel@tonic-gate LOCK_LDAP(ld); 1990Sstevel@tonic-gate #endif 2000Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 92, "ldap_uncache_entry %1$s ld_cache %2$x\n"), 2010Sstevel@tonic-gate dn, ld->ld_cache, 0 ); 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate uncache_entry_or_req( ld, dn, 0 ); 2040Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 2050Sstevel@tonic-gate UNLOCK_LDAP(ld); 2060Sstevel@tonic-gate #endif 2070Sstevel@tonic-gate } 2080Sstevel@tonic-gate 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate static void 2110Sstevel@tonic-gate uncache_entry_or_req( LDAP *ld, 2120Sstevel@tonic-gate char *dn, /* if non-NULL, uncache entry */ 2130Sstevel@tonic-gate int msgid ) /* request to uncache (if dn == NULL) */ 2140Sstevel@tonic-gate { 2150Sstevel@tonic-gate int i; 2160Sstevel@tonic-gate LDAPMessage *m, *prev, *next; 2170Sstevel@tonic-gate 2180Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, 2190Sstevel@tonic-gate catgets(slapdcat, 1, 93, "ldap_uncache_entry_or_req dn %1$s msgid %2$d ld_cache %3$x\n"), 2200Sstevel@tonic-gate dn, msgid, ld->ld_cache ); 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate if ( ld->ld_cache == NULLLDCACHE ) { 2230Sstevel@tonic-gate return; 2240Sstevel@tonic-gate } 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate /* first check the request queue */ 2270Sstevel@tonic-gate prev = NULLMSG; 2280Sstevel@tonic-gate for ( m = ld->ld_cache->lc_requests; m != NULLMSG; m = next ) { 2290Sstevel@tonic-gate next = m->lm_next; 2300Sstevel@tonic-gate if (( dn != NULL && chain_contains_dn( m, dn )) || 2310Sstevel@tonic-gate ( dn == NULL && m->lm_msgid == msgid )) { 2320Sstevel@tonic-gate if ( prev == NULLMSG ) { 2330Sstevel@tonic-gate ld->ld_cache->lc_requests = next; 2340Sstevel@tonic-gate } else { 2350Sstevel@tonic-gate prev->lm_next = next; 2360Sstevel@tonic-gate } 2370Sstevel@tonic-gate ld->ld_cache->lc_memused -= msg_size( m ); 2380Sstevel@tonic-gate ldap_msgfree( m ); 2390Sstevel@tonic-gate } else { 2400Sstevel@tonic-gate prev = m; 2410Sstevel@tonic-gate } 2420Sstevel@tonic-gate } 2430Sstevel@tonic-gate 2440Sstevel@tonic-gate /* now check the rest of the cache */ 2450Sstevel@tonic-gate for ( i = 0; i < LDAP_CACHE_BUCKETS; ++i ) { 2460Sstevel@tonic-gate prev = NULLMSG; 2470Sstevel@tonic-gate for ( m = ld->ld_cache->lc_buckets[ i ]; m != NULLMSG; 2480Sstevel@tonic-gate m = next ) { 2490Sstevel@tonic-gate next = m->lm_next; 2500Sstevel@tonic-gate if (( dn != NULL && chain_contains_dn( m, dn )) || 2510Sstevel@tonic-gate ( dn == NULL && m->lm_msgid == msgid )) { 2520Sstevel@tonic-gate if ( prev == NULLMSG ) { 2530Sstevel@tonic-gate ld->ld_cache->lc_buckets[ i ] = next; 2540Sstevel@tonic-gate } else { 2550Sstevel@tonic-gate prev->lm_next = next; 2560Sstevel@tonic-gate } 2570Sstevel@tonic-gate ld->ld_cache->lc_memused -= msg_size( m ); 2580Sstevel@tonic-gate ldap_msgfree( m ); 2590Sstevel@tonic-gate } else { 2600Sstevel@tonic-gate prev = m; 2610Sstevel@tonic-gate } 2620Sstevel@tonic-gate } 2630Sstevel@tonic-gate } 2640Sstevel@tonic-gate } 2650Sstevel@tonic-gate 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate void 2680Sstevel@tonic-gate add_request_to_cache( LDAP *ld, unsigned int msgtype, BerElement *request ) 2690Sstevel@tonic-gate { 2700Sstevel@tonic-gate LDAPMessage *new; 2710Sstevel@tonic-gate size_t len; 2720Sstevel@tonic-gate 2730Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 94, "add_request_to_cache\n"), 0, 0, 0 ); 2740Sstevel@tonic-gate 2750Sstevel@tonic-gate ld->ld_errno = LDAP_SUCCESS; 2760Sstevel@tonic-gate if ( ld->ld_cache == NULLLDCACHE || 2770Sstevel@tonic-gate ( ld->ld_cache->lc_enabled == 0 )) { 2780Sstevel@tonic-gate return; 2790Sstevel@tonic-gate } 2800Sstevel@tonic-gate 2810Sstevel@tonic-gate if (( new = (LDAPMessage *) calloc( 1, sizeof(LDAPMessage) )) 2820Sstevel@tonic-gate != NULL ) { 2830Sstevel@tonic-gate if (( new->lm_ber = alloc_ber_with_options( ld )) == NULLBER ) { 2840Sstevel@tonic-gate free( (char *)new ); 2850Sstevel@tonic-gate return; 2860Sstevel@tonic-gate } 2870Sstevel@tonic-gate len = request->ber_ptr - request->ber_buf; 2880Sstevel@tonic-gate if (( new->lm_ber->ber_buf = (char *) malloc( len )) 2890Sstevel@tonic-gate == NULL ) { 2900Sstevel@tonic-gate ber_free( new->lm_ber, 0 ); 2910Sstevel@tonic-gate free( (char *)new ); 2920Sstevel@tonic-gate ld->ld_errno = LDAP_NO_MEMORY; 2930Sstevel@tonic-gate return; 2940Sstevel@tonic-gate } 2950Sstevel@tonic-gate SAFEMEMCPY( new->lm_ber->ber_buf, request->ber_buf, len ); 2960Sstevel@tonic-gate new->lm_ber->ber_ptr = new->lm_ber->ber_buf; 2970Sstevel@tonic-gate new->lm_ber->ber_end = new->lm_ber->ber_buf + len; 2980Sstevel@tonic-gate new->lm_msgid = ld->ld_msgid; 2990Sstevel@tonic-gate new->lm_msgtype = (int) msgtype;; 3000Sstevel@tonic-gate new->lm_next = ld->ld_cache->lc_requests; 3010Sstevel@tonic-gate ld->ld_cache->lc_requests = new; 3020Sstevel@tonic-gate } else { 3030Sstevel@tonic-gate ld->ld_errno = LDAP_NO_MEMORY; 3040Sstevel@tonic-gate } 3050Sstevel@tonic-gate } 3060Sstevel@tonic-gate 3070Sstevel@tonic-gate 3080Sstevel@tonic-gate void 3090Sstevel@tonic-gate add_result_to_cache( LDAP *ld, LDAPMessage *result ) 3100Sstevel@tonic-gate { 3110Sstevel@tonic-gate LDAPMessage *m, **mp, *req, *new, *prev; 3120Sstevel@tonic-gate int err, keep; 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 95, "add_result_to_cache: id %1$d, type %2$d\n"), 3150Sstevel@tonic-gate result->lm_msgid, result->lm_msgtype, 0 ); 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate if ( ld->ld_cache == NULLLDCACHE || 3180Sstevel@tonic-gate ( ld->ld_cache->lc_enabled == 0 )) { 3190Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 96, "artc: cache disabled\n"), 0, 0, 0 ); 3200Sstevel@tonic-gate return; 3210Sstevel@tonic-gate } 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate if ( result->lm_msgtype != LDAP_RES_SEARCH_ENTRY && 3240Sstevel@tonic-gate result->lm_msgtype != LDAP_RES_SEARCH_RESULT && 3250Sstevel@tonic-gate result->lm_msgtype != LDAP_RES_SEARCH_REFERENCE && 3260Sstevel@tonic-gate result->lm_msgtype != LDAP_RES_COMPARE ) { 3270Sstevel@tonic-gate /* 3280Sstevel@tonic-gate * only cache search and compare operations 3290Sstevel@tonic-gate */ 3300Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, 3310Sstevel@tonic-gate catgets(slapdcat, 1, 97, "artc: only caching search & compare operations\n"), 0, 0, 0 ); 3320Sstevel@tonic-gate return; 3330Sstevel@tonic-gate } 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate /* 3360Sstevel@tonic-gate * if corresponding request is in the lc_requests list, add this 3370Sstevel@tonic-gate * result to it. if this result completes the results for the 3380Sstevel@tonic-gate * request, add the request/result chain to the cache proper. 3390Sstevel@tonic-gate */ 3400Sstevel@tonic-gate prev = NULLMSG; 3410Sstevel@tonic-gate for ( m = ld->ld_cache->lc_requests; m != NULL; m = m->lm_next ) { 3420Sstevel@tonic-gate if ( m->lm_msgid == result->lm_msgid ) { 3430Sstevel@tonic-gate break; 3440Sstevel@tonic-gate } 3450Sstevel@tonic-gate prev = m; 3460Sstevel@tonic-gate } 3470Sstevel@tonic-gate 3480Sstevel@tonic-gate if ( m != NULLMSG ) { /* found request; add to end of chain */ 3490Sstevel@tonic-gate req = m; 3500Sstevel@tonic-gate for ( ; m->lm_chain != NULLMSG; m = m->lm_chain ) 3510Sstevel@tonic-gate ; 3520Sstevel@tonic-gate if (( new = msg_dup( result )) != NULLMSG ) { 3530Sstevel@tonic-gate new->lm_chain = NULLMSG; 3540Sstevel@tonic-gate m->lm_chain = new; 3550Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, 3560Sstevel@tonic-gate catgets(slapdcat, 1, 98, "artc: result added to cache request chain\n"), 3570Sstevel@tonic-gate 0, 0, 0 ); 3580Sstevel@tonic-gate } 3590Sstevel@tonic-gate if ( result->lm_msgtype == LDAP_RES_SEARCH_RESULT || 3600Sstevel@tonic-gate result->lm_msgtype == LDAP_RES_COMPARE ) { 3610Sstevel@tonic-gate /* 3620Sstevel@tonic-gate * this result completes the chain of results 3630Sstevel@tonic-gate * add to cache proper if appropriate 3640Sstevel@tonic-gate */ 3650Sstevel@tonic-gate keep = 0; /* pessimistic */ 3660Sstevel@tonic-gate err = ldap_result2error( ld, result, 0 ); 3670Sstevel@tonic-gate if ( err == LDAP_SUCCESS || 3680Sstevel@tonic-gate ( result->lm_msgtype == LDAP_RES_COMPARE && 3690Sstevel@tonic-gate ( err == LDAP_COMPARE_FALSE || 3700Sstevel@tonic-gate err == LDAP_COMPARE_TRUE || 3710Sstevel@tonic-gate err == LDAP_NO_SUCH_ATTRIBUTE ))) { 3720Sstevel@tonic-gate keep = 1; 3730Sstevel@tonic-gate } 3740Sstevel@tonic-gate 3750Sstevel@tonic-gate if ( ld->ld_cache->lc_options == 0 ) { 3760Sstevel@tonic-gate if ( err == LDAP_SIZELIMIT_EXCEEDED ) { 3770Sstevel@tonic-gate keep = 1; 3780Sstevel@tonic-gate } 3790Sstevel@tonic-gate } else if (( ld->ld_cache->lc_options & 3800Sstevel@tonic-gate LDAP_CACHE_OPT_CACHEALLERRS ) != 0 ) { 3810Sstevel@tonic-gate keep = 1; 3820Sstevel@tonic-gate } 3830Sstevel@tonic-gate 3840Sstevel@tonic-gate if ( prev == NULLMSG ) { 3850Sstevel@tonic-gate ld->ld_cache->lc_requests = req->lm_next; 3860Sstevel@tonic-gate } else { 3870Sstevel@tonic-gate prev->lm_next = req->lm_next; 3880Sstevel@tonic-gate } 3890Sstevel@tonic-gate 3900Sstevel@tonic-gate if ( !keep ) { 3910Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, 3920Sstevel@tonic-gate catgets(slapdcat, 1, 99, "artc: not caching result with error %d\n"), 3930Sstevel@tonic-gate err, 0, 0 ); 3940Sstevel@tonic-gate ldap_msgfree( req ); 3950Sstevel@tonic-gate } else { 3960Sstevel@tonic-gate mp = &ld->ld_cache->lc_buckets[ 3970Sstevel@tonic-gate cache_hash( req->lm_ber ) ]; 3980Sstevel@tonic-gate req->lm_next = *mp; 3990Sstevel@tonic-gate *mp = req; 4000Sstevel@tonic-gate req->lm_time = time( NULL ); 4010Sstevel@tonic-gate ld->ld_cache->lc_memused += msg_size( req ); 4020Sstevel@tonic-gate check_cache_memused( ld->ld_cache ); 4030Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, 4040Sstevel@tonic-gate catgets(slapdcat, 1, 100, "artc: cached result with error %d\n"), 4050Sstevel@tonic-gate err, 0, 0 ); 4060Sstevel@tonic-gate } 4070Sstevel@tonic-gate } 4080Sstevel@tonic-gate } else { 4090Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 101, "artc: msgid not in request list\n"), 4100Sstevel@tonic-gate 0, 0, 0 ); 4110Sstevel@tonic-gate } 4120Sstevel@tonic-gate } 4130Sstevel@tonic-gate 4140Sstevel@tonic-gate 4150Sstevel@tonic-gate /* 4160Sstevel@tonic-gate * look in the cache for this request 4170Sstevel@tonic-gate * return 0 if found, -1 if not 4180Sstevel@tonic-gate * if found, the corresponding result messages are added to the incoming 4190Sstevel@tonic-gate * queue with the correct (new) msgid so that subsequent ldap_result calls 4200Sstevel@tonic-gate * will find them. 4210Sstevel@tonic-gate */ 4220Sstevel@tonic-gate int 4230Sstevel@tonic-gate check_cache( LDAP *ld, unsigned int msgtype, BerElement *request ) 4240Sstevel@tonic-gate { 4250Sstevel@tonic-gate LDAPMessage *m, *new, *prev, *next; 4260Sstevel@tonic-gate BerElement reqber; 4270Sstevel@tonic-gate int first, hash; 4280Sstevel@tonic-gate unsigned long validtime; 4290Sstevel@tonic-gate 4300Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 102, "check_cache\n"), 0, 0, 0 ); 4310Sstevel@tonic-gate 4320Sstevel@tonic-gate if ( ld->ld_cache == NULLLDCACHE || 4330Sstevel@tonic-gate ( ld->ld_cache->lc_enabled == 0 )) { 4340Sstevel@tonic-gate return( -1 ); 4350Sstevel@tonic-gate } 4360Sstevel@tonic-gate 4370Sstevel@tonic-gate reqber.ber_buf = reqber.ber_ptr = request->ber_buf; 4380Sstevel@tonic-gate reqber.ber_end = request->ber_ptr; 4390Sstevel@tonic-gate 4400Sstevel@tonic-gate validtime = time( NULL ) - ld->ld_cache->lc_timeout; 4410Sstevel@tonic-gate 4420Sstevel@tonic-gate prev = NULLMSG; 4430Sstevel@tonic-gate hash = cache_hash( &reqber ); 4440Sstevel@tonic-gate for ( m = ld->ld_cache->lc_buckets[ hash ]; m != NULLMSG; m = next ) { 4450Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE,catgets(slapdcat, 1, 103, "cc: examining id %1$d,type %2$d\n"), 4460Sstevel@tonic-gate m->lm_msgid, m->lm_msgtype, 0 ); 4470Sstevel@tonic-gate if ( m->lm_time < validtime ) { 4480Sstevel@tonic-gate /* delete expired message */ 4490Sstevel@tonic-gate next = m->lm_next; 4500Sstevel@tonic-gate if ( prev == NULL ) { 4510Sstevel@tonic-gate ld->ld_cache->lc_buckets[ hash ] = next; 4520Sstevel@tonic-gate } else { 4530Sstevel@tonic-gate prev->lm_next = next; 4540Sstevel@tonic-gate } 4550Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 104, "cc: expired id %d\n"), 4560Sstevel@tonic-gate m->lm_msgid, 0, 0 ); 4570Sstevel@tonic-gate ld->ld_cache->lc_memused -= msg_size( m ); 4580Sstevel@tonic-gate ldap_msgfree( m ); 4590Sstevel@tonic-gate } else { 4600Sstevel@tonic-gate if ( m->lm_msgtype == msgtype && 4610Sstevel@tonic-gate request_cmp( m->lm_ber, &reqber ) == 0 ) { 4620Sstevel@tonic-gate break; 4630Sstevel@tonic-gate } 4640Sstevel@tonic-gate next = m->lm_next; 4650Sstevel@tonic-gate prev = m; 4660Sstevel@tonic-gate } 4670Sstevel@tonic-gate } 4680Sstevel@tonic-gate 4690Sstevel@tonic-gate if ( m == NULLMSG ) { 4700Sstevel@tonic-gate return( -1 ); 4710Sstevel@tonic-gate } 4720Sstevel@tonic-gate 4730Sstevel@tonic-gate /* 4740Sstevel@tonic-gate * add duplicates of responses to incoming queue 4750Sstevel@tonic-gate */ 4760Sstevel@tonic-gate first = 1; 4770Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 4780Sstevel@tonic-gate LOCK_RESPONSE(ld); 4790Sstevel@tonic-gate #endif 4800Sstevel@tonic-gate for ( m = m->lm_chain; m != NULLMSG; m = m->lm_chain ) { 4810Sstevel@tonic-gate if (( new = msg_dup( m )) == NULLMSG ) { 4820Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 4830Sstevel@tonic-gate UNLOCK_RESPONSE(ld); 4840Sstevel@tonic-gate #endif 4850Sstevel@tonic-gate return( -1 ); 4860Sstevel@tonic-gate } 4870Sstevel@tonic-gate 4880Sstevel@tonic-gate new->lm_msgid = ld->ld_msgid; 4890Sstevel@tonic-gate new->lm_chain = NULLMSG; 4900Sstevel@tonic-gate if ( first ) { 4910Sstevel@tonic-gate new->lm_next = ld->ld_responses; 4920Sstevel@tonic-gate ld->ld_responses = new; 4930Sstevel@tonic-gate first = 0; 4940Sstevel@tonic-gate } else { 4950Sstevel@tonic-gate prev->lm_chain = new; 4960Sstevel@tonic-gate } 4970Sstevel@tonic-gate prev = new; 4980Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 105, "cc: added type %d\n"), 4990Sstevel@tonic-gate new->lm_msgtype, 0, 0 ); 5000Sstevel@tonic-gate } 5010Sstevel@tonic-gate 5020Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 106, "cc: result returned from cache\n"), 0, 0, 0 ); 5030Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT ) 5040Sstevel@tonic-gate UNLOCK_RESPONSE(ld); 5050Sstevel@tonic-gate #endif 5060Sstevel@tonic-gate return( 0 ); 5070Sstevel@tonic-gate } 5080Sstevel@tonic-gate 5090Sstevel@tonic-gate 5100Sstevel@tonic-gate static int 5110Sstevel@tonic-gate cache_hash( BerElement *ber ) 5120Sstevel@tonic-gate { 5130Sstevel@tonic-gate BerElement bercpy; 5140Sstevel@tonic-gate unsigned int len; 5150Sstevel@tonic-gate 5160Sstevel@tonic-gate /* 5170Sstevel@tonic-gate * just take the length of the packet and mod with # of buckets 5180Sstevel@tonic-gate */ 5190Sstevel@tonic-gate bercpy = *ber; 5200Sstevel@tonic-gate if ( ber_skip_tag( &bercpy, &len ) == LBER_ERROR 5210Sstevel@tonic-gate || ber_scanf( &bercpy, "x" ) == LBER_ERROR ) { 5220Sstevel@tonic-gate len = 0; /* punt: just return zero */ 5230Sstevel@tonic-gate } else { 5240Sstevel@tonic-gate len = (int) ( bercpy.ber_end - bercpy.ber_ptr ); 5250Sstevel@tonic-gate } 5260Sstevel@tonic-gate 5270Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 107, "cache_hash: len is %1$ld, returning %2$ld\n"), 5280Sstevel@tonic-gate len, len % LDAP_CACHE_BUCKETS, 0 ); 5290Sstevel@tonic-gate return ( len % LDAP_CACHE_BUCKETS ); 5300Sstevel@tonic-gate } 5310Sstevel@tonic-gate 5320Sstevel@tonic-gate 5330Sstevel@tonic-gate static LDAPMessage * 5340Sstevel@tonic-gate msg_dup( LDAPMessage *msg ) 5350Sstevel@tonic-gate { 5360Sstevel@tonic-gate LDAPMessage *new; 5370Sstevel@tonic-gate size_t len; 5380Sstevel@tonic-gate 5390Sstevel@tonic-gate if (( new = (LDAPMessage *)malloc( sizeof(LDAPMessage))) != NULL ) { 5400Sstevel@tonic-gate *new = *msg; /* struct copy */ 5410Sstevel@tonic-gate if (( new->lm_ber = ber_dup( msg->lm_ber )) == NULLBER ) { 5420Sstevel@tonic-gate free( (char *)new ); 5430Sstevel@tonic-gate return( NULLMSG ); 5440Sstevel@tonic-gate } 5450Sstevel@tonic-gate len = msg->lm_ber->ber_end - msg->lm_ber->ber_buf; 5460Sstevel@tonic-gate if (( new->lm_ber->ber_buf = (char *) malloc( len )) == NULL ) { 5470Sstevel@tonic-gate ber_free( new->lm_ber, 0 ); 5480Sstevel@tonic-gate free( (char *)new ); 5490Sstevel@tonic-gate return( NULLMSG ); 5500Sstevel@tonic-gate } 5510Sstevel@tonic-gate SAFEMEMCPY( new->lm_ber->ber_buf, msg->lm_ber->ber_buf, len ); 5520Sstevel@tonic-gate 5530Sstevel@tonic-gate new->lm_ber->ber_ptr = new->lm_ber->ber_buf + 5540Sstevel@tonic-gate ( msg->lm_ber->ber_ptr - msg->lm_ber->ber_buf ); 5550Sstevel@tonic-gate new->lm_ber->ber_end = new->lm_ber->ber_buf + len; 5560Sstevel@tonic-gate } 5570Sstevel@tonic-gate 5580Sstevel@tonic-gate return( new ); 5590Sstevel@tonic-gate } 5600Sstevel@tonic-gate 5610Sstevel@tonic-gate 5620Sstevel@tonic-gate static int 5630Sstevel@tonic-gate request_cmp( BerElement *req1, BerElement *req2 ) 5640Sstevel@tonic-gate { 5650Sstevel@tonic-gate unsigned int len; 5660Sstevel@tonic-gate size_t slen; 5670Sstevel@tonic-gate BerElement r1, r2; 5680Sstevel@tonic-gate 5690Sstevel@tonic-gate r1 = *req1; /* struct copies */ 5700Sstevel@tonic-gate r2 = *req2; 5710Sstevel@tonic-gate 5720Sstevel@tonic-gate /* 5730Sstevel@tonic-gate * skip the enclosing tags (sequence markers) and the msg ids 5740Sstevel@tonic-gate */ 5750Sstevel@tonic-gate if ( ber_skip_tag( &r1, &len ) == LBER_ERROR || ber_scanf( &r1, "x" ) 5760Sstevel@tonic-gate == LBER_ERROR ) { 5770Sstevel@tonic-gate return( -1 ); 5780Sstevel@tonic-gate } 5790Sstevel@tonic-gate if ( ber_skip_tag( &r2, &len ) == LBER_ERROR || ber_scanf( &r2, "x" ) 5800Sstevel@tonic-gate == LBER_ERROR ) { 5810Sstevel@tonic-gate return( -1 ); 5820Sstevel@tonic-gate } 5830Sstevel@tonic-gate 5840Sstevel@tonic-gate /* 5850Sstevel@tonic-gate * check remaining length and bytes if necessary 5860Sstevel@tonic-gate */ 5870Sstevel@tonic-gate if (( slen = r1.ber_end - r1.ber_ptr ) != r2.ber_end - r2.ber_ptr ) { 5880Sstevel@tonic-gate return( -1 ); /* different lengths */ 5890Sstevel@tonic-gate } 5900Sstevel@tonic-gate return( memcmp( r1.ber_ptr, r2.ber_ptr, slen )); 5910Sstevel@tonic-gate } 5920Sstevel@tonic-gate 5930Sstevel@tonic-gate 5940Sstevel@tonic-gate static int 5950Sstevel@tonic-gate chain_contains_dn( LDAPMessage *msg, char *dn ) 5960Sstevel@tonic-gate { 5970Sstevel@tonic-gate LDAPMessage *m; 5980Sstevel@tonic-gate BerElement ber; 5990Sstevel@tonic-gate int msgid; 6000Sstevel@tonic-gate char *s; 6010Sstevel@tonic-gate int rc; 6020Sstevel@tonic-gate 6030Sstevel@tonic-gate 6040Sstevel@tonic-gate /* 6050Sstevel@tonic-gate * first check the base or dn of the request 6060Sstevel@tonic-gate */ 6070Sstevel@tonic-gate ber = *msg->lm_ber; /* struct copy */ 6080Sstevel@tonic-gate if ( ber_scanf( &ber, "{i{a", &msgid, &s ) != LBER_ERROR ) { 6090Sstevel@tonic-gate rc = ( strcasecmp( dn, s ) == 0 ) ? 1 : 0; 6100Sstevel@tonic-gate free( s ); 6110Sstevel@tonic-gate if ( rc != 0 ) { 6120Sstevel@tonic-gate return( rc ); 6130Sstevel@tonic-gate } 6140Sstevel@tonic-gate } 6150Sstevel@tonic-gate 6160Sstevel@tonic-gate if ( msg->lm_msgtype == LDAP_REQ_COMPARE ) { 6170Sstevel@tonic-gate return( 0 ); 6180Sstevel@tonic-gate } 6190Sstevel@tonic-gate 6200Sstevel@tonic-gate /* 6210Sstevel@tonic-gate * now check the dn of each search result 6220Sstevel@tonic-gate */ 6230Sstevel@tonic-gate rc = 0; 6240Sstevel@tonic-gate for ( m = msg->lm_chain; m != NULLMSG && rc == 0 ; m = m->lm_chain ) { 6250Sstevel@tonic-gate if ( m->lm_msgtype != LDAP_RES_SEARCH_ENTRY ) { 6260Sstevel@tonic-gate continue; 6270Sstevel@tonic-gate } 6280Sstevel@tonic-gate ber = *m->lm_ber; /* struct copy */ 6290Sstevel@tonic-gate if ( ber_scanf( &ber, "{a", &s ) != LBER_ERROR ) { 6300Sstevel@tonic-gate rc = ( strcasecmp( dn, s ) == 0 ) ? 1 : 0; 6310Sstevel@tonic-gate free( s ); 6320Sstevel@tonic-gate } 6330Sstevel@tonic-gate } 6340Sstevel@tonic-gate 6350Sstevel@tonic-gate return( rc ); 6360Sstevel@tonic-gate } 6370Sstevel@tonic-gate 6380Sstevel@tonic-gate 6390Sstevel@tonic-gate static ssize_t 6400Sstevel@tonic-gate msg_size( LDAPMessage *msg ) 6410Sstevel@tonic-gate { 6420Sstevel@tonic-gate LDAPMessage *m; 6430Sstevel@tonic-gate ssize_t size; 6440Sstevel@tonic-gate 6450Sstevel@tonic-gate size = 0; 6460Sstevel@tonic-gate for ( m = msg; m != NULLMSG; m = m->lm_chain ) { 6470Sstevel@tonic-gate size += sizeof( LDAPMessage ) + m->lm_ber->ber_end - 6480Sstevel@tonic-gate m->lm_ber->ber_buf; 6490Sstevel@tonic-gate } 6500Sstevel@tonic-gate 6510Sstevel@tonic-gate return( size ); 6520Sstevel@tonic-gate } 6530Sstevel@tonic-gate 6540Sstevel@tonic-gate 6550Sstevel@tonic-gate #define THRESHOLD_FACTOR 3 / 4 6560Sstevel@tonic-gate #define SIZE_FACTOR 2 / 3 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate static void 6590Sstevel@tonic-gate check_cache_memused( LDAPCache *lc ) 6600Sstevel@tonic-gate { 6610Sstevel@tonic-gate /* 6620Sstevel@tonic-gate * this routine is called to check if the cache is too big (lc_maxmem > 6630Sstevel@tonic-gate * minimum cache size and lc_memused > lc_maxmem). If too big, it reduces 6640Sstevel@tonic-gate * the cache size to < SIZE_FACTOR * lc_maxmem. The algorithm is as follows: 6650Sstevel@tonic-gate * remove_threshold = lc_timeout seconds; 6660Sstevel@tonic-gate * do { 6670Sstevel@tonic-gate * remove everything older than remove_threshold seconds; 6680Sstevel@tonic-gate * remove_threshold = remove_threshold * THRESHOLD_FACTOR; 6690Sstevel@tonic-gate * } while ( cache size is > SIZE_FACTOR * lc_maxmem ) 6700Sstevel@tonic-gate */ 6710Sstevel@tonic-gate int i; 6720Sstevel@tonic-gate unsigned long remove_threshold, validtime; 6730Sstevel@tonic-gate LDAPMessage *m, *prev, *next; 6740Sstevel@tonic-gate 6750Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 108, "check_cache_memused: %1$ld bytes in use (%2$ld max)\n"), 6760Sstevel@tonic-gate lc->lc_memused, lc->lc_maxmem, 0 ); 6770Sstevel@tonic-gate 6780Sstevel@tonic-gate if ( lc->lc_maxmem <= sizeof( LDAPCache ) 6790Sstevel@tonic-gate || lc->lc_memused <= lc->lc_maxmem * SIZE_FACTOR ) { 6800Sstevel@tonic-gate return; 6810Sstevel@tonic-gate } 6820Sstevel@tonic-gate 6830Sstevel@tonic-gate remove_threshold = lc->lc_timeout; 6840Sstevel@tonic-gate while ( lc->lc_memused > lc->lc_maxmem * SIZE_FACTOR ) { 6850Sstevel@tonic-gate validtime = time( NULL ) - remove_threshold; 6860Sstevel@tonic-gate for ( i = 0; i < LDAP_CACHE_BUCKETS; ++i ) { 6870Sstevel@tonic-gate prev = NULLMSG; 6880Sstevel@tonic-gate for ( m = lc->lc_buckets[ i ]; m != NULLMSG; 6890Sstevel@tonic-gate m = next ) { 6900Sstevel@tonic-gate next = m->lm_next; 6910Sstevel@tonic-gate if ( m->lm_time < validtime ) { 6920Sstevel@tonic-gate if ( prev == NULLMSG ) { 6930Sstevel@tonic-gate lc->lc_buckets[ i ] = next; 6940Sstevel@tonic-gate } else { 6950Sstevel@tonic-gate prev->lm_next = next; 6960Sstevel@tonic-gate } 6970Sstevel@tonic-gate lc->lc_memused -= msg_size( m ); 6980Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, 6990Sstevel@tonic-gate catgets(slapdcat, 1, 109, "ccm: removed %d\n"), 7000Sstevel@tonic-gate m->lm_msgid, 0, 0 ); 7010Sstevel@tonic-gate ldap_msgfree( m ); 7020Sstevel@tonic-gate } else { 7030Sstevel@tonic-gate prev = m; 7040Sstevel@tonic-gate } 7050Sstevel@tonic-gate } 7060Sstevel@tonic-gate } 7070Sstevel@tonic-gate remove_threshold *= THRESHOLD_FACTOR; 7080Sstevel@tonic-gate } 7090Sstevel@tonic-gate 7100Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 110, "ccm: reduced usage to %ld bytes\n"), 7110Sstevel@tonic-gate lc->lc_memused, 0, 0 ); 7120Sstevel@tonic-gate } 7130Sstevel@tonic-gate 7140Sstevel@tonic-gate #endif /* !NO_CACHE */ 715