utils.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  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. /***********************************************************************
  42. ** NAME
  43. ** utils.c
  44. **
  45. ** DESCRIPTION
  46. **
  47. **
  48. ** AUTHOR
  49. ** <[email protected]>
  50. **
  51. ***********************************************************************/
  52. /***********************************************************************
  53. ** Includes
  54. ***********************************************************************/
  55. #include "plugin-utils.h"
  56. #include "nspr.h"
  57. static char *plugin_name = "utils";
  58. /*
  59. * Lock for updating a counter (global for all counters)
  60. */
  61. static Slapi_Mutex *counter_lock = NULL;
  62. /* ------------------------------------------------------------ */
  63. /*
  64. * op_error - Record (and report) an operational error.
  65. */
  66. int
  67. op_error(int internal_error) {
  68. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
  69. "Internal error: %d\n", internal_error);
  70. return LDAP_OPERATIONS_ERROR;
  71. }
  72. int initCounterLock() {
  73. if ( NULL == counter_lock ) {
  74. if ( !(counter_lock = slapi_new_mutex()) ) {
  75. return 200;
  76. }
  77. }
  78. return 0;
  79. }
  80. /* ------------------------------------------------------------ */
  81. /*
  82. * readPblockAndEntry - search for and read an entry
  83. * Return:
  84. * A pblock containing the entry, or NULL
  85. */
  86. Slapi_PBlock *
  87. readPblockAndEntry( const char *baseDN, const char *filter,
  88. char *attrs[] ) {
  89. Slapi_PBlock *spb = NULL;
  90. BEGIN
  91. int sres;
  92. /* Perform the search - the new pblock needs to be freed */
  93. spb = slapi_search_internal((char *)baseDN, LDAP_SCOPE_BASE,
  94. (char *)filter, NULL, attrs, 0);
  95. if ( !spb ) {
  96. op_error(20);
  97. break;
  98. }
  99. if ( slapi_pblock_get( spb, SLAPI_PLUGIN_INTOP_RESULT, &sres ) ) {
  100. op_error(21);
  101. break;
  102. } else if (sres) {
  103. op_error(22);
  104. break;
  105. }
  106. END
  107. return spb;
  108. }
  109. /* ------------------------------------------------------------ */
  110. /*
  111. * hasObjectClass - read an entry and check if it has a
  112. * particular object class value
  113. * Return:
  114. * 1 - the entry contains the object class value
  115. * 0 - the entry doesn't contain the object class value
  116. */
  117. int
  118. entryHasObjectClass(Slapi_PBlock *pb, Slapi_Entry *e,
  119. const char *objectClass) {
  120. Slapi_Attr *attr;
  121. Slapi_Value *v;
  122. const struct berval *bv;
  123. int vhint;
  124. if ( slapi_entry_attr_find(e, "objectclass", &attr) ) {
  125. return 0; /* no objectclass values! */
  126. }
  127. /*
  128. * Check each of the object class values in turn.
  129. */
  130. for ( vhint = slapi_attr_first_value( attr, &v );
  131. vhint != -1;
  132. vhint = slapi_attr_next_value( attr, vhint, &v )) {
  133. bv = slapi_value_get_berval(v);
  134. if ( NULL != bv && NULL != bv->bv_val &&
  135. !strcasecmp(bv->bv_val, objectClass) ) {
  136. return 1;
  137. }
  138. }
  139. return 0;
  140. }
  141. /* ------------------------------------------------------------ */
  142. /*
  143. * dnHasObjectClass - read an entry if it has a particular object class
  144. * Return:
  145. * A pblock containing the entry, or NULL
  146. */
  147. Slapi_PBlock *
  148. dnHasObjectClass( const char *baseDN, const char *objectClass ) {
  149. char *filter = NULL;
  150. Slapi_PBlock *spb = NULL;
  151. BEGIN
  152. Slapi_Entry **entries;
  153. char *attrs[2];
  154. /* Perform the search - the new pblock needs to be freed */
  155. attrs[0] = "objectclass";
  156. attrs[1] = NULL;
  157. filter = PR_smprintf("objectclass=%s", objectClass );
  158. if ( !(spb = readPblockAndEntry( baseDN, filter, attrs) ) ) {
  159. break;
  160. }
  161. if ( slapi_pblock_get(spb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
  162. &entries) ) {
  163. op_error(23);
  164. break;
  165. }
  166. /*
  167. * Can only be one entry returned on a base search; just check
  168. * the first one
  169. */
  170. if ( !*entries ) {
  171. /* Clean up */
  172. slapi_free_search_results_internal(spb);
  173. slapi_pblock_destroy(spb);
  174. spb = NULL;
  175. }
  176. END
  177. if (filter) {
  178. PR_smprintf_free(filter);
  179. }
  180. return spb;
  181. }
  182. /* ------------------------------------------------------------ */
  183. /*
  184. * dnHasAttribute - read an entry if it has a particular attribute
  185. * Return:
  186. * The entry, or NULL
  187. */
  188. Slapi_PBlock *
  189. dnHasAttribute( const char *baseDN, const char *attrName ) {
  190. Slapi_PBlock *spb = NULL;
  191. char *filter = NULL;
  192. BEGIN
  193. int sres;
  194. Slapi_Entry **entries;
  195. char *attrs[2];
  196. /* Perform the search - the new pblock needs to be freed */
  197. attrs[0] = (char *)attrName;
  198. attrs[1] = NULL;
  199. filter = PR_smprintf( "%s=*", attrName );
  200. spb = slapi_search_internal((char *)baseDN, LDAP_SCOPE_BASE,
  201. filter, NULL, attrs, 0);
  202. if ( !spb ) {
  203. op_error(20);
  204. break;
  205. }
  206. if ( slapi_pblock_get( spb, SLAPI_PLUGIN_INTOP_RESULT, &sres ) ) {
  207. op_error(21);
  208. break;
  209. } else if (sres) {
  210. op_error(22);
  211. break;
  212. }
  213. if ( slapi_pblock_get(spb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
  214. &entries) ) {
  215. op_error(23);
  216. break;
  217. }
  218. /*
  219. * Can only be one entry returned on a base search; just check
  220. * the first one
  221. */
  222. if ( !*entries ) {
  223. /* Clean up */
  224. slapi_free_search_results_internal(spb);
  225. slapi_pblock_destroy(spb);
  226. spb = NULL;
  227. }
  228. END
  229. if (filter) {
  230. PR_smprintf_free(filter);
  231. }
  232. return spb;
  233. }
  234. /* ------------------------------------------------------------ */
  235. /*
  236. * setCounter - set the value of a counter
  237. *
  238. * Return:
  239. * LDAP_SUCCESS - updated the attribute
  240. * other - failure to update the count
  241. */
  242. int
  243. setCounter( Slapi_Entry *e, const char *attrName, int value ) {
  244. int result = LDAP_SUCCESS;
  245. Slapi_PBlock *modifySpb = NULL;
  246. char strValue[16];
  247. char *strValues[2] = { NULL };
  248. LDAPMod mod;
  249. LDAPMod *mods[2];
  250. int res;
  251. BEGIN
  252. /* Store the updated value */
  253. strValues[0] = strValue;
  254. sprintf( strValue, "%d", value );
  255. mod.mod_op = LDAP_MOD_REPLACE;
  256. mod.mod_type = (char *)attrName;
  257. mod.mod_values = strValues;
  258. mods[0] = &mod;
  259. mods[1] = NULL;
  260. modifySpb = slapi_modify_internal( slapi_entry_get_dn(e), mods,
  261. NULL, 1 );
  262. /* Check if the operation succeeded */
  263. if ( slapi_pblock_get( modifySpb, SLAPI_PLUGIN_INTOP_RESULT,
  264. &res ) ) {
  265. result = op_error(33);
  266. break;
  267. } else if (res) {
  268. result = op_error(34);
  269. break;
  270. }
  271. slapi_pblock_destroy(modifySpb);
  272. END
  273. return result;
  274. }
  275. /* ------------------------------------------------------------ */
  276. /*
  277. * updateCounter - read and increment/decrement the value of a counter
  278. *
  279. * Return:
  280. * LDAP_SUCCESS - updated the attribute
  281. * other - failure to update the count
  282. */
  283. int
  284. updateCounter( Slapi_Entry *e, const char *attrName, int increment ) {
  285. int result = LDAP_SUCCESS;
  286. Slapi_PBlock *modifySpb = NULL;
  287. Slapi_Attr *attr;
  288. int value = 0;
  289. char strValue[16];
  290. char *strValues[2] = { NULL };
  291. LDAPMod mod;
  292. LDAPMod *mods[2];
  293. int res;
  294. BEGIN
  295. /* Lock the entry */
  296. slapi_lock_mutex(counter_lock);
  297. /* Get the count attribute */
  298. if ( slapi_entry_attr_find(e, (char *)attrName, &attr) ) {
  299. /* No count yet; that's OK */
  300. } else {
  301. /* Get the first value for the attribute */
  302. Slapi_Value *v = NULL;
  303. const struct berval *bv = NULL;
  304. if ( -1 == slapi_attr_first_value( attr, &v ) || NULL == v ||
  305. NULL == ( bv = slapi_value_get_berval(v)) ||
  306. NULL == bv->bv_val ) {
  307. /* No values yet; that's OK, too */
  308. } else {
  309. value = atoi( bv->bv_val );
  310. }
  311. }
  312. /* Add the increment */
  313. value += increment;
  314. if ( value < 0 ) {
  315. value = 0;
  316. }
  317. /* Store the updated value */
  318. strValues[0] = strValue;
  319. sprintf( strValue, "%d", value );
  320. mod.mod_op = LDAP_MOD_REPLACE;
  321. mod.mod_type = (char *)attrName;
  322. mod.mod_values = strValues;
  323. mods[0] = &mod;
  324. mods[1] = NULL;
  325. modifySpb = slapi_modify_internal( slapi_entry_get_dn(e), mods,
  326. NULL, 1 );
  327. /* Check if the operation succeeded */
  328. if ( slapi_pblock_get( modifySpb, SLAPI_PLUGIN_INTOP_RESULT,
  329. &res ) ) {
  330. result = op_error(33);
  331. break;
  332. } else if (res) {
  333. result = op_error(34);
  334. break;
  335. }
  336. slapi_pblock_destroy(modifySpb);
  337. /* Unlock the entry */
  338. slapi_unlock_mutex(counter_lock);
  339. #ifdef DEBUG
  340. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
  341. "adjusted %s in %s by %d to %d\n",
  342. attrName, slapi_entry_get_dn(e), increment, value);
  343. #endif
  344. END
  345. return result;
  346. }
  347. /* ------------------------------------------------------------ */
  348. /*
  349. * updateCounterByDN - read and increment/decrement the value of a counter
  350. *
  351. * Return:
  352. * LDAP_SUCCESS - updated the attribute
  353. * other - failure to update the count
  354. */
  355. int
  356. updateCounterByDN( const char *dn, const char *attrName, int increment ) {
  357. int result = LDAP_SUCCESS;
  358. Slapi_PBlock *spb = NULL;
  359. Slapi_Entry **entries;
  360. BEGIN
  361. char *attrs[2];
  362. int sres;
  363. /* Perform the search - the new pblock needs to be freed */
  364. attrs[0] = (char *)attrName;
  365. attrs[1] = NULL;
  366. spb = slapi_search_internal((char *)dn, LDAP_SCOPE_BASE,
  367. "objectclass=*", NULL, attrs, 0);
  368. if ( !spb ) {
  369. result = op_error(20);
  370. break;
  371. }
  372. if ( slapi_pblock_get( spb, SLAPI_PLUGIN_INTOP_RESULT, &sres ) ) {
  373. result = op_error(21);
  374. break;
  375. } else if (sres) {
  376. result = op_error(22);
  377. break;
  378. }
  379. if ( slapi_pblock_get(spb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
  380. &entries) ) {
  381. result = op_error(23);
  382. break;
  383. }
  384. END
  385. if ( 0 == result ) {
  386. result = updateCounter( *entries, attrName, increment );
  387. }
  388. if ( NULL != spb ) {
  389. /* Clean up */
  390. slapi_free_search_results_internal(spb);
  391. slapi_pblock_destroy(spb);
  392. }
  393. return result;
  394. }
  395. /*
  396. * Lock for accessing a cache (global for all caches)
  397. */
  398. static Slapi_Mutex *cache_lock = NULL;
  399. DNLink *cacheInit() {
  400. DNLink *root;
  401. slapi_lock_mutex(cache_lock);
  402. root = (DNLink *)slapi_ch_malloc( sizeof(DNLink) );
  403. root->next = NULL;
  404. root->data = NULL;
  405. root->dn = (char *)slapi_ch_malloc(1);
  406. root->dn[0] = 0;
  407. slapi_unlock_mutex(cache_lock);
  408. return root;
  409. }
  410. DNLink *cacheAdd( DNLink *root, char *dn, void *data ) {
  411. if ( NULL == root ) {
  412. return NULL;
  413. }
  414. slapi_lock_mutex(cache_lock);
  415. for( ; root->next; root = root->next ) {
  416. }
  417. root->next = (DNLink *)slapi_ch_malloc( sizeof(DNLink) );
  418. root = root->next;
  419. root->dn = dn;
  420. root->data = data;
  421. root->next = NULL;
  422. slapi_unlock_mutex(cache_lock);
  423. return root;
  424. }
  425. char *cacheRemove( DNLink *root, char *dn ) {
  426. char *found = NULL;
  427. DNLink *current = root;
  428. DNLink *prev = NULL;
  429. if ( NULL == root ) {
  430. return NULL;
  431. }
  432. slapi_lock_mutex(cache_lock);
  433. for( ; current; prev = current, current = current->next ) {
  434. if ( !strcmp( current->dn, dn ) ) {
  435. found = current->dn;
  436. prev->next = current->next;
  437. slapi_ch_free( (void **)&current );
  438. break;
  439. }
  440. }
  441. slapi_unlock_mutex(cache_lock);
  442. return found;
  443. }
  444. int cacheDelete( DNLink *root, char *dn ) {
  445. char *found = cacheRemove( root, dn );
  446. if ( found ) {
  447. slapi_ch_free( (void **)&found );
  448. return 0;
  449. } else {
  450. return 1;
  451. }
  452. }
  453. DNLink *cacheFind( DNLink *root, char *dn ) {
  454. if ( NULL == root ) {
  455. return NULL;
  456. }
  457. slapi_lock_mutex(cache_lock);
  458. for( ; root && strcmp(dn, root->dn); root = root->next ) {
  459. }
  460. slapi_unlock_mutex(cache_lock);
  461. return root;
  462. }