attrsyntax.c 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078
  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 = NULL;
  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. slapi_ch_free_string( &r );
  406. r = attr_syntax_normalize_no_lookup( s );
  407. }
  408. return r;
  409. }
  410. /*
  411. * attr_syntax_exists: return 1 if attr_name exists, 0 otherwise
  412. *
  413. */
  414. int
  415. attr_syntax_exists(const char *attr_name)
  416. {
  417. struct asyntaxinfo *asi;
  418. asi = attr_syntax_get_by_name(attr_name);
  419. attr_syntax_return( asi );
  420. if ( asi != NULL )
  421. {
  422. return 1;
  423. }
  424. return 0;
  425. }
  426. /* check syntax */
  427. static void *
  428. attr_syntax_get_plugin_by_name_with_default( const char *type )
  429. {
  430. struct asyntaxinfo *asi;
  431. void *plugin = NULL;
  432. /*
  433. * first we look for this attribute type explictly
  434. */
  435. if ( (asi = attr_syntax_get_by_name(type)) == NULL ) {
  436. /*
  437. * no syntax for this type... return Octet String
  438. * syntax. we accomplish this by looking up a well known
  439. * attribute type that has that syntax.
  440. */
  441. asi = attr_syntax_get_by_name(ATTR_WITH_OCTETSTRING_SYNTAX);
  442. }
  443. if ( NULL != asi ) {
  444. plugin = asi->asi_plugin;
  445. attr_syntax_return( asi );
  446. }
  447. return( plugin );
  448. }
  449. static struct asyntaxinfo *
  450. attr_syntax_dup( struct asyntaxinfo *a )
  451. {
  452. struct asyntaxinfo *newas = attr_syntax_new();
  453. newas->asi_aliases = cool_charray_dup( a->asi_aliases );
  454. newas->asi_name = slapi_ch_strdup( a->asi_name );
  455. newas->asi_desc = slapi_ch_strdup( a->asi_desc );
  456. newas->asi_superior = slapi_ch_strdup( a->asi_superior );
  457. newas->asi_mr_equality = slapi_ch_strdup( a->asi_mr_equality );
  458. newas->asi_mr_ordering = slapi_ch_strdup( a->asi_mr_ordering );
  459. newas->asi_mr_substring = slapi_ch_strdup( a->asi_mr_substring );
  460. newas->asi_origin = cool_charray_dup( a->asi_origin );
  461. newas->asi_plugin = a->asi_plugin;
  462. newas->asi_flags = a->asi_flags;
  463. newas->asi_oid = slapi_ch_strdup( a->asi_oid);
  464. newas->asi_syntaxlength = a->asi_syntaxlength;
  465. newas->asi_mr_eq_plugin = a->asi_mr_eq_plugin;
  466. newas->asi_mr_ord_plugin = a->asi_mr_ord_plugin;
  467. newas->asi_mr_sub_plugin = a->asi_mr_sub_plugin;
  468. return( newas );
  469. }
  470. /*
  471. * Add a new attribute type to the schema.
  472. *
  473. * Returns an LDAP error code (LDAP_SUCCESS if all goes well).
  474. */
  475. int
  476. attr_syntax_add( struct asyntaxinfo *asip )
  477. {
  478. int i, rc = LDAP_SUCCESS;
  479. int nolock = asip->asi_flags & SLAPI_ATTR_FLAG_NOLOCKING;
  480. struct asyntaxinfo *oldas_from_oid = NULL, *oldas_from_name = NULL;
  481. /* attr names may have subtypes in them, and we may not want this
  482. if strip_subtypes is true, the ; and anything after it in the
  483. attr name or alias will be stripped */
  484. /*int strip_subtypes = 1;*/
  485. /* make sure the oid is unique */
  486. if ( NULL != ( oldas_from_oid = attr_syntax_get_by_oid_locking_optional(
  487. asip->asi_oid, !nolock))) {
  488. if ( 0 == (asip->asi_flags & SLAPI_ATTR_FLAG_OVERRIDE)) {
  489. /* failure - OID is in use; no override flag */
  490. rc = LDAP_TYPE_OR_VALUE_EXISTS;
  491. goto cleanup_and_return;
  492. }
  493. }
  494. /* make sure the primary name is unique OR, if override is allowed, that
  495. * the primary name and OID point to the same schema definition.
  496. */
  497. if ( NULL != ( oldas_from_name = attr_syntax_get_by_name_locking_optional(
  498. asip->asi_name, !nolock))) {
  499. if ( 0 == (asip->asi_flags & SLAPI_ATTR_FLAG_OVERRIDE)
  500. || ( oldas_from_oid != oldas_from_name )) {
  501. /* failure; no override flag OR OID and name don't match */
  502. rc = LDAP_TYPE_OR_VALUE_EXISTS;
  503. goto cleanup_and_return;
  504. }
  505. /* Flag for deletion. We are going to override this attr */
  506. attr_syntax_delete(oldas_from_name);
  507. } else if ( NULL != oldas_from_oid ) {
  508. /* failure - OID is in use but name does not exist */
  509. rc = LDAP_TYPE_OR_VALUE_EXISTS;
  510. goto cleanup_and_return;
  511. }
  512. if ( NULL != asip->asi_aliases ) {
  513. /* make sure the aliases are unique */
  514. for (i = 0; asip->asi_aliases[i] != NULL; ++i) {
  515. struct asyntaxinfo *tmpasi;
  516. if ( NULL != ( tmpasi =
  517. attr_syntax_get_by_name_locking_optional(
  518. asip->asi_aliases[i], !nolock))) {
  519. if (asip->asi_flags & SLAPI_ATTR_FLAG_OVERRIDE) {
  520. /* Flag for tmpasi for deletion. It will be free'd
  521. * when attr_syntax_return is called. */
  522. attr_syntax_delete(tmpasi);
  523. } else {
  524. /* failure - one of the aliases is already in use */
  525. rc = LDAP_TYPE_OR_VALUE_EXISTS;
  526. }
  527. attr_syntax_return_locking_optional( tmpasi, !nolock );
  528. if ( LDAP_SUCCESS != rc ) {
  529. goto cleanup_and_return;
  530. }
  531. }
  532. }
  533. }
  534. /* the no lock flag is not worth keeping around */
  535. asip->asi_flags &= ~SLAPI_ATTR_FLAG_NOLOCKING;
  536. /* ditto for the override one */
  537. asip->asi_flags &= ~SLAPI_ATTR_FLAG_OVERRIDE;
  538. attr_syntax_add_by_oid( asip->asi_oid, asip, !nolock);
  539. attr_syntax_add_by_name( asip, !nolock);
  540. cleanup_and_return:
  541. attr_syntax_return_locking_optional( oldas_from_oid, !nolock );
  542. attr_syntax_return_locking_optional( oldas_from_name, !nolock );
  543. return rc;
  544. }
  545. /*
  546. * Returns an LDAP result code.
  547. */
  548. int
  549. attr_syntax_create(
  550. const char *attr_oid,
  551. char *const *attr_names,
  552. int num_names,
  553. const char *attr_desc,
  554. const char *attr_superior,
  555. const char *mr_equality,
  556. const char *mr_ordering,
  557. const char *mr_substring,
  558. char *const *attr_origins,
  559. const char *attr_syntax,
  560. int syntaxlength,
  561. unsigned long flags,
  562. struct asyntaxinfo **asip
  563. )
  564. {
  565. char *s;
  566. struct asyntaxinfo a;
  567. int rc = LDAP_SUCCESS;
  568. /* XXXmcs: had to cast away const in many places below */
  569. memset(&a, 0, sizeof(a));
  570. *asip = NULL;
  571. a.asi_name = slapi_ch_strdup(attr_names[0]);
  572. if ( NULL != attr_names[1] ) {
  573. a.asi_aliases = (char **)&attr_names[1]; /* all but the zero'th element */
  574. }
  575. a.asi_desc = (char*)attr_desc;
  576. a.asi_oid = (char*)attr_oid;
  577. a.asi_superior = (char*)attr_superior;
  578. a.asi_mr_equality = (char*)mr_equality;
  579. a.asi_mr_ordering = (char*)mr_ordering;
  580. a.asi_mr_substring = (char*)mr_substring;
  581. a.asi_origin = (char **)attr_origins;
  582. a.asi_plugin = plugin_syntax_find( attr_syntax );
  583. a.asi_syntaxlength = syntaxlength;
  584. /* ideally, we would report an error and fail to start if there was some problem
  585. with the matching rule - but since this functionality is new, and we might
  586. cause havoc if lots of servers failed to start because of bogus schema, we
  587. just report an error here - at some point in the future, we should actually
  588. report an error and exit, or allow the user to control the behavior - for
  589. now, just log an error, and address each case
  590. */
  591. if (mr_equality && !slapi_matchingrule_is_compat(mr_equality, attr_syntax)) {
  592. slapi_log_error(SLAPI_LOG_FATAL, "attr_syntax_create",
  593. "Error: the EQUALITY matching rule [%s] is not compatible "
  594. "with the syntax [%s] for the attribute [%s]\n",
  595. mr_equality, attr_syntax, attr_names[0]);
  596. #ifdef ENFORCE_MR_SYNTAX_COMPAT
  597. rc = LDAP_INAPPROPRIATE_MATCHING;
  598. goto done;
  599. #endif /* ENFORCE_MR_SYNTAX_COMPAT */
  600. }
  601. a.asi_mr_eq_plugin = plugin_mr_find( mr_equality );
  602. if (mr_ordering && !slapi_matchingrule_is_compat(mr_ordering, attr_syntax)) {
  603. slapi_log_error(SLAPI_LOG_FATAL, "attr_syntax_create",
  604. "Error: the ORDERING matching rule [%s] is not compatible "
  605. "with the syntax [%s] for the attribute [%s]\n",
  606. mr_ordering, attr_syntax, attr_names[0]);
  607. #ifdef ENFORCE_MR_SYNTAX_COMPAT
  608. rc = LDAP_INAPPROPRIATE_MATCHING;
  609. goto done;
  610. #endif /* ENFORCE_MR_SYNTAX_COMPAT */
  611. }
  612. a.asi_mr_ord_plugin = plugin_mr_find( mr_ordering );
  613. if (mr_substring && !slapi_matchingrule_is_compat(mr_substring, attr_syntax)) {
  614. slapi_log_error(SLAPI_LOG_FATAL, "attr_syntax_create",
  615. "Error: the SUBSTR matching rule [%s] is not compatible "
  616. "with the syntax [%s] for the attribute [%s]\n",
  617. mr_substring, attr_syntax, attr_names[0]);
  618. #ifdef ENFORCE_MR_SYNTAX_COMPAT
  619. rc = LDAP_INAPPROPRIATE_MATCHING;
  620. goto done;
  621. #endif /* ENFORCE_MR_SYNTAX_COMPAT */
  622. }
  623. a.asi_mr_sub_plugin = plugin_mr_find( mr_substring );
  624. a.asi_flags = flags;
  625. /*
  626. * If the 'return exact case' option is on (the default), we store the
  627. * first name (the canonical one) unchanged so that attribute names are
  628. * returned exactly as they appear in the schema configuration files.
  629. * But if 'return exact case' has been turned off, we convert the name
  630. * to lowercase. In Netscape Directory Server 4.x and earlier versions,
  631. * the default was to convert to lowercase.
  632. */
  633. if (!config_get_return_exact_case()) {
  634. for (s = a.asi_name; *s; ++s) {
  635. *s = TOLOWER(*s);
  636. }
  637. }
  638. *asip = attr_syntax_dup(&a);
  639. #ifdef ENFORCE_MR_SYNTAX_COMPAT
  640. done:
  641. #endif /* ENFORCE_MR_SYNTAX_COMPAT */
  642. slapi_ch_free((void **)&a.asi_name);
  643. return rc;
  644. }
  645. /*
  646. * slapi_attr_type2plugin - return the plugin handling the attribute type
  647. * if type is unknown, we return the caseIgnoreString plugin used by the
  648. * objectClass attribute type.
  649. */
  650. int
  651. slapi_attr_type2plugin( const char *type, void **pi )
  652. {
  653. char buf[SLAPD_TYPICAL_ATTRIBUTE_NAME_MAX_LENGTH];
  654. char *tmp, *basetype;
  655. int rc;
  656. basetype = buf;
  657. if ( (tmp = slapi_attr_basetype( type, buf, sizeof(buf) )) != NULL ) {
  658. basetype = tmp;
  659. }
  660. rc = -1;
  661. *pi = attr_syntax_get_plugin_by_name_with_default( basetype );
  662. if ( NULL != *pi ) {
  663. rc = 0;
  664. }
  665. slapi_ch_free_string(&tmp);
  666. return( rc );
  667. }
  668. /* deprecated -- not MT safe (pointer into asi is returned!) */
  669. int
  670. slapi_attr_get_oid( const Slapi_Attr *a, char **oid )
  671. {
  672. struct asyntaxinfo *asi = attr_syntax_get_by_name(a->a_type);
  673. if (asi) {
  674. *oid = asi->asi_oid;
  675. attr_syntax_return(asi);
  676. return( 0 );
  677. } else {
  678. *oid = NULL;
  679. return( -1 );
  680. }
  681. }
  682. /* The caller must dispose of oid by calling slapi_ch_free(). */
  683. int
  684. slapi_attr_get_oid_copy( const Slapi_Attr *a, char **oidp )
  685. {
  686. struct asyntaxinfo *asi = attr_syntax_get_by_name(a->a_type);
  687. if (asi) {
  688. *oidp = slapi_ch_strdup( asi->asi_oid );
  689. attr_syntax_return(asi);
  690. return( 0 );
  691. } else {
  692. *oidp = NULL;
  693. return( -1 );
  694. }
  695. }
  696. /* Returns the oid of the syntax of the Slapi_Attr that's passed in.
  697. * The caller must dispose of oid by calling slapi_ch_free_string(). */
  698. int
  699. slapi_attr_get_syntax_oid_copy( const Slapi_Attr *a, char **oidp )
  700. {
  701. const char *oid;
  702. if (a && ((oid = attr_get_syntax_oid(a)))) {
  703. *oidp = slapi_ch_strdup(oid);
  704. return( 0 );
  705. } else {
  706. *oidp = NULL;
  707. return( -1 );
  708. }
  709. }
  710. int
  711. slapi_attr_is_dn_syntax_attr(Slapi_Attr *attr)
  712. {
  713. const char *syntaxoid = NULL;
  714. int dn_syntax = 0; /* not DN, by default */
  715. if (attr && attr->a_plugin) { /* If not set, there is no way to get the info */
  716. if (syntaxoid = attr_get_syntax_oid(attr)) {
  717. dn_syntax = ((0 == strcmp(syntaxoid, NAMEANDOPTIONALUID_SYNTAX_OID))
  718. || (0 == strcmp(syntaxoid, DN_SYNTAX_OID)));
  719. }
  720. }
  721. return dn_syntax;
  722. }
  723. #ifdef ATTR_LDAP_DEBUG
  724. PRIntn
  725. attr_syntax_printnode(PLHashEntry *he, PRIntn i, void *arg)
  726. {
  727. char *alias = (char *)he->key;
  728. struct asyntaxinfo *a = (struct asyntaxinfo *)he->value;
  729. printf( " name: %s\n", a->asi_name );
  730. printf( "\t flags : 0x%x\n", a->asi_flags );
  731. printf( "\t alias : %s\n", alias );
  732. printf( "\t desc : %s\n", a->asi_desc );
  733. printf( "\t oid : %s\n", a->asi_oid );
  734. printf( "\t superior : %s\n", a->asi_superior );
  735. printf( "\t mr_equality : %s\n", a->asi_mr_equality );
  736. printf( "\t mr_ordering : %s\n", a->asi_mr_ordering );
  737. printf( "\t mr_substring: %s\n", a->asi_mr_substring );
  738. if ( NULL != a->asi_origin ) {
  739. for ( i = 0; NULL != a->asi_origin[i]; ++i ) {
  740. printf( "\t origin : %s\n", a->asi_origin[i] );
  741. }
  742. }
  743. printf( "\tplugin: %p\n", a->asi_plugin );
  744. printf( "--------------\n" );
  745. return HT_ENUMERATE_NEXT;
  746. }
  747. void
  748. attr_syntax_print()
  749. {
  750. printf( "*** attr_syntax_print ***\n" );
  751. PL_HashTableEnumerateEntries(name2asi, attr_syntax_printnode, 0);
  752. }
  753. #endif
  754. /* lowercase the attr name and chop trailing spaces */
  755. /* note that s may contain options also, e.g., userCertificate;binary */
  756. char *
  757. attr_syntax_normalize_no_lookup( const char *s )
  758. {
  759. char *save, *tmps;
  760. tmps = slapi_ch_strdup(s);
  761. for ( save = tmps; (*tmps != '\0') && (*tmps != ' '); tmps++ )
  762. {
  763. *tmps = TOLOWER( *tmps );
  764. }
  765. *tmps = '\0';
  766. return save;
  767. }
  768. struct enum_arg_wrapper {
  769. AttrEnumFunc aef;
  770. void *arg;
  771. };
  772. PRIntn
  773. attr_syntax_enumerate_internal(PLHashEntry *he, PRIntn i, void *arg)
  774. {
  775. struct enum_arg_wrapper *eaw = (struct enum_arg_wrapper *)arg;
  776. int rc;
  777. rc = (eaw->aef)((struct asyntaxinfo *)he->value, eaw->arg);
  778. if ( ATTR_SYNTAX_ENUM_STOP == rc ) {
  779. rc = HT_ENUMERATE_STOP;
  780. } else if ( ATTR_SYNTAX_ENUM_REMOVE == rc ) {
  781. rc = HT_ENUMERATE_REMOVE;
  782. } else {
  783. rc = HT_ENUMERATE_NEXT;
  784. }
  785. return rc;
  786. }
  787. void
  788. attr_syntax_enumerate_attrs(AttrEnumFunc aef, void *arg, PRBool writelock )
  789. {
  790. struct enum_arg_wrapper eaw;
  791. eaw.aef = aef;
  792. eaw.arg = arg;
  793. if (!oid2asi)
  794. return;
  795. if ( writelock ) {
  796. AS_LOCK_WRITE(oid2asi_lock);
  797. AS_LOCK_WRITE(name2asi_lock);
  798. } else {
  799. AS_LOCK_READ(oid2asi_lock);
  800. AS_LOCK_READ(name2asi_lock);
  801. }
  802. PL_HashTableEnumerateEntries(oid2asi, attr_syntax_enumerate_internal, &eaw);
  803. if ( writelock ) {
  804. AS_UNLOCK_WRITE(oid2asi_lock);
  805. AS_UNLOCK_WRITE(name2asi_lock);
  806. } else {
  807. AS_UNLOCK_READ(oid2asi_lock);
  808. AS_UNLOCK_READ(name2asi_lock);
  809. }
  810. }
  811. struct attr_syntax_enum_flaginfo {
  812. unsigned long asef_flag;
  813. };
  814. static int
  815. attr_syntax_clear_flag_callback(struct asyntaxinfo *asip, void *arg)
  816. {
  817. struct attr_syntax_enum_flaginfo *fi;
  818. PR_ASSERT( asip != NULL );
  819. fi = (struct attr_syntax_enum_flaginfo *)arg;
  820. PR_ASSERT( fi != NULL );
  821. asip->asi_flags &= ~(fi->asef_flag);
  822. return ATTR_SYNTAX_ENUM_NEXT;
  823. }
  824. static int
  825. attr_syntax_delete_if_not_flagged(struct asyntaxinfo *asip, void *arg)
  826. {
  827. struct attr_syntax_enum_flaginfo *fi;
  828. PR_ASSERT( asip != NULL );
  829. fi = (struct attr_syntax_enum_flaginfo *)arg;
  830. PR_ASSERT( fi != NULL );
  831. if ( 0 == ( asip->asi_flags & fi->asef_flag )) {
  832. attr_syntax_delete_no_lock( asip, PR_FALSE );
  833. return ATTR_SYNTAX_ENUM_REMOVE;
  834. } else {
  835. return ATTR_SYNTAX_ENUM_NEXT;
  836. }
  837. }
  838. static int
  839. attr_syntax_force_to_delete(struct asyntaxinfo *asip, void *arg)
  840. {
  841. struct attr_syntax_enum_flaginfo *fi;
  842. PR_ASSERT( asip != NULL );
  843. fi = (struct attr_syntax_enum_flaginfo *)arg;
  844. PR_ASSERT( fi != NULL );
  845. attr_syntax_delete_no_lock( asip, PR_FALSE );
  846. return ATTR_SYNTAX_ENUM_REMOVE;
  847. }
  848. /*
  849. * Clear 'flag' within all attribute definitions.
  850. */
  851. void
  852. attr_syntax_all_clear_flag( unsigned long flag )
  853. {
  854. struct attr_syntax_enum_flaginfo fi;
  855. memset( &fi, 0, sizeof(fi));
  856. fi.asef_flag = flag;
  857. attr_syntax_enumerate_attrs( attr_syntax_clear_flag_callback,
  858. (void *)&fi, PR_TRUE );
  859. }
  860. /*
  861. * Delete all attribute definitions that do not contain any bits of 'flag'
  862. * in their flags.
  863. */
  864. void
  865. attr_syntax_delete_all_not_flagged( unsigned long flag )
  866. {
  867. struct attr_syntax_enum_flaginfo fi;
  868. memset( &fi, 0, sizeof(fi));
  869. fi.asef_flag = flag;
  870. attr_syntax_enumerate_attrs( attr_syntax_delete_if_not_flagged,
  871. (void *)&fi, PR_TRUE );
  872. }
  873. /*
  874. * Delete all attribute definitions
  875. */
  876. void
  877. attr_syntax_delete_all()
  878. {
  879. struct attr_syntax_enum_flaginfo fi;
  880. memset( &fi, 0, sizeof(fi));
  881. attr_syntax_enumerate_attrs( attr_syntax_force_to_delete,
  882. (void *)&fi, PR_TRUE );
  883. }
  884. static int
  885. attr_syntax_init(void)
  886. {
  887. if (!oid2asi)
  888. {
  889. oid2asi = PL_NewHashTable(2047, hashNocaseString,
  890. hashNocaseCompare,
  891. PL_CompareValues, 0, 0);
  892. if ( NULL == ( oid2asi_lock = PR_NewRWLock( PR_RWLOCK_RANK_NONE,
  893. "attrsyntax oid rwlock" ))) {
  894. if(oid2asi) PL_HashTableDestroy(oid2asi);
  895. oid2asi = NULL;
  896. slapi_log_error( SLAPI_LOG_FATAL, "attr_syntax_init",
  897. "PR_NewRWLock() for oid2asi lock failed\n" );
  898. return 1;
  899. }
  900. }
  901. if (!name2asi)
  902. {
  903. name2asi = PL_NewHashTable(2047, hashNocaseString,
  904. hashNocaseCompare,
  905. PL_CompareValues, 0, 0);
  906. if ( NULL == ( name2asi_lock = PR_NewRWLock( PR_RWLOCK_RANK_NONE,
  907. "attrsyntax name2asi rwlock"))) {
  908. if(name2asi) PL_HashTableDestroy(name2asi);
  909. name2asi = NULL;
  910. slapi_log_error( SLAPI_LOG_FATAL, "attr_syntax_init",
  911. "PR_NewRWLock() for oid2asi lock failed\n" );
  912. return 1;
  913. }
  914. }
  915. return 0;
  916. }
  917. int
  918. slapi_attr_syntax_exists(const char *attr_name)
  919. {
  920. return attr_syntax_exists(attr_name);
  921. }