attrsyntax.c 24 KB

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