attrsyntax.c 28 KB

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