resourcelimit.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. /* resourcelimit.c - binder-based resource limits implementation */
  42. /*
  43. * Implementation notes:
  44. *
  45. * At present this code only provides support for integer-based
  46. * resource limits.
  47. *
  48. * When a successful bind occurs (i.e., when bind_credentials_set() is
  49. * called), reslimit_update_from_dn() or reslimit_update_from_entry()
  50. * must be called. These functions look in the binder entry and pull
  51. * out attribute values that correspond to resource limits. Typically
  52. * operational attributes are used, e.g., nsSizeLimit to hold a
  53. * binder-specific search size limit. The attributes should be single
  54. * valued; if not, this code ignores all but the first value it finds.
  55. * The virtual attribute interface is used to retrieve the binder entry
  56. * values, so they can be based on COS, etc.
  57. *
  58. * Any resource limits found in the binder entry are cached in the
  59. * connection structure. A connection object extension is used for this
  60. * purpose. This means that if the attributes that correspond to binder
  61. * entry are changed the resource limit won't be affected until the next
  62. * bind occurs as that entry. The data in the connection extension is
  63. * protected using a single writer/multiple reader locking scheme.
  64. *
  65. * A plugin or server subsystem that wants to use the resource limit
  66. * subsystem should call slapi_reslimit_register() once for each limit it
  67. * wants tracked. Note that slapi_reslimit_register() should be called
  68. * early, i.e., before any client connections are accepted.
  69. * slapi_reslimit_register() gives back an integer handle that is used
  70. * later to refer to the limit in question. Here's a sample call:
  71. */
  72. #if SLAPI_RESLIMIT_SAMPLE_CODE
  73. static int sizelimit_reslimit_handle = -1;
  74. if ( slapi_reslimit_register( SLAPI_RESLIMIT_TYPE_INT, "nsSizeLimit",
  75. &sizelimit_reslimit_handle ) != SLAPI_RESLIMIT_STATUS_SUCCESS ) {
  76. /* limit could not be registered -- fatal error? */
  77. }
  78. ...
  79. #endif
  80. /*
  81. * A successful call to slapi_reslimit_register() results in a new
  82. * entry in the reslimit_map, which is private to this source file.
  83. * The map data structure is protected using a single writer/multiple
  84. * reader locking scheme.
  85. *
  86. * To retrieve a binder-based limit, simple call
  87. * slapi_reslimit_get_integer_limit(). If a value was present in the
  88. * binder entry, it will be given back to the caller and
  89. * SLAPI_RESLIMIT_STATUS_SUCCESS will be returned. If no value was
  90. * present or the connection is NULL, SLAPI_RESLIMIT_STATUS_NOVALUE is
  91. * returned. Other errors may be returned also. Here's a sample call:
  92. */
  93. #if SLAPI_RESLIMIT_SAMPLE_CODE
  94. int rc, sizelimit;
  95. rc = slapi_reslimit_get_integer_limit( conn, sizelimit_reslimit_handle,
  96. &sizelimit );
  97. switch( rc ) {
  98. case SLAPI_RESLIMIT_STATUS_SUCCESS: /* got a value */
  99. break;
  100. case SLAPI_RESLIMIT_STATUS_NOVALUE: /* no limit value available */
  101. sizelimit = 500; /* use a default value */
  102. break;
  103. default: /* some other error occurred */
  104. sizelimit = 500; /* use a default value */
  105. }
  106. #endif
  107. /*
  108. * The function reslimit_cleanup() is called from main() to dispose of
  109. * memory, locks, etc. so tools like Purify() don't report leaks at exit.
  110. */
  111. /* End of implementation notes */
  112. #include "slap.h"
  113. /*
  114. * Macros.
  115. */
  116. #define SLAPI_RESLIMIT_MODULE "binder-based resource limits"
  117. /* #define SLAPI_RESLIMIT_DEBUG */ /* define this to enable extra logging */
  118. /* also forces trace log messages to */
  119. /* always be logged */
  120. #ifdef SLAPI_RESLIMIT_DEBUG
  121. #define SLAPI_RESLIMIT_TRACELEVEL LDAP_DEBUG_ANY
  122. #else /* SLAPI_RESLIMIT_DEBUG */
  123. #define SLAPI_RESLIMIT_TRACELEVEL LDAP_DEBUG_TRACE
  124. #endif /* SLAPI_RESLIMIT_DEBUG */
  125. /*
  126. * Structures and types.
  127. */
  128. /* Per-connection resource limits data */
  129. typedef struct slapi_reslimit_conndata {
  130. PRRWLock *rlcd_rwlock; /* to serialize access to the rest */
  131. int rlcd_integer_count; /* size of rlcd_integer_limit array */
  132. PRBool *rlcd_integer_available; /* array that says whether each */
  133. /* value is available */
  134. int *rlcd_integer_value; /* array that holds limit values */
  135. } SLAPIResLimitConnData;
  136. /* Mapping between attribute and limit */
  137. typedef struct slapi_reslimit_map {
  138. int rlmap_type; /* always SLAPI_RESLIMIT_TYPE_INT for now */
  139. char *rlmap_at; /* attribute type name */
  140. } SLAPIResLimitMap;
  141. /*
  142. * Static variables (module globals).
  143. */
  144. static int reslimit_inited = 0;
  145. static int reslimit_connext_objtype = 0;
  146. static int reslimit_connext_handle = 0;
  147. static struct slapi_reslimit_map *reslimit_map = NULL;
  148. static int reslimit_map_count = 0;
  149. static struct slapi_componentid *reslimit_componentid=NULL;
  150. /*
  151. * reslimit_map_rwlock is used to serialize access to
  152. * reslimit_map and reslimit_map_count
  153. */
  154. static PRRWLock *reslimit_map_rwlock = NULL;
  155. /*
  156. * Static functions.
  157. */
  158. static int reslimit_init( void );
  159. static void *reslimit_connext_constructor( void *object, void *parent );
  160. static void reslimit_connext_destructor( void *extension, void *object,
  161. void *parent );
  162. static int reslimit_get_ext( Slapi_Connection *conn, const char *logname,
  163. SLAPIResLimitConnData **rlcdpp );
  164. static int reslimit_bv2int( const struct berval *bvp );
  165. static char ** reslimit_get_registered_attributes();
  166. /*
  167. * reslimit_init() must be called before any resource related work
  168. * is done. It is safe to call this more than once, but reslimit_inited
  169. * can be tested to avoid a call.
  170. *
  171. * Returns zero if all goes well and non-zero if not.
  172. */
  173. static int
  174. reslimit_init( void )
  175. {
  176. if ( reslimit_inited == 0 ) {
  177. if ( slapi_register_object_extension( SLAPI_RESLIMIT_MODULE,
  178. SLAPI_EXT_CONNECTION, reslimit_connext_constructor,
  179. reslimit_connext_destructor,
  180. &reslimit_connext_objtype, &reslimit_connext_handle )
  181. != 0 ) {
  182. slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
  183. "reslimit_init: slapi_register_object_extension()"
  184. " failed\n" );
  185. return( -1 );
  186. }
  187. if (( reslimit_map_rwlock = PR_NewRWLock( PR_RWLOCK_RANK_NONE,
  188. "resourcelimit map rwlock" )) == NULL ) {
  189. slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
  190. "reslimit_init: PR_NewRWLock() failed\n" );
  191. return( -1 );
  192. }
  193. reslimit_inited = 1;
  194. }
  195. reslimit_componentid=generate_componentid(NULL,COMPONENT_RESLIMIT);
  196. return( 0 );
  197. }
  198. /*
  199. * Dispose of any allocated memory, locks, other resources. Called when
  200. * server is shutting down.
  201. */
  202. void
  203. reslimit_cleanup( void )
  204. {
  205. int i;
  206. if ( reslimit_map != NULL ) {
  207. for ( i = 0; i < reslimit_map_count; ++i ) {
  208. if ( reslimit_map[ i ].rlmap_at != NULL ) {
  209. slapi_ch_free( (void **)&reslimit_map[ i ].rlmap_at );
  210. }
  211. }
  212. slapi_ch_free( (void **)&reslimit_map );
  213. }
  214. if ( reslimit_map_rwlock != NULL ) {
  215. PR_DestroyRWLock( reslimit_map_rwlock );
  216. }
  217. if ( reslimit_componentid != NULL ) {
  218. release_componentid( reslimit_componentid );
  219. }
  220. }
  221. /*
  222. * constructor for the connection object extension.
  223. */
  224. static void *
  225. reslimit_connext_constructor( void *object, void *parent )
  226. {
  227. SLAPIResLimitConnData *rlcdp;
  228. PRRWLock *rwlock;
  229. if (( rwlock = PR_NewRWLock( PR_RWLOCK_RANK_NONE,
  230. "resource limit connection data rwlock" )) == NULL ) {
  231. slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
  232. "reslimit_connext_constructor: PR_NewRWLock() failed\n" );
  233. return( NULL );
  234. }
  235. rlcdp = (SLAPIResLimitConnData *)slapi_ch_calloc( 1,
  236. sizeof( SLAPIResLimitConnData ));
  237. rlcdp->rlcd_rwlock = rwlock;
  238. return( rlcdp );
  239. }
  240. /*
  241. * destructor for the connection object extension.
  242. */
  243. static void
  244. reslimit_connext_destructor( void *extension, void *object, void *parent )
  245. {
  246. SLAPIResLimitConnData *rlcdp = (SLAPIResLimitConnData *)extension;
  247. if ( rlcdp->rlcd_integer_available != NULL ) {
  248. slapi_ch_free( (void **)&rlcdp->rlcd_integer_available );
  249. }
  250. if ( rlcdp->rlcd_integer_value != NULL ) {
  251. slapi_ch_free( (void **)&rlcdp->rlcd_integer_value );
  252. }
  253. PR_DestroyRWLock( rlcdp->rlcd_rwlock );
  254. slapi_ch_free( (void **)&rlcdp );
  255. }
  256. /*
  257. * utility function to retrieve the connection object extension.
  258. *
  259. * if logname is non-NULL, errors are logged.
  260. */
  261. static int
  262. reslimit_get_ext( Slapi_Connection *conn, const char *logname,
  263. SLAPIResLimitConnData **rlcdpp )
  264. {
  265. if ( !reslimit_inited && reslimit_init() != 0 ) {
  266. if ( NULL != logname ) {
  267. slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
  268. "%s: reslimit_init() failed\n", logname );
  269. }
  270. return( SLAPI_RESLIMIT_STATUS_INIT_FAILURE );
  271. }
  272. if (( *rlcdpp = (SLAPIResLimitConnData *)slapi_get_object_extension(
  273. reslimit_connext_objtype, conn,
  274. reslimit_connext_handle )) == NULL ) {
  275. if ( NULL != logname ) {
  276. slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
  277. "%s: slapi_get_object_extension() returned NULL\n", logname );
  278. }
  279. return( SLAPI_RESLIMIT_STATUS_INTERNAL_ERROR );
  280. }
  281. return( SLAPI_RESLIMIT_STATUS_SUCCESS );
  282. }
  283. /*
  284. * utility function to convert a string-represented integer to an int.
  285. *
  286. * XXXmcs: wouldn't need this if slapi_value_get_int() returned a signed int!
  287. */
  288. static int
  289. reslimit_bv2int( const struct berval *bvp )
  290. {
  291. int rc = 0;
  292. char smallbuf[ 25 ], *buf;
  293. if ( bvp != NULL ) {
  294. /* make a copy to ensure it is zero-terminated */
  295. if ( bvp->bv_len < sizeof( smallbuf )) {
  296. buf = smallbuf;
  297. } else {
  298. buf = slapi_ch_malloc( bvp->bv_len + 1 );
  299. }
  300. memcpy( buf, bvp->bv_val, bvp->bv_len);
  301. buf[ bvp->bv_len ] = '\0';
  302. rc = atoi( buf );
  303. if ( buf != smallbuf ) {
  304. slapi_ch_free( (void **)&smallbuf );
  305. }
  306. }
  307. return( rc );
  308. }
  309. /**** Semi-public functions start here ***********************************/
  310. /*
  311. * These functions are exposed to other parts of the server only, i.e.,
  312. * they are NOT part of the official SLAPI API.
  313. */
  314. /*
  315. * Set the resource limits associated with connection `conn' based on the
  316. * entry named by `dn'. If `dn' is NULL, limits are returned to their
  317. * default state.
  318. *
  319. * A SLAPI_RESLIMIT_STATUS_... code is returned.
  320. */
  321. int
  322. reslimit_update_from_dn( Slapi_Connection *conn, Slapi_DN *dn )
  323. {
  324. Slapi_Entry *e;
  325. int rc;
  326. e = NULL;
  327. if ( dn != NULL ) {
  328. char ** attrs = reslimit_get_registered_attributes();
  329. (void) slapi_search_internal_get_entry( dn, attrs, &e , reslimit_componentid);
  330. charray_free(attrs);
  331. }
  332. rc = reslimit_update_from_entry( conn, e );
  333. if ( NULL != e ) {
  334. slapi_entry_free( e );
  335. }
  336. return( rc );
  337. }
  338. /*
  339. * Set the resource limits associated with connection `conn' based on the
  340. * entry `e'. If `e' is NULL, limits are returned to their default state.
  341. * If `conn' is NULL, nothing is done.
  342. *
  343. * A SLAPI_RESLIMIT_STATUS_... code is returned.
  344. */
  345. int
  346. reslimit_update_from_entry( Slapi_Connection *conn, Slapi_Entry *e )
  347. {
  348. char *fnname = "reslimit_update_from_entry()";
  349. char *actual_type_name, *get_ext_logname;
  350. int i, rc, type_name_disposition, free_flags;
  351. SLAPIResLimitConnData *rlcdp;
  352. Slapi_ValueSet *vs;
  353. LDAPDebug( SLAPI_RESLIMIT_TRACELEVEL, "=> %s conn=0x%x, entry=0x%x\n",
  354. fnname, conn, e );
  355. rc = SLAPI_RESLIMIT_STATUS_SUCCESS; /* optimistic */
  356. /* if conn is NULL, there is nothing to be done */
  357. if ( conn == NULL ) {
  358. goto log_and_return;
  359. }
  360. if ( NULL == e ) {
  361. get_ext_logname = NULL; /* do not log errors if resetting limits */
  362. } else {
  363. get_ext_logname = fnname;
  364. }
  365. if (( rc = reslimit_get_ext( conn, get_ext_logname, &rlcdp )) !=
  366. SLAPI_RESLIMIT_STATUS_SUCCESS ) {
  367. goto log_and_return;
  368. }
  369. /* LOCK FOR READ -- map lock */
  370. PR_RWLock_Rlock( reslimit_map_rwlock );
  371. /* LOCK FOR WRITE -- conn. data lock */
  372. PR_RWLock_Wlock( rlcdp->rlcd_rwlock );
  373. if ( rlcdp->rlcd_integer_value == NULL ) {
  374. rlcdp->rlcd_integer_count = reslimit_map_count;
  375. if ( rlcdp->rlcd_integer_count > 0 ) {
  376. rlcdp->rlcd_integer_available = (PRBool *)slapi_ch_calloc(
  377. rlcdp->rlcd_integer_count, sizeof( PRBool ));
  378. rlcdp->rlcd_integer_value = (int *)slapi_ch_calloc(
  379. rlcdp->rlcd_integer_count, sizeof( int ));
  380. }
  381. }
  382. for ( i = 0; i < rlcdp->rlcd_integer_count; ++i ) {
  383. if ( reslimit_map[ i ].rlmap_type != SLAPI_RESLIMIT_TYPE_INT ) {
  384. continue;
  385. }
  386. LDAPDebug( SLAPI_RESLIMIT_TRACELEVEL,
  387. "%s: setting limit for handle %d (based on %s)\n",
  388. fnname, i, reslimit_map[ i ].rlmap_at );
  389. rlcdp->rlcd_integer_available[ i ] = PR_FALSE;
  390. if ( NULL != e && 0 == slapi_vattr_values_get( e,
  391. reslimit_map[ i ].rlmap_at, &vs, &type_name_disposition,
  392. &actual_type_name, 0, &free_flags )) {
  393. Slapi_Value *v;
  394. int index;
  395. const struct berval *bvp;
  396. if (( index = slapi_valueset_first_value( vs, &v )) != -1 &&
  397. ( bvp = slapi_value_get_berval( v )) != NULL ) {
  398. rlcdp->rlcd_integer_value[ i ] = reslimit_bv2int( bvp );
  399. rlcdp->rlcd_integer_available[ i ] = PR_TRUE;
  400. LDAPDebug( SLAPI_RESLIMIT_TRACELEVEL,
  401. "%s: set limit based on %s to %d\n",
  402. fnname, reslimit_map[ i ].rlmap_at,
  403. rlcdp->rlcd_integer_value[ i ] );
  404. if ( slapi_valueset_next_value( vs, index, &v ) != -1 ) {
  405. char ebuf[ BUFSIZ ];
  406. slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
  407. "%s: ignoring multiple values for %s in entry %s\n",
  408. fnname, reslimit_map[ i ].rlmap_at,
  409. escape_string( slapi_entry_get_dn_const( e ),
  410. ebuf ));
  411. }
  412. }
  413. slapi_vattr_values_free( &vs, &actual_type_name, free_flags);
  414. }
  415. }
  416. PR_RWLock_Unlock( rlcdp->rlcd_rwlock );
  417. /* UNLOCKED -- conn. data lock */
  418. PR_RWLock_Unlock( reslimit_map_rwlock );
  419. /* UNLOCKED -- map lock */
  420. log_and_return:
  421. LDAPDebug( SLAPI_RESLIMIT_TRACELEVEL, "<= %s returning status %d\n",
  422. fnname, rc, 0 );
  423. return( rc );
  424. }
  425. /* return the list of registered attributes */
  426. static char ** reslimit_get_registered_attributes()
  427. {
  428. int i;
  429. char **attrs=NULL;
  430. /* LOCK FOR READ -- map lock */
  431. PR_RWLock_Rlock( reslimit_map_rwlock );
  432. for ( i = 0; i < reslimit_map_count; ++i ) {
  433. if ( reslimit_map[ i ].rlmap_at != NULL ) {
  434. charray_add(&attrs, slapi_ch_strdup(reslimit_map[ i ].rlmap_at));
  435. }
  436. }
  437. PR_RWLock_Unlock( reslimit_map_rwlock );
  438. return attrs;
  439. }
  440. /**** Public functions can be found below this point *********************/
  441. /*
  442. * These functions are exposed to plugins, i.e., they are part of the
  443. * official SLAPI API.
  444. */
  445. /*
  446. * Register a new resource to be tracked. `type' must be
  447. * SLAPI_RESLIMIT_TYPE_INT and `attrname' is an LDAP attribute type that
  448. * is consulted in the bound entry to determine the limit's value.
  449. *
  450. * A SLAPI_RESLIMIT_STATUS_... code is returned. If it is ...SUCCESS, then
  451. * `*handlep' is set to an opaque integer value that should be used in
  452. * subsequent calls to slapi_reslimit_get_integer_limit().
  453. */
  454. int
  455. slapi_reslimit_register( int type, const char *attrname, int *handlep )
  456. {
  457. char *fnname = "slapi_reslimit_register()";
  458. int i, rc;
  459. LDAPDebug( SLAPI_RESLIMIT_TRACELEVEL, "=> %s attrname=%s\n",
  460. fnname, attrname, 0 );
  461. rc = SLAPI_RESLIMIT_STATUS_SUCCESS; /* optimistic */
  462. /* initialize if necessary */
  463. if ( !reslimit_inited && reslimit_init() != 0 ) {
  464. slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
  465. "%s: reslimit_init() failed\n", fnname );
  466. rc = SLAPI_RESLIMIT_STATUS_INIT_FAILURE;
  467. goto log_and_return;
  468. }
  469. /* sanity check parameters */
  470. if ( type != SLAPI_RESLIMIT_TYPE_INT || attrname == NULL
  471. || handlep == NULL ) {
  472. slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
  473. "%s: parameter error\n", fnname );
  474. rc = SLAPI_RESLIMIT_STATUS_PARAM_ERROR;
  475. goto log_and_return;
  476. }
  477. /* LOCK FOR WRITE -- map lock */
  478. PR_RWLock_Wlock( reslimit_map_rwlock );
  479. /*
  480. * check that attrname is not already registered
  481. */
  482. for ( i = 0; i < reslimit_map_count; ++i ) {
  483. if ( 0 == slapi_attr_type_cmp( reslimit_map[ i ].rlmap_at,
  484. attrname, SLAPI_TYPE_CMP_EXACT )) {
  485. slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
  486. "%s: parameter error (%s already registered)\n",
  487. attrname, fnname );
  488. rc = SLAPI_RESLIMIT_STATUS_PARAM_ERROR;
  489. goto unlock_and_return;
  490. }
  491. }
  492. /*
  493. * expand the map array and add the new element
  494. */
  495. reslimit_map = (SLAPIResLimitMap *)slapi_ch_realloc(
  496. (char *)reslimit_map,
  497. (1 + reslimit_map_count) * sizeof( SLAPIResLimitMap ));
  498. reslimit_map[ reslimit_map_count ].rlmap_type = type;
  499. reslimit_map[ reslimit_map_count ].rlmap_at
  500. = slapi_ch_strdup( attrname );
  501. *handlep = reslimit_map_count;
  502. ++reslimit_map_count;
  503. unlock_and_return:
  504. PR_RWLock_Unlock( reslimit_map_rwlock );
  505. /* UNLOCKED -- map lock */
  506. log_and_return:
  507. LDAPDebug( SLAPI_RESLIMIT_TRACELEVEL,
  508. "<= %s returning status=%d, handle=%d\n", fnname, rc,
  509. (handlep == NULL) ? -1 : *handlep );
  510. return( rc );
  511. }
  512. /*
  513. * Retrieve the integer limit associated with connection `conn' for
  514. * the resource identified by `handle'.
  515. *
  516. * A SLAPI_RESLIMIT_STATUS_... code is returned:
  517. *
  518. * SLAPI_RESLIMIT_STATUS_SUCCESS -- `*limitp' is set to the limit value.
  519. * SLAPI_RESLIMIT_STATUS_NOVALUE -- no limit value is available (use default).
  520. * Another SLAPI_RESLIMIT_STATUS_... code -- some more fatal error occurred.
  521. *
  522. * If `conn' is NULL, SLAPI_RESLIMIT_STATUS_NOVALUE is returned.
  523. */
  524. int
  525. slapi_reslimit_get_integer_limit( Slapi_Connection *conn, int handle,
  526. int *limitp )
  527. {
  528. char *fnname = "slapi_reslimit_get_integer_limit()";
  529. int rc;
  530. SLAPIResLimitConnData *rlcdp;
  531. LDAPDebug( SLAPI_RESLIMIT_TRACELEVEL, "=> %s conn=0x%x, handle=%d\n",
  532. fnname, conn, handle );
  533. rc = SLAPI_RESLIMIT_STATUS_SUCCESS; /* optimistic */
  534. /* sanity check parameters */
  535. if ( limitp == NULL ) {
  536. slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
  537. "%s: parameter error\n", fnname );
  538. rc = SLAPI_RESLIMIT_STATUS_PARAM_ERROR;
  539. goto log_and_return;
  540. }
  541. if ( conn == NULL ) {
  542. rc = SLAPI_RESLIMIT_STATUS_NOVALUE;
  543. goto log_and_return;
  544. }
  545. if (( rc = reslimit_get_ext( conn, fnname, &rlcdp )) !=
  546. SLAPI_RESLIMIT_STATUS_SUCCESS ) {
  547. goto log_and_return;
  548. }
  549. if(rlcdp->rlcd_integer_count==0) { /* peek at it to avoid lock */
  550. rc = SLAPI_RESLIMIT_STATUS_NOVALUE;
  551. } else {
  552. PR_RWLock_Rlock( rlcdp->rlcd_rwlock );
  553. if(rlcdp->rlcd_integer_count==0) {
  554. rc = SLAPI_RESLIMIT_STATUS_NOVALUE;
  555. } else if ( handle < 0 || handle >= rlcdp->rlcd_integer_count ) {
  556. slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
  557. "%s: unknown handle %d\n", fnname, handle );
  558. rc = SLAPI_RESLIMIT_STATUS_UNKNOWN_HANDLE;
  559. } else if ( rlcdp->rlcd_integer_available[ handle ] ) {
  560. *limitp = rlcdp->rlcd_integer_value[ handle ];
  561. } else {
  562. rc = SLAPI_RESLIMIT_STATUS_NOVALUE;
  563. }
  564. PR_RWLock_Unlock( rlcdp->rlcd_rwlock );
  565. }
  566. log_and_return:
  567. if ( LDAPDebugLevelIsSet( LDAP_DEBUG_TRACE )) {
  568. if ( rc == SLAPI_RESLIMIT_STATUS_SUCCESS ) {
  569. LDAPDebug( SLAPI_RESLIMIT_TRACELEVEL,
  570. "<= %s returning SUCCESS, value=%d\n", fnname, *limitp, 0 );
  571. } else if ( rc == SLAPI_RESLIMIT_STATUS_NOVALUE ) {
  572. LDAPDebug( SLAPI_RESLIMIT_TRACELEVEL, "<= %s returning NO VALUE\n",
  573. fnname, 0, 0 );
  574. } else {
  575. LDAPDebug( SLAPI_RESLIMIT_TRACELEVEL, "<= %s returning ERROR %d\n",
  576. fnname, rc, 0 );
  577. }
  578. }
  579. return( rc );
  580. }
  581. /**** Public functions END ***********************************************/