attrsyntax.c 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184
  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. static PLHashTable *internalasi = NULL;
  55. /*
  56. * This hashtable maps the name or alias of the attribute to the
  57. * syntax info structure for that attribute. An attribute type has as
  58. * many entries in the name2asi table as it has names and aliases, but
  59. * all entries point to the same struct asyntaxinfo.
  60. */
  61. static PLHashTable *name2asi = NULL;
  62. /* read/write lock to protect table */
  63. static Slapi_RWLock *name2asi_lock = NULL;
  64. #define AS_LOCK_READ(l) slapi_rwlock_rdlock(l)
  65. #define AS_LOCK_WRITE(l) slapi_rwlock_wrlock(l)
  66. #define AS_UNLOCK_READ(l) slapi_rwlock_unlock(l)
  67. #define AS_UNLOCK_WRITE(l) slapi_rwlock_unlock(l)
  68. static void *attr_syntax_get_plugin_by_name_with_default( const char *type );
  69. static void attr_syntax_delete_no_lock( struct asyntaxinfo *asip,
  70. PRBool remove_from_oid_table );
  71. static struct asyntaxinfo *attr_syntax_get_by_oid_locking_optional( const
  72. char *oid, PRBool use_lock);
  73. #ifdef ATTR_LDAP_DEBUG
  74. static void attr_syntax_print();
  75. #endif
  76. static int attr_syntax_init(void);
  77. void
  78. attr_syntax_read_lock(void)
  79. {
  80. if (0 != attr_syntax_init()) return;
  81. AS_LOCK_READ(oid2asi_lock);
  82. AS_LOCK_READ(name2asi_lock);
  83. }
  84. void
  85. attr_syntax_unlock_read(void)
  86. {
  87. if(name2asi_lock) AS_UNLOCK_READ(name2asi_lock);
  88. if(oid2asi_lock) AS_UNLOCK_READ(oid2asi_lock);
  89. }
  90. #if 0
  91. static int
  92. check_oid( const char *oid ) {
  93. int i = 0, length_oid = 0, rc = 0;
  94. if ( oid == NULL) {
  95. /* this is bad */
  96. LDAPDebug (LDAP_DEBUG_ANY, "NULL passed to check_oid\n",0,0,0);
  97. return 0;
  98. }
  99. length_oid = strlen(oid);
  100. if (length_oid < 4) {
  101. /* this is probably bad */
  102. LDAPDebug (LDAP_DEBUG_ANY, "Bad oid %s passed to check_oid\n",oid,0,0);
  103. return 0;
  104. }
  105. rc = strcasecmp(oid+(length_oid-4), "-oid");
  106. if ( 0 == rc ) {
  107. return 1;
  108. }
  109. /* If not, the OID must begin and end with a digit, and contain only
  110. digits and dots */
  111. if ( !isdigit(oid[0]) ||
  112. !isdigit(oid[length_oid-1]) ) {
  113. LDAPDebug (LDAP_DEBUG_ANY, "Non numeric oid %s passed to check_oid\n",oid,0,0);
  114. return 0;
  115. }
  116. /* check to see that it contains only digits and dots */
  117. for ( i = 0; i < length_oid; i++ ) {
  118. if ( !isdigit(oid[i]) && oid[i] != '.' ){
  119. LDAPDebug (LDAP_DEBUG_ANY, "Non numeric oid %s passed to check_oid\n",oid,0,0);
  120. return 0;
  121. }
  122. }
  123. /* The oid is OK if we're here */
  124. return 1;
  125. }
  126. #endif
  127. #define NBUCKETS(ht) (1 << (PL_HASH_BITS - (ht)->shift))
  128. #if 0
  129. static int
  130. attr_syntax_check_oids()
  131. {
  132. int ii = 0;
  133. int nbad = 0;
  134. AS_LOCK_READ(oid2asi_lock);
  135. ii = NBUCKETS(oid2asi);
  136. for (;ii;--ii) {
  137. PLHashEntry *he = oid2asi->buckets[ii-1];
  138. for (; he; he = he->next) {
  139. if (!check_oid(he->key)) {
  140. LDAPDebug(LDAP_DEBUG_ANY, "Error: bad oid %s in bucket %d\n",
  141. he->key, ii-1, 0);
  142. nbad++;
  143. }
  144. }
  145. }
  146. AS_UNLOCK_READ(oid2asi_lock);
  147. return nbad;
  148. }
  149. #endif
  150. void
  151. attr_syntax_free( struct asyntaxinfo *a )
  152. {
  153. PR_ASSERT( a->asi_refcnt == 0 );
  154. cool_charray_free( a->asi_aliases );
  155. slapi_ch_free( (void**)&a->asi_name );
  156. slapi_ch_free( (void **)&a->asi_desc );
  157. slapi_ch_free( (void **)&a->asi_oid );
  158. slapi_ch_free( (void **)&a->asi_superior );
  159. slapi_ch_free( (void **)&a->asi_mr_equality );
  160. slapi_ch_free( (void **)&a->asi_mr_ordering );
  161. slapi_ch_free( (void **)&a->asi_mr_substring );
  162. cool_charray_free( a->asi_origin );
  163. slapi_ch_free( (void **) &a );
  164. }
  165. static struct asyntaxinfo *
  166. attr_syntax_new()
  167. {
  168. return (struct asyntaxinfo *)slapi_ch_calloc(1, sizeof(struct asyntaxinfo));
  169. }
  170. /*
  171. * Given an OID, return the syntax info. If there is more than one
  172. * attribute syntax with the same OID (i.e. aliases), the first one
  173. * will be returned. This is usually the "canonical" one, but it may
  174. * not be.
  175. *
  176. * Note: once the caller is finished using it, the structure returned must
  177. * be returned by calling to attr_syntax_return().
  178. */
  179. struct asyntaxinfo *
  180. attr_syntax_get_by_oid(const char *oid)
  181. {
  182. return attr_syntax_get_by_oid_locking_optional( oid, PR_TRUE);
  183. }
  184. /*
  185. * A version of attr_syntax_get_by_oid() that allows you to bypass using
  186. * a lock to access the global oid hash table.
  187. *
  188. * Note: once the caller is finished using it, the structure must be
  189. * returned by calling attr_syntax_return_locking_optional() with the
  190. * same use_lock parameter.
  191. */
  192. static struct asyntaxinfo *
  193. attr_syntax_get_by_oid_locking_optional( const char *oid, PRBool use_lock )
  194. {
  195. struct asyntaxinfo *asi = 0;
  196. if (oid2asi)
  197. {
  198. if ( use_lock ) AS_LOCK_READ(oid2asi_lock);
  199. asi = (struct asyntaxinfo *)PL_HashTableLookup_const(oid2asi, oid);
  200. if (asi)
  201. {
  202. PR_AtomicIncrement( &asi->asi_refcnt );
  203. }
  204. if ( use_lock ) AS_UNLOCK_READ(oid2asi_lock);
  205. }
  206. return asi;
  207. }
  208. /*
  209. * Add the syntax info pointer to the look-up-by-oid table.
  210. * The lock parameter is used by the initialization code. Normally, we want
  211. * to acquire a write lock before we modify the table, but during
  212. * initialization, we are running in single threaded mode, so we don't have
  213. * to worry about resource contention.
  214. */
  215. static void
  216. attr_syntax_add_by_oid(const char *oid, struct asyntaxinfo *a, int lock)
  217. {
  218. if (0 != attr_syntax_init()) return;
  219. if (lock)
  220. AS_LOCK_WRITE(oid2asi_lock);
  221. PL_HashTableAdd(oid2asi, oid, a);
  222. if (lock)
  223. AS_UNLOCK_WRITE(oid2asi_lock);
  224. }
  225. /*
  226. * Return the syntax info given an attribute name. The name may be the
  227. * "canonical" name, an alias, or an OID. The given name need not be
  228. * normalized since the look up is done case insensitively.
  229. *
  230. * Note: once the caller is finished using it, the structure returned must
  231. * be returned by calling to attr_syntax_return().
  232. */
  233. struct asyntaxinfo *
  234. attr_syntax_get_by_name(const char *name)
  235. {
  236. return attr_syntax_get_by_name_locking_optional(name, PR_TRUE);
  237. }
  238. /*
  239. * A version of attr_syntax_get_by_name() that allows you to bypass using
  240. * a lock around the global name hashtable.
  241. *
  242. * Note: once the caller is finished using it, the structure must be
  243. * returned by calling attr_syntax_return_locking_optional() with the
  244. * same use_lock parameter.
  245. */
  246. struct asyntaxinfo *
  247. attr_syntax_get_by_name_locking_optional(const char *name, PRBool use_lock)
  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. 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);
  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. /* ref count is 0 and it's flagged for
  290. * deletion, so it's safe to free now */
  291. attr_syntax_free(asi);
  292. }
  293. AS_UNLOCK_WRITE(name2asi_lock);
  294. }
  295. }
  296. }
  297. }
  298. /*
  299. * Add the syntax info to the look-up-by-name table. The asi_name and
  300. * elements of the asi_aliasses field of the syntax info are the keys.
  301. * These need not be normalized since the look up table is case insensitive.
  302. * The lock parameter is used by the initialization code. Normally, we want
  303. * to acquire a write lock before we modify the table, but during
  304. * initialization, we are running in single threaded mode, so we don't have
  305. * to worry about resource contention.
  306. */
  307. static void
  308. attr_syntax_add_by_name(struct asyntaxinfo *a, int lock)
  309. {
  310. if (0 != attr_syntax_init()) return;
  311. if (lock)
  312. AS_LOCK_WRITE(name2asi_lock);
  313. PL_HashTableAdd(name2asi, a->asi_name, a);
  314. if ( a->asi_aliases != NULL ) {
  315. int i;
  316. for ( i = 0; a->asi_aliases[i] != NULL; ++i ) {
  317. PL_HashTableAdd(name2asi, a->asi_aliases[i], a);
  318. }
  319. }
  320. if (lock)
  321. AS_UNLOCK_WRITE(name2asi_lock);
  322. }
  323. /*
  324. * Delete the attribute syntax and all entries corresponding to aliases
  325. * and oids.
  326. */
  327. void
  328. attr_syntax_delete( struct asyntaxinfo *asi )
  329. {
  330. PR_ASSERT( asi );
  331. if (oid2asi && name2asi) {
  332. AS_LOCK_WRITE(oid2asi_lock);
  333. AS_LOCK_WRITE(name2asi_lock);
  334. attr_syntax_delete_no_lock( asi, PR_TRUE );
  335. AS_UNLOCK_WRITE(name2asi_lock);
  336. AS_UNLOCK_WRITE(oid2asi_lock);
  337. }
  338. }
  339. /*
  340. * Dispose of a node. The caller is responsible for locking. See
  341. * attr_syntax_delete() for an example.
  342. */
  343. static void
  344. attr_syntax_delete_no_lock( struct asyntaxinfo *asi,
  345. PRBool remove_from_oidtable )
  346. {
  347. int i;
  348. if (oid2asi && remove_from_oidtable ) {
  349. PL_HashTableRemove(oid2asi, asi->asi_oid);
  350. }
  351. if(name2asi) {
  352. PL_HashTableRemove(name2asi, asi->asi_name);
  353. if ( asi->asi_aliases != NULL ) {
  354. for ( i = 0; asi->asi_aliases[i] != NULL; ++i ) {
  355. PL_HashTableRemove(name2asi, asi->asi_aliases[i]);
  356. }
  357. }
  358. if ( asi->asi_refcnt > 0 ) {
  359. asi->asi_marked_for_delete = PR_TRUE;
  360. } else {
  361. /* This is ok, but the correct thing is to call delete first,
  362. * then to call return. The last return will then take care of
  363. * the free. The only way this free would happen here is if
  364. * you return the syntax before calling delete. */
  365. attr_syntax_free(asi);
  366. }
  367. }
  368. }
  369. /*
  370. * Look up the attribute type in the syntaxes and return a copy of the
  371. * normalised attribute type. If it's not there then return a normalised
  372. * copy of what the caller gave us.
  373. *
  374. * Warning: The caller must free the returned string.
  375. */
  376. char *
  377. slapi_attr_syntax_normalize( const char *s )
  378. {
  379. struct asyntaxinfo *asi = NULL;
  380. char *r = NULL;
  381. if((asi=attr_syntax_get_by_name(s)) != NULL ) {
  382. r = slapi_ch_strdup(asi->asi_name);
  383. attr_syntax_return( asi );
  384. }
  385. if ( NULL == asi ) {
  386. slapi_ch_free_string( &r );
  387. r = attr_syntax_normalize_no_lookup( s );
  388. }
  389. return r;
  390. }
  391. /*
  392. * attr_syntax_exists: return 1 if attr_name exists, 0 otherwise
  393. *
  394. */
  395. int
  396. attr_syntax_exists(const char *attr_name)
  397. {
  398. struct asyntaxinfo *asi;
  399. asi = attr_syntax_get_by_name(attr_name);
  400. attr_syntax_return( asi );
  401. if ( asi != NULL )
  402. {
  403. return 1;
  404. }
  405. return 0;
  406. }
  407. /* check syntax */
  408. static void *
  409. attr_syntax_get_plugin_by_name_with_default( const char *type )
  410. {
  411. struct asyntaxinfo *asi;
  412. void *plugin = NULL;
  413. /*
  414. * first we look for this attribute type explictly
  415. */
  416. if ( (asi = attr_syntax_get_by_name(type)) == NULL ) {
  417. /*
  418. * no syntax for this type... return Octet String
  419. * syntax. we accomplish this by looking up a well known
  420. * attribute type that has that syntax.
  421. */
  422. asi = attr_syntax_get_by_name(ATTR_WITH_OCTETSTRING_SYNTAX);
  423. }
  424. if ( NULL != asi ) {
  425. plugin = asi->asi_plugin;
  426. attr_syntax_return( asi );
  427. }
  428. return( plugin );
  429. }
  430. static struct asyntaxinfo *
  431. attr_syntax_dup( struct asyntaxinfo *a )
  432. {
  433. struct asyntaxinfo *newas = attr_syntax_new();
  434. newas->asi_aliases = cool_charray_dup( a->asi_aliases );
  435. newas->asi_name = slapi_ch_strdup( a->asi_name );
  436. newas->asi_desc = slapi_ch_strdup( a->asi_desc );
  437. newas->asi_superior = slapi_ch_strdup( a->asi_superior );
  438. newas->asi_mr_equality = slapi_ch_strdup( a->asi_mr_equality );
  439. newas->asi_mr_ordering = slapi_ch_strdup( a->asi_mr_ordering );
  440. newas->asi_mr_substring = slapi_ch_strdup( a->asi_mr_substring );
  441. newas->asi_origin = cool_charray_dup( a->asi_origin );
  442. newas->asi_plugin = a->asi_plugin;
  443. newas->asi_flags = a->asi_flags;
  444. newas->asi_oid = slapi_ch_strdup( a->asi_oid);
  445. newas->asi_syntaxlength = a->asi_syntaxlength;
  446. newas->asi_mr_eq_plugin = a->asi_mr_eq_plugin;
  447. newas->asi_mr_ord_plugin = a->asi_mr_ord_plugin;
  448. newas->asi_mr_sub_plugin = a->asi_mr_sub_plugin;
  449. return( newas );
  450. }
  451. /*
  452. * Add a new attribute type to the schema.
  453. *
  454. * Returns an LDAP error code (LDAP_SUCCESS if all goes well).
  455. */
  456. int
  457. attr_syntax_add( struct asyntaxinfo *asip )
  458. {
  459. int i, rc = LDAP_SUCCESS;
  460. int nolock = asip->asi_flags & SLAPI_ATTR_FLAG_NOLOCKING;
  461. struct asyntaxinfo *oldas_from_oid = NULL, *oldas_from_name = NULL;
  462. /* attr names may have subtypes in them, and we may not want this
  463. if strip_subtypes is true, the ; and anything after it in the
  464. attr name or alias will be stripped */
  465. /*int strip_subtypes = 1;*/
  466. /* make sure the oid is unique */
  467. if ( NULL != ( oldas_from_oid = attr_syntax_get_by_oid_locking_optional(
  468. asip->asi_oid, !nolock))) {
  469. if ( 0 == (asip->asi_flags & SLAPI_ATTR_FLAG_OVERRIDE)) {
  470. /* failure - OID is in use; no override flag */
  471. rc = LDAP_TYPE_OR_VALUE_EXISTS;
  472. goto cleanup_and_return;
  473. }
  474. }
  475. /* make sure the primary name is unique OR, if override is allowed, that
  476. * the primary name and OID point to the same schema definition.
  477. */
  478. if ( NULL != ( oldas_from_name = attr_syntax_get_by_name_locking_optional(
  479. asip->asi_name, !nolock))) {
  480. if ( 0 == (asip->asi_flags & SLAPI_ATTR_FLAG_OVERRIDE)
  481. || ( oldas_from_oid != oldas_from_name )) {
  482. /* failure; no override flag OR OID and name don't match */
  483. rc = LDAP_TYPE_OR_VALUE_EXISTS;
  484. goto cleanup_and_return;
  485. }
  486. /* Flag for deletion. We are going to override this attr */
  487. attr_syntax_delete(oldas_from_name);
  488. } else if ( NULL != oldas_from_oid ) {
  489. /* failure - OID is in use but name does not exist */
  490. rc = LDAP_TYPE_OR_VALUE_EXISTS;
  491. goto cleanup_and_return;
  492. }
  493. if ( NULL != asip->asi_aliases ) {
  494. /* make sure the aliases are unique */
  495. for (i = 0; asip->asi_aliases[i] != NULL; ++i) {
  496. struct asyntaxinfo *tmpasi;
  497. if ( NULL != ( tmpasi =
  498. attr_syntax_get_by_name_locking_optional(
  499. asip->asi_aliases[i], !nolock))) {
  500. if (asip->asi_flags & SLAPI_ATTR_FLAG_OVERRIDE) {
  501. /* Flag for tmpasi for deletion. It will be free'd
  502. * when attr_syntax_return is called. */
  503. attr_syntax_delete(tmpasi);
  504. } else {
  505. /* failure - one of the aliases is already in use */
  506. rc = LDAP_TYPE_OR_VALUE_EXISTS;
  507. }
  508. attr_syntax_return_locking_optional( tmpasi, !nolock );
  509. if ( LDAP_SUCCESS != rc ) {
  510. goto cleanup_and_return;
  511. }
  512. }
  513. }
  514. }
  515. /* the no lock flag is not worth keeping around */
  516. asip->asi_flags &= ~SLAPI_ATTR_FLAG_NOLOCKING;
  517. /* ditto for the override one */
  518. asip->asi_flags &= ~SLAPI_ATTR_FLAG_OVERRIDE;
  519. attr_syntax_add_by_oid( asip->asi_oid, asip, !nolock);
  520. attr_syntax_add_by_name( asip, !nolock);
  521. cleanup_and_return:
  522. attr_syntax_return_locking_optional( oldas_from_oid, !nolock );
  523. attr_syntax_return_locking_optional( oldas_from_name, !nolock );
  524. return rc;
  525. }
  526. /*
  527. * Returns an LDAP result code.
  528. */
  529. int
  530. attr_syntax_create(
  531. const char *attr_oid,
  532. char *const *attr_names,
  533. int num_names,
  534. const char *attr_desc,
  535. const char *attr_superior,
  536. const char *mr_equality,
  537. const char *mr_ordering,
  538. const char *mr_substring,
  539. char *const *attr_origins,
  540. const char *attr_syntax,
  541. int syntaxlength,
  542. unsigned long flags,
  543. struct asyntaxinfo **asip
  544. )
  545. {
  546. char *s;
  547. struct asyntaxinfo a;
  548. int rc = LDAP_SUCCESS;
  549. /* XXXmcs: had to cast away const in many places below */
  550. memset(&a, 0, sizeof(a));
  551. *asip = NULL;
  552. a.asi_name = slapi_ch_strdup(attr_names[0]);
  553. if ( NULL != attr_names[1] ) {
  554. a.asi_aliases = (char **)&attr_names[1]; /* all but the zero'th element */
  555. }
  556. a.asi_desc = (char*)attr_desc;
  557. a.asi_oid = (char*)attr_oid;
  558. a.asi_superior = (char*)attr_superior;
  559. a.asi_mr_equality = (char*)mr_equality;
  560. a.asi_mr_ordering = (char*)mr_ordering;
  561. a.asi_mr_substring = (char*)mr_substring;
  562. a.asi_origin = (char **)attr_origins;
  563. a.asi_plugin = plugin_syntax_find( attr_syntax );
  564. a.asi_syntaxlength = syntaxlength;
  565. /* ideally, we would report an error and fail to start if there was some problem
  566. with the matching rule - but since this functionality is new, and we might
  567. cause havoc if lots of servers failed to start because of bogus schema, we
  568. just report an error here - at some point in the future, we should actually
  569. report an error and exit, or allow the user to control the behavior - for
  570. now, just log an error, and address each case
  571. */
  572. if (mr_equality && !slapi_matchingrule_is_compat(mr_equality, attr_syntax)) {
  573. slapi_log_error(SLAPI_LOG_FATAL, "attr_syntax_create",
  574. "Error: the EQUALITY matching rule [%s] is not compatible "
  575. "with the syntax [%s] for the attribute [%s]\n",
  576. mr_equality, attr_syntax, attr_names[0]);
  577. #ifdef ENFORCE_MR_SYNTAX_COMPAT
  578. rc = LDAP_INAPPROPRIATE_MATCHING;
  579. goto done;
  580. #endif /* ENFORCE_MR_SYNTAX_COMPAT */
  581. }
  582. a.asi_mr_eq_plugin = plugin_mr_find( mr_equality );
  583. if (mr_ordering && !slapi_matchingrule_is_compat(mr_ordering, attr_syntax)) {
  584. slapi_log_error(SLAPI_LOG_FATAL, "attr_syntax_create",
  585. "Error: the ORDERING matching rule [%s] is not compatible "
  586. "with the syntax [%s] for the attribute [%s]\n",
  587. mr_ordering, attr_syntax, attr_names[0]);
  588. #ifdef ENFORCE_MR_SYNTAX_COMPAT
  589. rc = LDAP_INAPPROPRIATE_MATCHING;
  590. goto done;
  591. #endif /* ENFORCE_MR_SYNTAX_COMPAT */
  592. }
  593. a.asi_mr_ord_plugin = plugin_mr_find( mr_ordering );
  594. if (mr_substring && !slapi_matchingrule_is_compat(mr_substring, attr_syntax)) {
  595. slapi_log_error(SLAPI_LOG_FATAL, "attr_syntax_create",
  596. "Error: the SUBSTR matching rule [%s] is not compatible "
  597. "with the syntax [%s] for the attribute [%s]\n",
  598. mr_substring, attr_syntax, attr_names[0]);
  599. #ifdef ENFORCE_MR_SYNTAX_COMPAT
  600. rc = LDAP_INAPPROPRIATE_MATCHING;
  601. goto done;
  602. #endif /* ENFORCE_MR_SYNTAX_COMPAT */
  603. }
  604. a.asi_mr_sub_plugin = plugin_mr_find( mr_substring );
  605. a.asi_flags = flags;
  606. /*
  607. * If the 'return exact case' option is on (the default), we store the
  608. * first name (the canonical one) unchanged so that attribute names are
  609. * returned exactly as they appear in the schema configuration files.
  610. * But if 'return exact case' has been turned off, we convert the name
  611. * to lowercase. In Netscape Directory Server 4.x and earlier versions,
  612. * the default was to convert to lowercase.
  613. */
  614. if (!config_get_return_exact_case()) {
  615. for (s = a.asi_name; *s; ++s) {
  616. *s = TOLOWER(*s);
  617. }
  618. }
  619. *asip = attr_syntax_dup(&a);
  620. #ifdef ENFORCE_MR_SYNTAX_COMPAT
  621. done:
  622. #endif /* ENFORCE_MR_SYNTAX_COMPAT */
  623. slapi_ch_free((void **)&a.asi_name);
  624. return rc;
  625. }
  626. /*
  627. * slapi_attr_type2plugin - return the plugin handling the attribute type
  628. * if type is unknown, we return the caseIgnoreString plugin used by the
  629. * objectClass attribute type.
  630. */
  631. int
  632. slapi_attr_type2plugin( const char *type, void **pi )
  633. {
  634. char buf[SLAPD_TYPICAL_ATTRIBUTE_NAME_MAX_LENGTH];
  635. char *tmp, *basetype;
  636. int rc;
  637. basetype = buf;
  638. if ( (tmp = slapi_attr_basetype( type, buf, sizeof(buf) )) != NULL ) {
  639. basetype = tmp;
  640. }
  641. rc = -1;
  642. *pi = attr_syntax_get_plugin_by_name_with_default( basetype );
  643. if ( NULL != *pi ) {
  644. rc = 0;
  645. }
  646. slapi_ch_free_string(&tmp);
  647. return( rc );
  648. }
  649. /* deprecated -- not MT safe (pointer into asi is returned!) */
  650. int
  651. slapi_attr_get_oid( const Slapi_Attr *a, char **oid )
  652. {
  653. struct asyntaxinfo *asi = attr_syntax_get_by_name(a->a_type);
  654. if (asi) {
  655. *oid = asi->asi_oid;
  656. attr_syntax_return(asi);
  657. return( 0 );
  658. } else {
  659. *oid = NULL;
  660. return( -1 );
  661. }
  662. }
  663. /* The caller must dispose of oid by calling slapi_ch_free(). */
  664. int
  665. slapi_attr_get_oid_copy( const Slapi_Attr *a, char **oidp )
  666. {
  667. struct asyntaxinfo *asi = attr_syntax_get_by_name(a->a_type);
  668. if (asi) {
  669. *oidp = slapi_ch_strdup( asi->asi_oid );
  670. attr_syntax_return(asi);
  671. return( 0 );
  672. } else {
  673. *oidp = NULL;
  674. return( -1 );
  675. }
  676. }
  677. /* Returns the oid of the syntax of the Slapi_Attr that's passed in.
  678. * The caller must dispose of oid by calling slapi_ch_free_string(). */
  679. int
  680. slapi_attr_get_syntax_oid_copy( const Slapi_Attr *a, char **oidp )
  681. {
  682. const char *oid;
  683. if (a && ((oid = attr_get_syntax_oid(a)))) {
  684. *oidp = slapi_ch_strdup(oid);
  685. return( 0 );
  686. } else {
  687. *oidp = NULL;
  688. return( -1 );
  689. }
  690. }
  691. int
  692. slapi_attr_is_dn_syntax_attr(Slapi_Attr *attr)
  693. {
  694. const char *syntaxoid = NULL;
  695. int dn_syntax = 0; /* not DN, by default */
  696. if (attr && attr->a_plugin) { /* If not set, there is no way to get the info */
  697. if ((syntaxoid = attr_get_syntax_oid(attr))) {
  698. dn_syntax = ((0 == strcmp(syntaxoid, NAMEANDOPTIONALUID_SYNTAX_OID))
  699. || (0 == strcmp(syntaxoid, DN_SYNTAX_OID)));
  700. }
  701. }
  702. return dn_syntax;
  703. }
  704. int
  705. slapi_attr_is_dn_syntax_type(char *type)
  706. {
  707. const char *syntaxoid = NULL;
  708. int dn_syntax = 0; /* not DN, by default */
  709. struct asyntaxinfo * asi;
  710. asi = attr_syntax_get_by_name(type);
  711. if (asi && asi->asi_plugin) { /* If not set, there is no way to get the info */
  712. if (syntaxoid = asi->asi_plugin->plg_syntax_oid) {
  713. dn_syntax = ((0 == strcmp(syntaxoid, NAMEANDOPTIONALUID_SYNTAX_OID))
  714. || (0 == strcmp(syntaxoid, DN_SYNTAX_OID)));
  715. }
  716. }
  717. return dn_syntax;
  718. }
  719. #ifdef ATTR_LDAP_DEBUG
  720. PRIntn
  721. attr_syntax_printnode(PLHashEntry *he, PRIntn i, void *arg)
  722. {
  723. char *alias = (char *)he->key;
  724. struct asyntaxinfo *a = (struct asyntaxinfo *)he->value;
  725. printf( " name: %s\n", a->asi_name );
  726. printf( "\t flags : 0x%x\n", a->asi_flags );
  727. printf( "\t alias : %s\n", alias );
  728. printf( "\t desc : %s\n", a->asi_desc );
  729. printf( "\t oid : %s\n", a->asi_oid );
  730. printf( "\t superior : %s\n", a->asi_superior );
  731. printf( "\t mr_equality : %s\n", a->asi_mr_equality );
  732. printf( "\t mr_ordering : %s\n", a->asi_mr_ordering );
  733. printf( "\t mr_substring: %s\n", a->asi_mr_substring );
  734. if ( NULL != a->asi_origin ) {
  735. for ( i = 0; NULL != a->asi_origin[i]; ++i ) {
  736. printf( "\t origin : %s\n", a->asi_origin[i] );
  737. }
  738. }
  739. printf( "\tplugin: %p\n", a->asi_plugin );
  740. printf( "--------------\n" );
  741. return HT_ENUMERATE_NEXT;
  742. }
  743. void
  744. attr_syntax_print()
  745. {
  746. printf( "*** attr_syntax_print ***\n" );
  747. PL_HashTableEnumerateEntries(name2asi, attr_syntax_printnode, 0);
  748. }
  749. #endif
  750. /* lowercase the attr name and chop trailing spaces */
  751. /* note that s may contain options also, e.g., userCertificate;binary */
  752. char *
  753. attr_syntax_normalize_no_lookup( const char *s )
  754. {
  755. char *save, *tmps;
  756. tmps = slapi_ch_strdup(s);
  757. for ( save = tmps; (*tmps != '\0') && (*tmps != ' '); tmps++ )
  758. {
  759. *tmps = TOLOWER( *tmps );
  760. }
  761. *tmps = '\0';
  762. return save;
  763. }
  764. struct enum_arg_wrapper {
  765. AttrEnumFunc aef;
  766. void *arg;
  767. };
  768. PRIntn
  769. attr_syntax_enumerate_internal(PLHashEntry *he, PRIntn i, void *arg)
  770. {
  771. struct enum_arg_wrapper *eaw = (struct enum_arg_wrapper *)arg;
  772. int rc;
  773. rc = (eaw->aef)((struct asyntaxinfo *)he->value, eaw->arg);
  774. if ( ATTR_SYNTAX_ENUM_STOP == rc ) {
  775. rc = HT_ENUMERATE_STOP;
  776. } else if ( ATTR_SYNTAX_ENUM_REMOVE == rc ) {
  777. rc = HT_ENUMERATE_REMOVE;
  778. } else {
  779. rc = HT_ENUMERATE_NEXT;
  780. }
  781. return rc;
  782. }
  783. static void
  784. attr_syntax_enumerate_attrs_ext( PLHashTable *ht,
  785. AttrEnumFunc aef, void *arg )
  786. {
  787. struct enum_arg_wrapper eaw;
  788. eaw.aef = aef;
  789. eaw.arg = arg;
  790. if (!ht)
  791. return;
  792. PL_HashTableEnumerateEntries(ht, attr_syntax_enumerate_internal, &eaw);
  793. }
  794. void
  795. attr_syntax_enumerate_attrs(AttrEnumFunc aef, void *arg, PRBool writelock )
  796. {
  797. if (!oid2asi)
  798. return;
  799. if ( writelock ) {
  800. AS_LOCK_WRITE(oid2asi_lock);
  801. AS_LOCK_WRITE(name2asi_lock);
  802. } else {
  803. AS_LOCK_READ(oid2asi_lock);
  804. AS_LOCK_READ(name2asi_lock);
  805. }
  806. attr_syntax_enumerate_attrs_ext(oid2asi, aef, arg);
  807. if ( writelock ) {
  808. AS_UNLOCK_WRITE(oid2asi_lock);
  809. AS_UNLOCK_WRITE(name2asi_lock);
  810. } else {
  811. AS_UNLOCK_READ(oid2asi_lock);
  812. AS_UNLOCK_READ(name2asi_lock);
  813. }
  814. }
  815. struct attr_syntax_enum_flaginfo {
  816. unsigned long asef_flag;
  817. };
  818. static int
  819. attr_syntax_clear_flag_callback(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. asip->asi_flags &= ~(fi->asef_flag);
  826. return ATTR_SYNTAX_ENUM_NEXT;
  827. }
  828. static int
  829. attr_syntax_delete_if_not_flagged(struct asyntaxinfo *asip, void *arg)
  830. {
  831. struct attr_syntax_enum_flaginfo *fi;
  832. PR_ASSERT( asip != NULL );
  833. fi = (struct attr_syntax_enum_flaginfo *)arg;
  834. PR_ASSERT( fi != NULL );
  835. if ( 0 == ( asip->asi_flags & fi->asef_flag )) {
  836. attr_syntax_delete_no_lock( asip, PR_FALSE );
  837. return ATTR_SYNTAX_ENUM_REMOVE;
  838. } else {
  839. return ATTR_SYNTAX_ENUM_NEXT;
  840. }
  841. }
  842. static int
  843. attr_syntax_force_to_delete(struct asyntaxinfo *asip, void *arg)
  844. {
  845. struct attr_syntax_enum_flaginfo *fi;
  846. PR_ASSERT( asip != NULL );
  847. fi = (struct attr_syntax_enum_flaginfo *)arg;
  848. PR_ASSERT( fi != NULL );
  849. attr_syntax_delete_no_lock( asip, PR_FALSE );
  850. return ATTR_SYNTAX_ENUM_REMOVE;
  851. }
  852. /*
  853. * Clear 'flag' within all attribute definitions.
  854. */
  855. void
  856. attr_syntax_all_clear_flag( unsigned long flag )
  857. {
  858. struct attr_syntax_enum_flaginfo fi;
  859. memset( &fi, 0, sizeof(fi));
  860. fi.asef_flag = flag;
  861. attr_syntax_enumerate_attrs( attr_syntax_clear_flag_callback,
  862. (void *)&fi, PR_TRUE );
  863. }
  864. /*
  865. * Delete all attribute definitions that do not contain any bits of 'flag'
  866. * in their flags.
  867. */
  868. void
  869. attr_syntax_delete_all_not_flagged( unsigned long flag )
  870. {
  871. struct attr_syntax_enum_flaginfo fi;
  872. memset( &fi, 0, sizeof(fi));
  873. fi.asef_flag = flag;
  874. attr_syntax_enumerate_attrs( attr_syntax_delete_if_not_flagged,
  875. (void *)&fi, PR_TRUE );
  876. }
  877. /*
  878. * Delete all attribute definitions
  879. */
  880. void
  881. attr_syntax_delete_all()
  882. {
  883. struct attr_syntax_enum_flaginfo fi;
  884. memset( &fi, 0, sizeof(fi));
  885. attr_syntax_enumerate_attrs( attr_syntax_force_to_delete,
  886. (void *)&fi, PR_TRUE );
  887. }
  888. static int
  889. attr_syntax_init(void)
  890. {
  891. if (!oid2asi)
  892. {
  893. oid2asi = PL_NewHashTable(2047, hashNocaseString,
  894. hashNocaseCompare,
  895. PL_CompareValues, 0, 0);
  896. if ( NULL == ( oid2asi_lock = slapi_new_rwlock())) {
  897. if(oid2asi) PL_HashTableDestroy(oid2asi);
  898. oid2asi = NULL;
  899. slapi_log_error( SLAPI_LOG_FATAL, "attr_syntax_init",
  900. "slapi_new_rwlock() for oid2asi lock failed\n" );
  901. return 1;
  902. }
  903. }
  904. if (!name2asi)
  905. {
  906. name2asi = PL_NewHashTable(2047, hashNocaseString,
  907. hashNocaseCompare,
  908. PL_CompareValues, 0, 0);
  909. if ( NULL == ( name2asi_lock = slapi_new_rwlock())) {
  910. if(name2asi) PL_HashTableDestroy(name2asi);
  911. name2asi = NULL;
  912. slapi_log_error( SLAPI_LOG_FATAL, "attr_syntax_init",
  913. "slapi_new_rwlock() for oid2asi lock failed\n" );
  914. return 1;
  915. }
  916. }
  917. return 0;
  918. }
  919. int
  920. slapi_attr_syntax_exists(const char *attr_name)
  921. {
  922. return attr_syntax_exists(attr_name);
  923. }
  924. /*
  925. * Keep the internally added schema in the hash table,
  926. * which are re-added if the schema is reloaded.
  927. */
  928. static int
  929. attr_syntax_internal_asi_add_ht(struct asyntaxinfo *asip)
  930. {
  931. if (!internalasi) {
  932. internalasi = PL_NewHashTable(64, hashNocaseString,
  933. hashNocaseCompare,
  934. PL_CompareValues, 0, 0);
  935. }
  936. if (!internalasi) {
  937. slapi_log_error(SLAPI_LOG_FATAL, "attr_syntax_internal_asi_add_ht",
  938. "Failed to create HashTable.\n");
  939. return 1;
  940. }
  941. if (!PL_HashTableLookup(internalasi, asip->asi_oid)) {
  942. struct asyntaxinfo *asip_copy = attr_syntax_dup(asip);
  943. if (!asip_copy) {
  944. slapi_log_error(SLAPI_LOG_FATAL, "attr_syntax_internal_asi_add_ht",
  945. "Failed to duplicate asyntaxinfo: %s.\n",
  946. asip->asi_name);
  947. return 1;
  948. }
  949. PL_HashTableAdd(internalasi, asip_copy->asi_oid, asip_copy);
  950. }
  951. return 0;
  952. }
  953. /*
  954. * Add an attribute syntax using some default flags, etc.
  955. * Returns an LDAP error code (LDAP_SUCCESS if all goes well)
  956. */
  957. int
  958. slapi_add_internal_attr_syntax( const char *name, const char *oid,
  959. const char *syntax, const char *mr_equality, unsigned long extraflags )
  960. {
  961. int rc = LDAP_SUCCESS;
  962. struct asyntaxinfo *asip;
  963. char *names[2];
  964. char *origins[2];
  965. unsigned long std_flags = SLAPI_ATTR_FLAG_STD_ATTR | SLAPI_ATTR_FLAG_OPATTR;
  966. names[0] = (char *)name;
  967. names[1] = NULL;
  968. origins[0] = SLAPD_VERSION_STR;
  969. origins[1] = NULL;
  970. rc = attr_syntax_create( oid, names, 1,
  971. "internal server defined attribute type",
  972. NULL, /* superior */
  973. mr_equality, NULL, NULL, /* matching rules */
  974. origins, syntax,
  975. SLAPI_SYNTAXLENGTH_NONE,
  976. std_flags | extraflags,
  977. &asip );
  978. if ( rc == LDAP_SUCCESS ) {
  979. rc = attr_syntax_add( asip );
  980. if ( rc == LDAP_SUCCESS ) {
  981. if (attr_syntax_internal_asi_add_ht(asip)) {
  982. slapi_log_error(SLAPI_LOG_FATAL,
  983. "slapi_add_internal_attr_syntax",
  984. "Failed to stash internal asyntaxinfo: %s.\n",
  985. asip->asi_name);
  986. }
  987. }
  988. }
  989. return rc;
  990. }
  991. /* Adding internal asyncinfo via slapi_reload_internal_attr_syntax */
  992. static int
  993. attr_syntax_internal_asi_add(struct asyntaxinfo *asip, void *arg)
  994. {
  995. struct asyntaxinfo *asip_copy;
  996. if (!asip) {
  997. return 1;
  998. }
  999. /* Copy is needed since when reloading the schema,
  1000. * existing syntax info is cleaned up. */
  1001. asip_copy = attr_syntax_dup(asip);
  1002. return attr_syntax_add(asip_copy);
  1003. }
  1004. /* Reload internal attribute syntax stashed in the internalasi hashtable. */
  1005. int
  1006. slapi_reload_internal_attr_syntax()
  1007. {
  1008. int rc = LDAP_SUCCESS;
  1009. if (!internalasi) {
  1010. slapi_log_error(SLAPI_LOG_TRACE, "attr_reload_internal_attr_syntax",
  1011. "No internal attribute syntax to reload.\n");
  1012. return rc;
  1013. }
  1014. attr_syntax_enumerate_attrs_ext(internalasi, attr_syntax_internal_asi_add, NULL);
  1015. return rc;
  1016. }