attrsyntax.c 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054
  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. /* attrsyntax.c */
  42. #include "slap.h"
  43. #include <plhash.h>
  44. /*
  45. * Note: if both the oid2asi and name2asi locks are acquired at the
  46. * same time, the old2asi one should be acquired first,
  47. */
  48. /*
  49. * This hashtable maps the oid to the struct asyntaxinfo for that oid.
  50. */
  51. static PLHashTable *oid2asi = NULL;
  52. /* read/write lock to protect table */
  53. static PRRWLock *oid2asi_lock = NULL;
  54. /*
  55. * This hashtable maps the name or alias of the attribute to the
  56. * syntax info structure for that attribute. An attribute type has as
  57. * many entries in the name2asi table as it has names and aliases, but
  58. * all entries point to the same struct asyntaxinfo.
  59. */
  60. static PLHashTable *name2asi = NULL;
  61. /* read/write lock to protect table */
  62. static PRRWLock *name2asi_lock = NULL;
  63. #define AS_LOCK_READ(l) PR_RWLock_Rlock(l)
  64. #define AS_LOCK_WRITE(l) PR_RWLock_Wlock(l)
  65. #define AS_UNLOCK_READ(l) PR_RWLock_Unlock(l)
  66. #define AS_UNLOCK_WRITE(l) PR_RWLock_Unlock(l)
  67. static void *attr_syntax_get_plugin_by_name_with_default( const char *type );
  68. static void attr_syntax_delete_no_lock( struct asyntaxinfo *asip,
  69. PRBool remove_from_oid_table );
  70. static struct asyntaxinfo *attr_syntax_get_by_oid_locking_optional( const
  71. char *oid, PRBool use_lock);
  72. #ifdef ATTR_LDAP_DEBUG
  73. static void attr_syntax_print();
  74. #endif
  75. static int attr_syntax_init(void);
  76. void
  77. attr_syntax_read_lock(void)
  78. {
  79. if (0 != attr_syntax_init()) return;
  80. AS_LOCK_READ(oid2asi_lock);
  81. AS_LOCK_READ(name2asi_lock);
  82. }
  83. void
  84. attr_syntax_unlock_read(void)
  85. {
  86. if(name2asi_lock) AS_UNLOCK_READ(name2asi_lock);
  87. if(oid2asi_lock) AS_UNLOCK_READ(oid2asi_lock);
  88. }
  89. #if 0
  90. static int
  91. check_oid( const char *oid ) {
  92. int i = 0, length_oid = 0, rc = 0;
  93. if ( oid == NULL) {
  94. /* this is bad */
  95. LDAPDebug (LDAP_DEBUG_ANY, "NULL passed to check_oid\n",0,0,0);
  96. return 0;
  97. }
  98. length_oid = strlen(oid);
  99. if (length_oid < 4) {
  100. /* this is probably bad */
  101. LDAPDebug (LDAP_DEBUG_ANY, "Bad oid %s passed to check_oid\n",oid,0,0);
  102. return 0;
  103. }
  104. rc = strcasecmp(oid+(length_oid-4), "-oid");
  105. if ( 0 == rc ) {
  106. return 1;
  107. }
  108. /* If not, the OID must begin and end with a digit, and contain only
  109. digits and dots */
  110. if ( !isdigit(oid[0]) ||
  111. !isdigit(oid[length_oid-1]) ) {
  112. LDAPDebug (LDAP_DEBUG_ANY, "Non numeric oid %s passed to check_oid\n",oid,0,0);
  113. return 0;
  114. }
  115. /* check to see that it contains only digits and dots */
  116. for ( i = 0; i < length_oid; i++ ) {
  117. if ( !isdigit(oid[i]) && oid[i] != '.' ){
  118. LDAPDebug (LDAP_DEBUG_ANY, "Non numeric oid %s passed to check_oid\n",oid,0,0);
  119. return 0;
  120. }
  121. }
  122. /* The oid is OK if we're here */
  123. return 1;
  124. }
  125. #endif
  126. #define NBUCKETS(ht) (1 << (PL_HASH_BITS - (ht)->shift))
  127. #if 0
  128. static int
  129. attr_syntax_check_oids()
  130. {
  131. int ii = 0;
  132. int nbad = 0;
  133. AS_LOCK_READ(oid2asi_lock);
  134. ii = NBUCKETS(oid2asi);
  135. for (;ii;--ii) {
  136. PLHashEntry *he = oid2asi->buckets[ii-1];
  137. for (; he; he = he->next) {
  138. if (!check_oid(he->key)) {
  139. LDAPDebug(LDAP_DEBUG_ANY, "Error: bad oid %s in bucket %d\n",
  140. he->key, ii-1, 0);
  141. nbad++;
  142. }
  143. }
  144. }
  145. AS_UNLOCK_READ(oid2asi_lock);
  146. return nbad;
  147. }
  148. #endif
  149. void
  150. attr_syntax_free( struct asyntaxinfo *a )
  151. {
  152. PR_ASSERT( a->asi_refcnt == 0 );
  153. cool_charray_free( a->asi_aliases );
  154. slapi_ch_free( (void**)&a->asi_name );
  155. slapi_ch_free( (void **)&a->asi_desc );
  156. slapi_ch_free( (void **)&a->asi_oid );
  157. slapi_ch_free( (void **)&a->asi_superior );
  158. slapi_ch_free( (void **)&a->asi_mr_equality );
  159. slapi_ch_free( (void **)&a->asi_mr_ordering );
  160. slapi_ch_free( (void **)&a->asi_mr_substring );
  161. cool_charray_free( a->asi_origin );
  162. slapi_ch_free( (void **) &a );
  163. }
  164. static struct asyntaxinfo *
  165. attr_syntax_new()
  166. {
  167. return (struct asyntaxinfo *)slapi_ch_calloc(1, sizeof(struct asyntaxinfo));
  168. }
  169. /*
  170. * hashNocaseString - used for case insensitive hash lookups
  171. */
  172. static PLHashNumber
  173. hashNocaseString(const void *key)
  174. {
  175. PLHashNumber h = 0;
  176. const unsigned char *s;
  177. for (s = key; *s; s++)
  178. h = (h >> 28) ^ (h << 4) ^ (tolower(*s));
  179. return h;
  180. }
  181. /*
  182. * hashNocaseCompare - used for case insensitive hash key comparisons
  183. */
  184. static PRIntn
  185. hashNocaseCompare(const void *v1, const void *v2)
  186. {
  187. return (strcasecmp((char *)v1, (char *)v2) == 0);
  188. }
  189. /*
  190. * Given an OID, return the syntax info. If there is more than one
  191. * attribute syntax with the same OID (i.e. aliases), the first one
  192. * will be returned. This is usually the "canonical" one, but it may
  193. * not be.
  194. *
  195. * Note: once the caller is finished using it, the structure returned must
  196. * be returned by calling to attr_syntax_return().
  197. */
  198. struct asyntaxinfo *
  199. attr_syntax_get_by_oid(const char *oid)
  200. {
  201. return attr_syntax_get_by_oid_locking_optional( oid, PR_TRUE);
  202. }
  203. /*
  204. * A version of attr_syntax_get_by_oid() that allows you to bypass using
  205. * a lock to access the global oid hash table.
  206. *
  207. * Note: once the caller is finished using it, the structure must be
  208. * returned by calling attr_syntax_return_locking_optional() with the
  209. * same use_lock parameter.
  210. */
  211. static struct asyntaxinfo *
  212. attr_syntax_get_by_oid_locking_optional( const char *oid, PRBool use_lock )
  213. {
  214. struct asyntaxinfo *asi = 0;
  215. if (oid2asi)
  216. {
  217. if ( use_lock ) AS_LOCK_READ(oid2asi_lock);
  218. asi = (struct asyntaxinfo *)PL_HashTableLookup_const(oid2asi, oid);
  219. if (asi)
  220. {
  221. PR_AtomicIncrement( &asi->asi_refcnt );
  222. }
  223. if ( use_lock ) AS_UNLOCK_READ(oid2asi_lock);
  224. }
  225. return asi;
  226. }
  227. /*
  228. * Add the syntax info pointer to the look-up-by-oid table.
  229. * The lock parameter is used by the initialization code. Normally, we want
  230. * to acquire a write lock before we modify the table, but during
  231. * initialization, we are running in single threaded mode, so we don't have
  232. * to worry about resource contention.
  233. */
  234. static void
  235. attr_syntax_add_by_oid(const char *oid, struct asyntaxinfo *a, int lock)
  236. {
  237. if (0 != attr_syntax_init()) return;
  238. if (lock)
  239. AS_LOCK_WRITE(oid2asi_lock);
  240. PL_HashTableAdd(oid2asi, oid, a);
  241. if (lock)
  242. AS_UNLOCK_WRITE(oid2asi_lock);
  243. }
  244. /*
  245. * Return the syntax info given an attribute name. The name may be the
  246. * "canonical" name, an alias, or an OID. The given name need not be
  247. * normalized since the look up is done case insensitively.
  248. *
  249. * Note: once the caller is finished using it, the structure returned must
  250. * be returned by calling to attr_syntax_return().
  251. */
  252. struct asyntaxinfo *
  253. attr_syntax_get_by_name(const char *name)
  254. {
  255. return attr_syntax_get_by_name_locking_optional(name, PR_TRUE);
  256. }
  257. /*
  258. * A version of attr_syntax_get_by_name() that allows you to bypass using
  259. * a lock around the global name hashtable.
  260. *
  261. * Note: once the caller is finished using it, the structure must be
  262. * returned by calling attr_syntax_return_locking_optional() with the
  263. * same use_lock parameter.
  264. */
  265. struct asyntaxinfo *
  266. attr_syntax_get_by_name_locking_optional(const char *name, PRBool use_lock)
  267. {
  268. struct asyntaxinfo *asi = 0;
  269. if (name2asi)
  270. {
  271. if ( use_lock ) AS_LOCK_READ(name2asi_lock);
  272. asi = (struct asyntaxinfo *)PL_HashTableLookup_const(name2asi, name);
  273. if ( NULL != asi ) {
  274. PR_AtomicIncrement( &asi->asi_refcnt );
  275. }
  276. if ( use_lock ) AS_UNLOCK_READ(name2asi_lock);
  277. }
  278. if (!asi) /* given name may be an OID */
  279. asi = attr_syntax_get_by_oid_locking_optional(name, use_lock);
  280. return asi;
  281. }
  282. /*
  283. * Give up a reference to an asi.
  284. * If the asi has been marked for delete, free it. This would be a bit
  285. * easier if we could upgrade a read lock to a write one... but NSPR does
  286. * not support that paradigm.
  287. */
  288. void
  289. attr_syntax_return( struct asyntaxinfo *asi )
  290. {
  291. attr_syntax_return_locking_optional( asi, PR_TRUE );
  292. }
  293. void
  294. attr_syntax_return_locking_optional( struct asyntaxinfo *asi, PRBool use_lock )
  295. {
  296. if ( NULL != asi ) {
  297. if ( 0 == PR_AtomicDecrement( &asi->asi_refcnt ))
  298. {
  299. PRBool delete_it;
  300. if(use_lock) AS_LOCK_READ(name2asi_lock);
  301. delete_it = asi->asi_marked_for_delete;
  302. if(use_lock) AS_UNLOCK_READ(name2asi_lock);
  303. if ( delete_it )
  304. {
  305. AS_LOCK_WRITE(name2asi_lock); /* get a write lock */
  306. if ( asi->asi_marked_for_delete ) /* one final check */
  307. {
  308. /* ref count is 0 and it's flagged for
  309. * deletion, so it's safe to free now */
  310. attr_syntax_free(asi);
  311. }
  312. AS_UNLOCK_WRITE(name2asi_lock);
  313. }
  314. }
  315. }
  316. }
  317. /*
  318. * Add the syntax info to the look-up-by-name table. The asi_name and
  319. * elements of the asi_aliasses field of the syntax info are the keys.
  320. * These need not be normalized since the look up table is case insensitive.
  321. * The lock parameter is used by the initialization code. Normally, we want
  322. * to acquire a write lock before we modify the table, but during
  323. * initialization, we are running in single threaded mode, so we don't have
  324. * to worry about resource contention.
  325. */
  326. static void
  327. attr_syntax_add_by_name(struct asyntaxinfo *a, int lock)
  328. {
  329. if (0 != attr_syntax_init()) return;
  330. if (lock)
  331. AS_LOCK_WRITE(name2asi_lock);
  332. PL_HashTableAdd(name2asi, a->asi_name, a);
  333. if ( a->asi_aliases != NULL ) {
  334. int i;
  335. for ( i = 0; a->asi_aliases[i] != NULL; ++i ) {
  336. PL_HashTableAdd(name2asi, a->asi_aliases[i], a);
  337. }
  338. }
  339. if (lock)
  340. AS_UNLOCK_WRITE(name2asi_lock);
  341. }
  342. /*
  343. * Delete the attribute syntax and all entries corresponding to aliases
  344. * and oids.
  345. */
  346. void
  347. attr_syntax_delete( struct asyntaxinfo *asi )
  348. {
  349. PR_ASSERT( asi );
  350. if (oid2asi && name2asi) {
  351. AS_LOCK_WRITE(oid2asi_lock);
  352. AS_LOCK_WRITE(name2asi_lock);
  353. attr_syntax_delete_no_lock( asi, PR_TRUE );
  354. AS_UNLOCK_WRITE(name2asi_lock);
  355. AS_UNLOCK_WRITE(oid2asi_lock);
  356. }
  357. }
  358. /*
  359. * Dispose of a node. The caller is responsible for locking. See
  360. * attr_syntax_delete() for an example.
  361. */
  362. static void
  363. attr_syntax_delete_no_lock( struct asyntaxinfo *asi,
  364. PRBool remove_from_oidtable )
  365. {
  366. int i;
  367. if (oid2asi && remove_from_oidtable ) {
  368. PL_HashTableRemove(oid2asi, asi->asi_oid);
  369. }
  370. if(name2asi) {
  371. PL_HashTableRemove(name2asi, asi->asi_name);
  372. if ( asi->asi_aliases != NULL ) {
  373. for ( i = 0; asi->asi_aliases[i] != NULL; ++i ) {
  374. PL_HashTableRemove(name2asi, asi->asi_aliases[i]);
  375. }
  376. }
  377. if ( asi->asi_refcnt > 0 ) {
  378. asi->asi_marked_for_delete = PR_TRUE;
  379. } else {
  380. /* This is ok, but the correct thing is to call delete first,
  381. * then to call return. The last return will then take care of
  382. * the free. The only way this free would happen here is if
  383. * you return the syntax before calling delete. */
  384. attr_syntax_free(asi);
  385. }
  386. }
  387. }
  388. /*
  389. * Look up the attribute type in the syntaxes and return a copy of the
  390. * normalised attribute type. If it's not there then return a normalised
  391. * copy of what the caller gave us.
  392. *
  393. * Warning: The caller must free the returned string.
  394. */
  395. char *
  396. slapi_attr_syntax_normalize( const char *s )
  397. {
  398. struct asyntaxinfo *asi = NULL;
  399. char *r;
  400. if((asi=attr_syntax_get_by_name(s)) != NULL ) {
  401. r = slapi_ch_strdup(asi->asi_name);
  402. attr_syntax_return( asi );
  403. }
  404. if ( NULL == asi ) {
  405. r = attr_syntax_normalize_no_lookup( s );
  406. }
  407. return r;
  408. }
  409. /*
  410. * attr_syntax_exists: return 1 if attr_name exists, 0 otherwise
  411. *
  412. */
  413. int
  414. attr_syntax_exists(const char *attr_name)
  415. {
  416. struct asyntaxinfo *asi;
  417. asi = attr_syntax_get_by_name(attr_name);
  418. attr_syntax_return( asi );
  419. if ( asi != NULL )
  420. {
  421. return 1;
  422. }
  423. return 0;
  424. }
  425. /* check syntax */
  426. static void *
  427. attr_syntax_get_plugin_by_name_with_default( const char *type )
  428. {
  429. struct asyntaxinfo *asi;
  430. void *plugin = NULL;
  431. /*
  432. * first we look for this attribute type explictly
  433. */
  434. if ( (asi = attr_syntax_get_by_name(type)) == NULL ) {
  435. /*
  436. * no syntax for this type... return Octet String
  437. * syntax. we accomplish this by looking up a well known
  438. * attribute type that has that syntax.
  439. */
  440. asi = attr_syntax_get_by_name(ATTR_WITH_OCTETSTRING_SYNTAX);
  441. }
  442. if ( NULL != asi ) {
  443. plugin = asi->asi_plugin;
  444. attr_syntax_return( asi );
  445. }
  446. return( plugin );
  447. }
  448. static struct asyntaxinfo *
  449. attr_syntax_dup( struct asyntaxinfo *a )
  450. {
  451. struct asyntaxinfo *newas = attr_syntax_new();
  452. newas->asi_aliases = cool_charray_dup( a->asi_aliases );
  453. newas->asi_name = slapi_ch_strdup( a->asi_name );
  454. newas->asi_desc = slapi_ch_strdup( a->asi_desc );
  455. newas->asi_superior = slapi_ch_strdup( a->asi_superior );
  456. newas->asi_mr_equality = slapi_ch_strdup( a->asi_mr_equality );
  457. newas->asi_mr_ordering = slapi_ch_strdup( a->asi_mr_ordering );
  458. newas->asi_mr_substring = slapi_ch_strdup( a->asi_mr_substring );
  459. newas->asi_origin = cool_charray_dup( a->asi_origin );
  460. newas->asi_plugin = a->asi_plugin;
  461. newas->asi_flags = a->asi_flags;
  462. newas->asi_oid = slapi_ch_strdup( a->asi_oid);
  463. newas->asi_syntaxlength = a->asi_syntaxlength;
  464. newas->asi_mr_eq_plugin = a->asi_mr_eq_plugin;
  465. newas->asi_mr_ord_plugin = a->asi_mr_ord_plugin;
  466. newas->asi_mr_sub_plugin = a->asi_mr_sub_plugin;
  467. return( newas );
  468. }
  469. /*
  470. * Add a new attribute type to the schema.
  471. *
  472. * Returns an LDAP error code (LDAP_SUCCESS if all goes well).
  473. */
  474. int
  475. attr_syntax_add( struct asyntaxinfo *asip )
  476. {
  477. int i, rc = LDAP_SUCCESS;
  478. int nolock = asip->asi_flags & SLAPI_ATTR_FLAG_NOLOCKING;
  479. struct asyntaxinfo *oldas_from_oid = NULL, *oldas_from_name = NULL;
  480. /* attr names may have subtypes in them, and we may not want this
  481. if strip_subtypes is true, the ; and anything after it in the
  482. attr name or alias will be stripped */
  483. /*int strip_subtypes = 1;*/
  484. /* make sure the oid is unique */
  485. if ( NULL != ( oldas_from_oid = attr_syntax_get_by_oid_locking_optional(
  486. asip->asi_oid, !nolock))) {
  487. if ( 0 == (asip->asi_flags & SLAPI_ATTR_FLAG_OVERRIDE)) {
  488. /* failure - OID is in use; no override flag */
  489. rc = LDAP_TYPE_OR_VALUE_EXISTS;
  490. goto cleanup_and_return;
  491. }
  492. }
  493. /* make sure the primary name is unique OR, if override is allowed, that
  494. * the primary name and OID point to the same schema definition.
  495. */
  496. if ( NULL != ( oldas_from_name = attr_syntax_get_by_name_locking_optional(
  497. asip->asi_name, !nolock))) {
  498. if ( 0 == (asip->asi_flags & SLAPI_ATTR_FLAG_OVERRIDE)
  499. || ( oldas_from_oid != oldas_from_name )) {
  500. /* failure; no override flag OR OID and name don't match */
  501. rc = LDAP_TYPE_OR_VALUE_EXISTS;
  502. goto cleanup_and_return;
  503. }
  504. /* Flag for deletion. We are going to override this attr */
  505. attr_syntax_delete(oldas_from_name);
  506. } else if ( NULL != oldas_from_oid ) {
  507. /* failure - OID is in use but name does not exist */
  508. rc = LDAP_TYPE_OR_VALUE_EXISTS;
  509. goto cleanup_and_return;
  510. }
  511. if ( NULL != asip->asi_aliases ) {
  512. /* make sure the aliases are unique */
  513. for (i = 0; asip->asi_aliases[i] != NULL; ++i) {
  514. struct asyntaxinfo *tmpasi;
  515. if ( NULL != ( tmpasi =
  516. attr_syntax_get_by_name_locking_optional(
  517. asip->asi_aliases[i], !nolock))) {
  518. if (asip->asi_flags & SLAPI_ATTR_FLAG_OVERRIDE) {
  519. /* Flag for tmpasi for deletion. It will be free'd
  520. * when attr_syntax_return is called. */
  521. attr_syntax_delete(tmpasi);
  522. } else {
  523. /* failure - one of the aliases is already in use */
  524. rc = LDAP_TYPE_OR_VALUE_EXISTS;
  525. }
  526. attr_syntax_return_locking_optional( tmpasi, !nolock );
  527. if ( LDAP_SUCCESS != rc ) {
  528. goto cleanup_and_return;
  529. }
  530. }
  531. }
  532. }
  533. /* the no lock flag is not worth keeping around */
  534. asip->asi_flags &= ~SLAPI_ATTR_FLAG_NOLOCKING;
  535. /* ditto for the override one */
  536. asip->asi_flags &= ~SLAPI_ATTR_FLAG_OVERRIDE;
  537. attr_syntax_add_by_oid( asip->asi_oid, asip, !nolock);
  538. attr_syntax_add_by_name( asip, !nolock);
  539. cleanup_and_return:
  540. attr_syntax_return_locking_optional( oldas_from_oid, !nolock );
  541. attr_syntax_return_locking_optional( oldas_from_name, !nolock );
  542. return rc;
  543. }
  544. /*
  545. * Returns an LDAP result code.
  546. */
  547. int
  548. attr_syntax_create(
  549. const char *attr_oid,
  550. char *const *attr_names,
  551. int num_names,
  552. const char *attr_desc,
  553. const char *attr_superior,
  554. const char *mr_equality,
  555. const char *mr_ordering,
  556. const char *mr_substring,
  557. char *const *attr_origins,
  558. const char *attr_syntax,
  559. int syntaxlength,
  560. unsigned long flags,
  561. struct asyntaxinfo **asip
  562. )
  563. {
  564. char *s;
  565. struct asyntaxinfo a;
  566. int rc = LDAP_SUCCESS;
  567. /* XXXmcs: had to cast away const in many places below */
  568. memset(&a, 0, sizeof(a));
  569. *asip = NULL;
  570. a.asi_name = slapi_ch_strdup(attr_names[0]);
  571. if ( NULL != attr_names[1] ) {
  572. a.asi_aliases = (char **)&attr_names[1]; /* all but the zero'th element */
  573. }
  574. a.asi_desc = (char*)attr_desc;
  575. a.asi_oid = (char*)attr_oid;
  576. a.asi_superior = (char*)attr_superior;
  577. a.asi_mr_equality = (char*)mr_equality;
  578. a.asi_mr_ordering = (char*)mr_ordering;
  579. a.asi_mr_substring = (char*)mr_substring;
  580. a.asi_origin = (char **)attr_origins;
  581. a.asi_plugin = plugin_syntax_find( attr_syntax );
  582. a.asi_syntaxlength = syntaxlength;
  583. /* ideally, we would report an error and fail to start if there was some problem
  584. with the matching rule - but since this functionality is new, and we might
  585. cause havoc if lots of servers failed to start because of bogus schema, we
  586. just report an error here - at some point in the future, we should actually
  587. report an error and exit, or allow the user to control the behavior - for
  588. now, just log an error, and address each case
  589. */
  590. if (mr_equality && !slapi_matchingrule_is_compat(mr_equality, attr_syntax)) {
  591. slapi_log_error(SLAPI_LOG_FATAL, "attr_syntax_create",
  592. "Error: the EQUALITY matching rule [%s] is not compatible "
  593. "with the syntax [%s] for the attribute [%s]\n",
  594. mr_equality, attr_syntax, attr_names[0]);
  595. /*
  596. rc = LDAP_INAPPROPRIATE_MATCHING;
  597. goto done;
  598. */
  599. }
  600. a.asi_mr_eq_plugin = plugin_mr_find( mr_equality );
  601. if (mr_ordering && !slapi_matchingrule_is_compat(mr_ordering, attr_syntax)) {
  602. slapi_log_error(SLAPI_LOG_FATAL, "attr_syntax_create",
  603. "Error: the ORDERING matching rule [%s] is not compatible "
  604. "with the syntax [%s] for the attribute [%s]\n",
  605. mr_ordering, attr_syntax, attr_names[0]);
  606. /*
  607. rc = LDAP_INAPPROPRIATE_MATCHING;
  608. goto done;
  609. */
  610. }
  611. a.asi_mr_ord_plugin = plugin_mr_find( mr_ordering );
  612. if (mr_substring && !slapi_matchingrule_is_compat(mr_substring, attr_syntax)) {
  613. slapi_log_error(SLAPI_LOG_FATAL, "attr_syntax_create",
  614. "Error: the SUBSTR matching rule [%s] is not compatible "
  615. "with the syntax [%s] for the attribute [%s]\n",
  616. mr_substring, attr_syntax, attr_names[0]);
  617. /*
  618. rc = LDAP_INAPPROPRIATE_MATCHING;
  619. goto done;
  620. */
  621. }
  622. a.asi_mr_sub_plugin = plugin_mr_find( mr_substring );
  623. a.asi_flags = flags;
  624. /*
  625. * If the 'return exact case' option is on (the default), we store the
  626. * first name (the canonical one) unchanged so that attribute names are
  627. * returned exactly as they appear in the schema configuration files.
  628. * But if 'return exact case' has been turned off, we convert the name
  629. * to lowercase. In Netscape Directory Server 4.x and earlier versions,
  630. * the default was to convert to lowercase.
  631. */
  632. if (!config_get_return_exact_case()) {
  633. for (s = a.asi_name; *s; ++s) {
  634. *s = TOLOWER(*s);
  635. }
  636. }
  637. *asip = attr_syntax_dup(&a);
  638. done:
  639. slapi_ch_free((void **)&a.asi_name);
  640. return rc;
  641. }
  642. /*
  643. * slapi_attr_type2plugin - return the plugin handling the attribute type
  644. * if type is unknown, we return the caseIgnoreString plugin used by the
  645. * objectClass attribute type.
  646. */
  647. int
  648. slapi_attr_type2plugin( const char *type, void **pi )
  649. {
  650. char buf[SLAPD_TYPICAL_ATTRIBUTE_NAME_MAX_LENGTH];
  651. char *tmp, *basetype;
  652. int rc;
  653. basetype = buf;
  654. if ( (tmp = slapi_attr_basetype( type, buf, sizeof(buf) )) != NULL ) {
  655. basetype = tmp;
  656. }
  657. rc = -1;
  658. *pi = attr_syntax_get_plugin_by_name_with_default( basetype );
  659. if ( NULL != *pi ) {
  660. rc = 0;
  661. }
  662. slapi_ch_free_string(&tmp);
  663. return( rc );
  664. }
  665. /* deprecated -- not MT safe (pointer into asi is returned!) */
  666. int
  667. slapi_attr_get_oid( const Slapi_Attr *a, char **oid )
  668. {
  669. struct asyntaxinfo *asi = attr_syntax_get_by_name(a->a_type);
  670. if (asi) {
  671. *oid = asi->asi_oid;
  672. attr_syntax_return(asi);
  673. return( 0 );
  674. } else {
  675. *oid = NULL;
  676. return( -1 );
  677. }
  678. }
  679. /* The caller must dispose of oid by calling slapi_ch_free(). */
  680. int
  681. slapi_attr_get_oid_copy( const Slapi_Attr *a, char **oidp )
  682. {
  683. struct asyntaxinfo *asi = attr_syntax_get_by_name(a->a_type);
  684. if (asi) {
  685. *oidp = slapi_ch_strdup( asi->asi_oid );
  686. attr_syntax_return(asi);
  687. return( 0 );
  688. } else {
  689. *oidp = NULL;
  690. return( -1 );
  691. }
  692. }
  693. /* Returns the oid of the syntax of the Slapi_Attr that's passed in.
  694. * The caller must dispose of oid by calling slapi_ch_free_string(). */
  695. int
  696. slapi_attr_get_syntax_oid_copy( const Slapi_Attr *a, char **oidp )
  697. {
  698. const char *oid;
  699. if (a && ((oid = attr_get_syntax_oid(a)))) {
  700. *oidp = slapi_ch_strdup(oid);
  701. return( 0 );
  702. } else {
  703. *oidp = NULL;
  704. return( -1 );
  705. }
  706. }
  707. #ifdef ATTR_LDAP_DEBUG
  708. PRIntn
  709. attr_syntax_printnode(PLHashEntry *he, PRIntn i, void *arg)
  710. {
  711. char *alias = (char *)he->key;
  712. struct asyntaxinfo *a = (struct asyntaxinfo *)he->value;
  713. printf( " name: %s\n", a->asi_name );
  714. printf( "\t flags : 0x%x\n", a->asi_flags );
  715. printf( "\t alias : %s\n", alias );
  716. printf( "\t desc : %s\n", a->asi_desc );
  717. printf( "\t oid : %s\n", a->asi_oid );
  718. printf( "\t superior : %s\n", a->asi_superior );
  719. printf( "\t mr_equality : %s\n", a->asi_mr_equality );
  720. printf( "\t mr_ordering : %s\n", a->asi_mr_ordering );
  721. printf( "\t mr_substring: %s\n", a->asi_mr_substring );
  722. if ( NULL != a->asi_origin ) {
  723. for ( i = 0; NULL != a->asi_origin[i]; ++i ) {
  724. printf( "\t origin : %s\n", a->asi_origin[i] );
  725. }
  726. }
  727. printf( "\tplugin: %p\n", a->asi_plugin );
  728. printf( "--------------\n" );
  729. return HT_ENUMERATE_NEXT;
  730. }
  731. void
  732. attr_syntax_print()
  733. {
  734. printf( "*** attr_syntax_print ***\n" );
  735. PL_HashTableEnumerateEntries(name2asi, attr_syntax_printnode, 0);
  736. }
  737. #endif
  738. /* lowercase the attr name and chop trailing spaces */
  739. /* note that s may contain options also, e.g., userCertificate;binary */
  740. char *
  741. attr_syntax_normalize_no_lookup( const char *s )
  742. {
  743. char *save, *tmps;
  744. tmps = slapi_ch_strdup(s);
  745. for ( save = tmps; (*tmps != '\0') && (*tmps != ' '); tmps++ )
  746. {
  747. *tmps = TOLOWER( *tmps );
  748. }
  749. *tmps = '\0';
  750. return save;
  751. }
  752. struct enum_arg_wrapper {
  753. AttrEnumFunc aef;
  754. void *arg;
  755. };
  756. PRIntn
  757. attr_syntax_enumerate_internal(PLHashEntry *he, PRIntn i, void *arg)
  758. {
  759. struct enum_arg_wrapper *eaw = (struct enum_arg_wrapper *)arg;
  760. int rc;
  761. rc = (eaw->aef)((struct asyntaxinfo *)he->value, eaw->arg);
  762. if ( ATTR_SYNTAX_ENUM_STOP == rc ) {
  763. rc = HT_ENUMERATE_STOP;
  764. } else if ( ATTR_SYNTAX_ENUM_REMOVE == rc ) {
  765. rc = HT_ENUMERATE_REMOVE;
  766. } else {
  767. rc = HT_ENUMERATE_NEXT;
  768. }
  769. return rc;
  770. }
  771. void
  772. attr_syntax_enumerate_attrs(AttrEnumFunc aef, void *arg, PRBool writelock )
  773. {
  774. struct enum_arg_wrapper eaw;
  775. eaw.aef = aef;
  776. eaw.arg = arg;
  777. if (!oid2asi)
  778. return;
  779. if ( writelock ) {
  780. AS_LOCK_WRITE(oid2asi_lock);
  781. AS_LOCK_WRITE(name2asi_lock);
  782. } else {
  783. AS_LOCK_READ(oid2asi_lock);
  784. AS_LOCK_READ(name2asi_lock);
  785. }
  786. PL_HashTableEnumerateEntries(oid2asi, attr_syntax_enumerate_internal, &eaw);
  787. if ( writelock ) {
  788. AS_UNLOCK_WRITE(oid2asi_lock);
  789. AS_UNLOCK_WRITE(name2asi_lock);
  790. } else {
  791. AS_UNLOCK_READ(oid2asi_lock);
  792. AS_UNLOCK_READ(name2asi_lock);
  793. }
  794. }
  795. struct attr_syntax_enum_flaginfo {
  796. unsigned long asef_flag;
  797. };
  798. static int
  799. attr_syntax_clear_flag_callback(struct asyntaxinfo *asip, void *arg)
  800. {
  801. struct attr_syntax_enum_flaginfo *fi;
  802. PR_ASSERT( asip != NULL );
  803. fi = (struct attr_syntax_enum_flaginfo *)arg;
  804. PR_ASSERT( fi != NULL );
  805. asip->asi_flags &= ~(fi->asef_flag);
  806. return ATTR_SYNTAX_ENUM_NEXT;
  807. }
  808. static int
  809. attr_syntax_delete_if_not_flagged(struct asyntaxinfo *asip, void *arg)
  810. {
  811. struct attr_syntax_enum_flaginfo *fi;
  812. PR_ASSERT( asip != NULL );
  813. fi = (struct attr_syntax_enum_flaginfo *)arg;
  814. PR_ASSERT( fi != NULL );
  815. if ( 0 == ( asip->asi_flags & fi->asef_flag )) {
  816. attr_syntax_delete_no_lock( asip, PR_FALSE );
  817. return ATTR_SYNTAX_ENUM_REMOVE;
  818. } else {
  819. return ATTR_SYNTAX_ENUM_NEXT;
  820. }
  821. }
  822. static int
  823. attr_syntax_force_to_delete(struct asyntaxinfo *asip, void *arg)
  824. {
  825. struct attr_syntax_enum_flaginfo *fi;
  826. PR_ASSERT( asip != NULL );
  827. fi = (struct attr_syntax_enum_flaginfo *)arg;
  828. PR_ASSERT( fi != NULL );
  829. attr_syntax_delete_no_lock( asip, PR_FALSE );
  830. return ATTR_SYNTAX_ENUM_REMOVE;
  831. }
  832. /*
  833. * Clear 'flag' within all attribute definitions.
  834. */
  835. void
  836. attr_syntax_all_clear_flag( unsigned long flag )
  837. {
  838. struct attr_syntax_enum_flaginfo fi;
  839. memset( &fi, 0, sizeof(fi));
  840. fi.asef_flag = flag;
  841. attr_syntax_enumerate_attrs( attr_syntax_clear_flag_callback,
  842. (void *)&fi, PR_TRUE );
  843. }
  844. /*
  845. * Delete all attribute definitions that do not contain any bits of 'flag'
  846. * in their flags.
  847. */
  848. void
  849. attr_syntax_delete_all_not_flagged( unsigned long flag )
  850. {
  851. struct attr_syntax_enum_flaginfo fi;
  852. memset( &fi, 0, sizeof(fi));
  853. fi.asef_flag = flag;
  854. attr_syntax_enumerate_attrs( attr_syntax_delete_if_not_flagged,
  855. (void *)&fi, PR_TRUE );
  856. }
  857. /*
  858. * Delete all attribute definitions
  859. */
  860. void
  861. attr_syntax_delete_all()
  862. {
  863. struct attr_syntax_enum_flaginfo fi;
  864. memset( &fi, 0, sizeof(fi));
  865. attr_syntax_enumerate_attrs( attr_syntax_force_to_delete,
  866. (void *)&fi, PR_TRUE );
  867. }
  868. static int
  869. attr_syntax_init(void)
  870. {
  871. if (!oid2asi)
  872. {
  873. oid2asi = PL_NewHashTable(2047, hashNocaseString,
  874. hashNocaseCompare,
  875. PL_CompareValues, 0, 0);
  876. if ( NULL == ( oid2asi_lock = PR_NewRWLock( PR_RWLOCK_RANK_NONE,
  877. "attrsyntax oid rwlock" ))) {
  878. if(oid2asi) PL_HashTableDestroy(oid2asi);
  879. oid2asi = NULL;
  880. slapi_log_error( SLAPI_LOG_FATAL, "attr_syntax_init",
  881. "PR_NewRWLock() for oid2asi lock failed\n" );
  882. return 1;
  883. }
  884. }
  885. if (!name2asi)
  886. {
  887. name2asi = PL_NewHashTable(2047, hashNocaseString,
  888. hashNocaseCompare,
  889. PL_CompareValues, 0, 0);
  890. if ( NULL == ( name2asi_lock = PR_NewRWLock( PR_RWLOCK_RANK_NONE,
  891. "attrsyntax name2asi rwlock"))) {
  892. if(name2asi) PL_HashTableDestroy(name2asi);
  893. name2asi = NULL;
  894. slapi_log_error( SLAPI_LOG_FATAL, "attr_syntax_init",
  895. "PR_NewRWLock() for oid2asi lock failed\n" );
  896. return 1;
  897. }
  898. }
  899. return 0;
  900. }