attrsyntax.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984
  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, PRBool ref_count);
  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, PR_TRUE);
  202. }
  203. static struct asyntaxinfo *
  204. attr_syntax_get_by_oid_locking_optional( const char *oid, PRBool use_lock, PRBool ref_count )
  205. {
  206. struct asyntaxinfo *asi = 0;
  207. if (oid2asi)
  208. {
  209. if ( use_lock ) AS_LOCK_READ(oid2asi_lock);
  210. asi = (struct asyntaxinfo *)PL_HashTableLookup_const(oid2asi, oid);
  211. if (asi)
  212. {
  213. if(ref_count) PR_AtomicIncrement( &asi->asi_refcnt );
  214. }
  215. if ( use_lock ) AS_UNLOCK_READ(oid2asi_lock);
  216. }
  217. return asi;
  218. }
  219. /*
  220. * Add the syntax info pointer to the look-up-by-oid table.
  221. * The lock parameter is used by the initialization code. Normally, we want
  222. * to acquire a write lock before we modify the table, but during
  223. * initialization, we are running in single threaded mode, so we don't have
  224. * to worry about resource contention.
  225. */
  226. static void
  227. attr_syntax_add_by_oid(const char *oid, struct asyntaxinfo *a, int lock)
  228. {
  229. if (0 != attr_syntax_init()) return;
  230. if (lock)
  231. AS_LOCK_WRITE(oid2asi_lock);
  232. PL_HashTableAdd(oid2asi, oid, a);
  233. if (lock)
  234. AS_UNLOCK_WRITE(oid2asi_lock);
  235. }
  236. /*
  237. * Return the syntax info given an attribute name. The name may be the
  238. * "canonical" name, an alias, or an OID. The given name need not be
  239. * normalized since the look up is done case insensitively.
  240. *
  241. * Note: once the caller is finished using it, the structure returned must
  242. * be returned by calling to attr_syntax_return().
  243. */
  244. struct asyntaxinfo *
  245. attr_syntax_get_by_name(const char *name)
  246. {
  247. return attr_syntax_get_by_name_locking_optional(name, PR_TRUE, PR_TRUE);
  248. }
  249. struct asyntaxinfo *
  250. attr_syntax_get_by_name_locking_optional(const char *name, PRBool use_lock, PRBool ref_count)
  251. {
  252. struct asyntaxinfo *asi = 0;
  253. if (name2asi)
  254. {
  255. if ( use_lock ) AS_LOCK_READ(name2asi_lock);
  256. asi = (struct asyntaxinfo *)PL_HashTableLookup_const(name2asi, name);
  257. if ( NULL != asi ) {
  258. if(ref_count) PR_AtomicIncrement( &asi->asi_refcnt );
  259. }
  260. if ( use_lock ) AS_UNLOCK_READ(name2asi_lock);
  261. }
  262. if (!asi) /* given name may be an OID */
  263. asi = attr_syntax_get_by_oid_locking_optional(name, use_lock, ref_count);
  264. return asi;
  265. }
  266. /*
  267. * Give up a reference to an asi.
  268. * If the asi has been marked for delete, free it. This would be a bit
  269. * easier if we could upgrade a read lock to a write one... but NSPR does
  270. * not support that paradigm.
  271. */
  272. void
  273. attr_syntax_return( struct asyntaxinfo *asi )
  274. {
  275. attr_syntax_return_locking_optional( asi, PR_TRUE );
  276. }
  277. void
  278. attr_syntax_return_locking_optional( struct asyntaxinfo *asi, PRBool use_lock )
  279. {
  280. if ( NULL != asi ) {
  281. if ( 0 == PR_AtomicDecrement( &asi->asi_refcnt ))
  282. {
  283. PRBool delete_it;
  284. if(use_lock) AS_LOCK_READ(name2asi_lock);
  285. delete_it = asi->asi_marked_for_delete;
  286. if(use_lock) AS_UNLOCK_READ(name2asi_lock);
  287. if ( delete_it )
  288. {
  289. AS_LOCK_WRITE(name2asi_lock); /* get a write lock */
  290. if ( asi->asi_marked_for_delete ) /* one final check */
  291. {
  292. attr_syntax_free(asi);
  293. }
  294. AS_UNLOCK_WRITE(name2asi_lock);
  295. }
  296. }
  297. }
  298. }
  299. /*
  300. * Add the syntax info to the look-up-by-name table. The asi_name and
  301. * elements of the asi_aliasses field of the syntax info are the keys.
  302. * These need not be normalized since the look up table is case insensitive.
  303. * The lock parameter is used by the initialization code. Normally, we want
  304. * to acquire a write lock before we modify the table, but during
  305. * initialization, we are running in single threaded mode, so we don't have
  306. * to worry about resource contention.
  307. */
  308. static void
  309. attr_syntax_add_by_name(struct asyntaxinfo *a, int lock)
  310. {
  311. if (0 != attr_syntax_init()) return;
  312. if (lock)
  313. AS_LOCK_WRITE(name2asi_lock);
  314. PL_HashTableAdd(name2asi, a->asi_name, a);
  315. if ( a->asi_aliases != NULL ) {
  316. int i;
  317. for ( i = 0; a->asi_aliases[i] != NULL; ++i ) {
  318. PL_HashTableAdd(name2asi, a->asi_aliases[i], a);
  319. }
  320. }
  321. if (lock)
  322. AS_UNLOCK_WRITE(name2asi_lock);
  323. }
  324. /*
  325. * Delete the attribute syntax and all entries corresponding to aliases
  326. * and oids.
  327. */
  328. void
  329. attr_syntax_delete( struct asyntaxinfo *asi )
  330. {
  331. PR_ASSERT( asi );
  332. if (oid2asi && name2asi) {
  333. AS_LOCK_WRITE(oid2asi_lock);
  334. AS_LOCK_WRITE(name2asi_lock);
  335. attr_syntax_delete_no_lock( asi, PR_TRUE );
  336. AS_UNLOCK_WRITE(name2asi_lock);
  337. AS_UNLOCK_WRITE(oid2asi_lock);
  338. }
  339. }
  340. /*
  341. * Dispose of a node. The caller is responsible for locking. See
  342. * attr_syntax_delete() for an example.
  343. */
  344. static void
  345. attr_syntax_delete_no_lock( struct asyntaxinfo *asi,
  346. PRBool remove_from_oidtable )
  347. {
  348. int i;
  349. if (oid2asi && remove_from_oidtable ) {
  350. PL_HashTableRemove(oid2asi, asi->asi_oid);
  351. }
  352. if(name2asi) {
  353. PL_HashTableRemove(name2asi, asi->asi_name);
  354. if ( asi->asi_aliases != NULL ) {
  355. for ( i = 0; asi->asi_aliases[i] != NULL; ++i ) {
  356. PL_HashTableRemove(name2asi, asi->asi_aliases[i]);
  357. }
  358. }
  359. if ( asi->asi_refcnt > 0 ) {
  360. asi->asi_marked_for_delete = PR_TRUE;
  361. } else {
  362. attr_syntax_free(asi);
  363. }
  364. }
  365. }
  366. /*
  367. * Look up the attribute type in the syntaxes and return a copy of the
  368. * normalised attribute type. If it's not there then return a normalised
  369. * copy of what the caller gave us.
  370. *
  371. * Warning: The caller must free the returned string.
  372. */
  373. char *
  374. slapi_attr_syntax_normalize( const char *s )
  375. {
  376. struct asyntaxinfo *asi = NULL;
  377. char *r;
  378. if((asi=attr_syntax_get_by_name_locking_optional(s, PR_TRUE, PR_FALSE)) != NULL ) {
  379. r = slapi_ch_strdup(asi->asi_name);
  380. attr_syntax_return( asi );
  381. }
  382. if ( NULL == asi ) {
  383. r = attr_syntax_normalize_no_lookup( s );
  384. }
  385. return r;
  386. }
  387. /*
  388. * attr_syntax_exists: return 1 if attr_name exists, 0 otherwise
  389. *
  390. */
  391. int
  392. attr_syntax_exists(const char *attr_name)
  393. {
  394. struct asyntaxinfo *asi;
  395. asi = attr_syntax_get_by_name(attr_name);
  396. attr_syntax_return( asi );
  397. if ( asi != NULL )
  398. {
  399. return 1;
  400. }
  401. return 0;
  402. }
  403. /* check syntax without incrementing refcount -- handles locking itself */
  404. static void *
  405. attr_syntax_get_plugin_by_name_with_default( const char *type )
  406. {
  407. struct asyntaxinfo *asi;
  408. void *plugin = NULL;
  409. /*
  410. * first we look for this attribute type explictly
  411. */
  412. if ( (asi = attr_syntax_get_by_name_locking_optional(type, PR_TRUE, PR_FALSE)) == NULL ) {
  413. /*
  414. * no syntax for this type... return DirectoryString
  415. * syntax. we accomplish this by looking up a well known
  416. * attribute type that has that syntax.
  417. */
  418. asi = attr_syntax_get_by_name_locking_optional(
  419. ATTR_WITH_DIRSTRING_SYNTAX, PR_TRUE, PR_FALSE);
  420. }
  421. if ( NULL != asi ) {
  422. plugin = asi->asi_plugin;
  423. attr_syntax_return( asi );
  424. }
  425. return( plugin );
  426. }
  427. static struct asyntaxinfo *
  428. attr_syntax_dup( struct asyntaxinfo *a )
  429. {
  430. struct asyntaxinfo *newas = attr_syntax_new();
  431. newas->asi_aliases = cool_charray_dup( a->asi_aliases );
  432. newas->asi_name = slapi_ch_strdup( a->asi_name );
  433. newas->asi_desc = slapi_ch_strdup( a->asi_desc );
  434. newas->asi_superior = slapi_ch_strdup( a->asi_superior );
  435. newas->asi_mr_equality = slapi_ch_strdup( a->asi_mr_equality );
  436. newas->asi_mr_ordering = slapi_ch_strdup( a->asi_mr_ordering );
  437. newas->asi_mr_substring = slapi_ch_strdup( a->asi_mr_substring );
  438. newas->asi_origin = cool_charray_dup( a->asi_origin );
  439. newas->asi_plugin = a->asi_plugin;
  440. newas->asi_flags = a->asi_flags;
  441. newas->asi_oid = slapi_ch_strdup( a->asi_oid);
  442. newas->asi_syntaxlength = a->asi_syntaxlength;
  443. return( newas );
  444. }
  445. /*
  446. * Add a new attribute type to the schema.
  447. *
  448. * Returns an LDAP error code (LDAP_SUCCESS if all goes well).
  449. */
  450. int
  451. attr_syntax_add( struct asyntaxinfo *asip )
  452. {
  453. int i, rc = LDAP_SUCCESS;
  454. int nolock = asip->asi_flags & SLAPI_ATTR_FLAG_NOLOCKING;
  455. struct asyntaxinfo *oldas_from_oid = NULL, *oldas_from_name = NULL;
  456. /* attr names may have subtypes in them, and we may not want this
  457. if strip_subtypes is true, the ; and anything after it in the
  458. attr name or alias will be stripped */
  459. /*int strip_subtypes = 1;*/
  460. /* make sure the oid is unique */
  461. if ( NULL != ( oldas_from_oid = attr_syntax_get_by_oid_locking_optional(
  462. asip->asi_oid, !nolock, PR_TRUE))) {
  463. if ( 0 == (asip->asi_flags & SLAPI_ATTR_FLAG_OVERRIDE)) {
  464. /* failure - OID is in use; no override flag */
  465. rc = LDAP_TYPE_OR_VALUE_EXISTS;
  466. goto cleanup_and_return;
  467. }
  468. }
  469. /* make sure the primary name is unique OR, if override is allowed, that
  470. * the primary name and OID point to the same schema definition.
  471. */
  472. if ( NULL != ( oldas_from_name = attr_syntax_get_by_name_locking_optional(
  473. asip->asi_name, !nolock, PR_TRUE))) {
  474. if ( 0 == (asip->asi_flags & SLAPI_ATTR_FLAG_OVERRIDE)
  475. || ( oldas_from_oid != oldas_from_name )) {
  476. /* failure; no override flag OR OID and name don't match */
  477. rc = LDAP_TYPE_OR_VALUE_EXISTS;
  478. goto cleanup_and_return;
  479. }
  480. } else if ( NULL != oldas_from_oid ) {
  481. /* failure - OID is in use but name does not exist */
  482. rc = LDAP_TYPE_OR_VALUE_EXISTS;
  483. goto cleanup_and_return;
  484. }
  485. if ( NULL != asip->asi_aliases ) {
  486. /* make sure the aliases are unique */
  487. for (i = 0; asip->asi_aliases[i] != NULL; ++i) {
  488. struct asyntaxinfo *tmpasi;
  489. if ( NULL != ( tmpasi =
  490. attr_syntax_get_by_name_locking_optional(
  491. asip->asi_aliases[i], !nolock,PR_TRUE))) {
  492. if (asip->asi_flags & SLAPI_ATTR_FLAG_OVERRIDE) {
  493. attr_syntax_delete(tmpasi);
  494. } else {
  495. /* failure - one of the aliases is already in use */
  496. rc = LDAP_TYPE_OR_VALUE_EXISTS;
  497. }
  498. attr_syntax_return( tmpasi );
  499. if ( LDAP_SUCCESS != rc ) {
  500. goto cleanup_and_return;
  501. }
  502. }
  503. }
  504. }
  505. /* the no lock flag is not worth keeping around */
  506. asip->asi_flags &= ~SLAPI_ATTR_FLAG_NOLOCKING;
  507. /* ditto for the override one */
  508. asip->asi_flags &= ~SLAPI_ATTR_FLAG_OVERRIDE;
  509. attr_syntax_add_by_oid( asip->asi_oid, asip, !nolock);
  510. attr_syntax_add_by_name( asip, !nolock);
  511. cleanup_and_return:
  512. attr_syntax_return( oldas_from_oid );
  513. attr_syntax_return( oldas_from_name );
  514. return rc;
  515. }
  516. /*
  517. * Returns an LDAP result code.
  518. */
  519. int
  520. attr_syntax_create(
  521. const char *attr_oid,
  522. char *const *attr_names,
  523. int num_names,
  524. const char *attr_desc,
  525. const char *attr_superior,
  526. const char *mr_equality,
  527. const char *mr_ordering,
  528. const char *mr_substring,
  529. char *const *attr_origins,
  530. const char *attr_syntax,
  531. int syntaxlength,
  532. unsigned long flags,
  533. struct asyntaxinfo **asip
  534. )
  535. {
  536. char *s;
  537. struct asyntaxinfo a;
  538. /* XXXmcs: had to cast away const in many places below */
  539. memset(&a, 0, sizeof(a));
  540. a.asi_name = slapi_ch_strdup(attr_names[0]);
  541. if ( NULL != attr_names[1] ) {
  542. a.asi_aliases = (char **)&attr_names[1]; /* all but the zero'th element */
  543. }
  544. a.asi_desc = (char*)attr_desc;
  545. a.asi_oid = (char*)attr_oid;
  546. a.asi_superior = (char*)attr_superior;
  547. a.asi_mr_equality = (char*)mr_equality;
  548. a.asi_mr_ordering = (char*)mr_ordering;
  549. a.asi_mr_substring = (char*)mr_substring;
  550. a.asi_origin = (char **)attr_origins;
  551. a.asi_plugin = plugin_syntax_find( attr_syntax );
  552. a.asi_syntaxlength = syntaxlength;
  553. a.asi_flags = flags;
  554. /*
  555. * If the 'return exact case' option is on (the default), we store the
  556. * first name (the canonical one) unchanged so that attribute names are
  557. * returned exactly as they appear in the schema configuration files.
  558. * But if 'return exact case' has been turned off, we convert the name
  559. * to lowercase. In Netscape Directory Server 4.x and earlier versions,
  560. * the default was to convert to lowercase.
  561. */
  562. if (!config_get_return_exact_case()) {
  563. for (s = a.asi_name; *s; ++s) {
  564. *s = TOLOWER(*s);
  565. }
  566. }
  567. *asip = attr_syntax_dup(&a);
  568. slapi_ch_free((void **)&a.asi_name);
  569. return LDAP_SUCCESS;
  570. }
  571. /*
  572. * slapi_attr_type2plugin - return the plugin handling the attribute type
  573. * if type is unknown, we return the caseIgnoreString plugin used by the
  574. * objectClass attribute type.
  575. */
  576. int
  577. slapi_attr_type2plugin( const char *type, void **pi )
  578. {
  579. char buf[SLAPD_TYPICAL_ATTRIBUTE_NAME_MAX_LENGTH];
  580. char *tmp, *basetype;
  581. int rc;
  582. basetype = buf;
  583. if ( (tmp = slapi_attr_basetype( type, buf, sizeof(buf) )) != NULL ) {
  584. basetype = tmp;
  585. }
  586. rc = -1;
  587. *pi = attr_syntax_get_plugin_by_name_with_default( basetype );
  588. if ( NULL != *pi ) {
  589. rc = 0;
  590. }
  591. slapi_ch_free_string(&tmp);
  592. return( rc );
  593. }
  594. /* deprecated -- not MT safe (pointer into asi is returned!) */
  595. int
  596. slapi_attr_get_oid( const Slapi_Attr *a, char **oid )
  597. {
  598. struct asyntaxinfo *asi = attr_syntax_get_by_name(a->a_type);
  599. if (asi) {
  600. *oid = asi->asi_oid;
  601. attr_syntax_return(asi);
  602. return( 0 );
  603. } else {
  604. *oid = NULL;
  605. return( -1 );
  606. }
  607. }
  608. /* The caller must dispose of oid by calling slapi_ch_free(). */
  609. int
  610. slapi_attr_get_oid_copy( const Slapi_Attr *a, char **oidp )
  611. {
  612. struct asyntaxinfo *asi = attr_syntax_get_by_name(a->a_type);
  613. if (asi) {
  614. *oidp = slapi_ch_strdup( asi->asi_oid );
  615. attr_syntax_return(asi);
  616. return( 0 );
  617. } else {
  618. *oidp = NULL;
  619. return( -1 );
  620. }
  621. }
  622. /* Returns the oid of the syntax of the Slapi_Attr that's passed in.
  623. * The caller must dispose of oid by calling slapi_ch_free_string(). */
  624. int
  625. slapi_attr_get_syntax_oid_copy( const Slapi_Attr *a, char **oidp )
  626. {
  627. void *pi = NULL;
  628. if (a && (slapi_attr_type2plugin(a->a_type, &pi) == 0)) {
  629. *oidp = slapi_ch_strdup(plugin_syntax2oid(pi));
  630. return( 0 );
  631. } else {
  632. *oidp = NULL;
  633. return( -1 );
  634. }
  635. }
  636. #ifdef ATTR_LDAP_DEBUG
  637. PRIntn
  638. attr_syntax_printnode(PLHashEntry *he, PRIntn i, void *arg)
  639. {
  640. char *alias = (char *)he->key;
  641. struct asyntaxinfo *a = (struct asyntaxinfo *)he->value;
  642. printf( " name: %s\n", a->asi_name );
  643. printf( "\t flags : 0x%x\n", a->asi_flags );
  644. printf( "\t alias : %s\n", alias );
  645. printf( "\t desc : %s\n", a->asi_desc );
  646. printf( "\t oid : %s\n", a->asi_oid );
  647. printf( "\t superior : %s\n", a->asi_superior );
  648. printf( "\t mr_equality : %s\n", a->asi_mr_equality );
  649. printf( "\t mr_ordering : %s\n", a->asi_mr_ordering );
  650. printf( "\t mr_substring: %s\n", a->asi_mr_substring );
  651. if ( NULL != a->asi_origin ) {
  652. for ( i = 0; NULL != a->asi_origin[i]; ++i ) {
  653. printf( "\t origin : %s\n", a->asi_origin[i] );
  654. }
  655. }
  656. printf( "\tplugin: %p\n", a->asi_plugin );
  657. printf( "--------------\n" );
  658. return HT_ENUMERATE_NEXT;
  659. }
  660. void
  661. attr_syntax_print()
  662. {
  663. printf( "*** attr_syntax_print ***\n" );
  664. PL_HashTableEnumerateEntries(name2asi, attr_syntax_printnode, 0);
  665. }
  666. #endif
  667. /* lowercase the attr name and chop trailing spaces */
  668. /* note that s may contain options also, e.g., userCertificate;binary */
  669. char *
  670. attr_syntax_normalize_no_lookup( const char *s )
  671. {
  672. char *save, *tmps;
  673. tmps = slapi_ch_strdup(s);
  674. for ( save = tmps; (*tmps != '\0') && (*tmps != ' '); tmps++ )
  675. {
  676. *tmps = TOLOWER( *tmps );
  677. }
  678. *tmps = '\0';
  679. return save;
  680. }
  681. struct enum_arg_wrapper {
  682. AttrEnumFunc aef;
  683. void *arg;
  684. };
  685. PRIntn
  686. attr_syntax_enumerate_internal(PLHashEntry *he, PRIntn i, void *arg)
  687. {
  688. struct enum_arg_wrapper *eaw = (struct enum_arg_wrapper *)arg;
  689. int rc;
  690. rc = (eaw->aef)((struct asyntaxinfo *)he->value, eaw->arg);
  691. if ( ATTR_SYNTAX_ENUM_STOP == rc ) {
  692. rc = HT_ENUMERATE_STOP;
  693. } else if ( ATTR_SYNTAX_ENUM_REMOVE == rc ) {
  694. rc = HT_ENUMERATE_REMOVE;
  695. } else {
  696. rc = HT_ENUMERATE_NEXT;
  697. }
  698. return rc;
  699. }
  700. void
  701. attr_syntax_enumerate_attrs(AttrEnumFunc aef, void *arg, PRBool writelock )
  702. {
  703. struct enum_arg_wrapper eaw;
  704. eaw.aef = aef;
  705. eaw.arg = arg;
  706. if (!oid2asi)
  707. return;
  708. if ( writelock ) {
  709. AS_LOCK_WRITE(oid2asi_lock);
  710. AS_LOCK_WRITE(name2asi_lock);
  711. } else {
  712. AS_LOCK_READ(oid2asi_lock);
  713. AS_LOCK_READ(name2asi_lock);
  714. }
  715. PL_HashTableEnumerateEntries(oid2asi, attr_syntax_enumerate_internal, &eaw);
  716. if ( writelock ) {
  717. AS_UNLOCK_WRITE(oid2asi_lock);
  718. AS_UNLOCK_WRITE(name2asi_lock);
  719. } else {
  720. AS_UNLOCK_READ(oid2asi_lock);
  721. AS_UNLOCK_READ(name2asi_lock);
  722. }
  723. }
  724. struct attr_syntax_enum_flaginfo {
  725. unsigned long asef_flag;
  726. };
  727. static int
  728. attr_syntax_clear_flag_callback(struct asyntaxinfo *asip, void *arg)
  729. {
  730. struct attr_syntax_enum_flaginfo *fi;
  731. PR_ASSERT( asip != NULL );
  732. fi = (struct attr_syntax_enum_flaginfo *)arg;
  733. PR_ASSERT( fi != NULL );
  734. asip->asi_flags &= ~(fi->asef_flag);
  735. return ATTR_SYNTAX_ENUM_NEXT;
  736. }
  737. static int
  738. attr_syntax_delete_if_not_flagged(struct asyntaxinfo *asip, void *arg)
  739. {
  740. struct attr_syntax_enum_flaginfo *fi;
  741. PR_ASSERT( asip != NULL );
  742. fi = (struct attr_syntax_enum_flaginfo *)arg;
  743. PR_ASSERT( fi != NULL );
  744. if ( 0 == ( asip->asi_flags & fi->asef_flag )) {
  745. attr_syntax_delete_no_lock( asip, PR_FALSE );
  746. return ATTR_SYNTAX_ENUM_REMOVE;
  747. } else {
  748. return ATTR_SYNTAX_ENUM_NEXT;
  749. }
  750. }
  751. static int
  752. attr_syntax_force_to_delete(struct asyntaxinfo *asip, void *arg)
  753. {
  754. struct attr_syntax_enum_flaginfo *fi;
  755. PR_ASSERT( asip != NULL );
  756. fi = (struct attr_syntax_enum_flaginfo *)arg;
  757. PR_ASSERT( fi != NULL );
  758. attr_syntax_delete_no_lock( asip, PR_FALSE );
  759. return ATTR_SYNTAX_ENUM_REMOVE;
  760. }
  761. /*
  762. * Clear 'flag' within all attribute definitions.
  763. */
  764. void
  765. attr_syntax_all_clear_flag( unsigned long flag )
  766. {
  767. struct attr_syntax_enum_flaginfo fi;
  768. memset( &fi, 0, sizeof(fi));
  769. fi.asef_flag = flag;
  770. attr_syntax_enumerate_attrs( attr_syntax_clear_flag_callback,
  771. (void *)&fi, PR_TRUE );
  772. }
  773. /*
  774. * Delete all attribute definitions that do not contain any bits of 'flag'
  775. * in their flags.
  776. */
  777. void
  778. attr_syntax_delete_all_not_flagged( unsigned long flag )
  779. {
  780. struct attr_syntax_enum_flaginfo fi;
  781. memset( &fi, 0, sizeof(fi));
  782. fi.asef_flag = flag;
  783. attr_syntax_enumerate_attrs( attr_syntax_delete_if_not_flagged,
  784. (void *)&fi, PR_TRUE );
  785. }
  786. /*
  787. * Delete all attribute definitions
  788. */
  789. void
  790. attr_syntax_delete_all()
  791. {
  792. struct attr_syntax_enum_flaginfo fi;
  793. memset( &fi, 0, sizeof(fi));
  794. attr_syntax_enumerate_attrs( attr_syntax_force_to_delete,
  795. (void *)&fi, PR_TRUE );
  796. }
  797. static int
  798. attr_syntax_init(void)
  799. {
  800. if (!oid2asi)
  801. {
  802. oid2asi = PL_NewHashTable(2047, hashNocaseString,
  803. hashNocaseCompare,
  804. PL_CompareValues, 0, 0);
  805. if ( NULL == ( oid2asi_lock = PR_NewRWLock( PR_RWLOCK_RANK_NONE,
  806. "attrsyntax oid rwlock" ))) {
  807. if(oid2asi) PL_HashTableDestroy(oid2asi);
  808. oid2asi = NULL;
  809. slapi_log_error( SLAPI_LOG_FATAL, "attr_syntax_init",
  810. "PR_NewRWLock() for oid2asi lock failed\n" );
  811. return 1;
  812. }
  813. }
  814. if (!name2asi)
  815. {
  816. name2asi = PL_NewHashTable(2047, hashNocaseString,
  817. hashNocaseCompare,
  818. PL_CompareValues, 0, 0);
  819. if ( NULL == ( name2asi_lock = PR_NewRWLock( PR_RWLOCK_RANK_NONE,
  820. "attrsyntax name2asi rwlock"))) {
  821. if(name2asi) PL_HashTableDestroy(name2asi);
  822. name2asi = NULL;
  823. slapi_log_error( SLAPI_LOG_FATAL, "attr_syntax_init",
  824. "PR_NewRWLock() for oid2asi lock failed\n" );
  825. return 1;
  826. }
  827. }
  828. return 0;
  829. }