attrsyntax.c 29 KB

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