attrsyntax.c 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505
  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. static int asi_locking = 1;
  65. #define AS_LOCK_READ(l) if (asi_locking) { slapi_rwlock_rdlock(l); }
  66. #define AS_LOCK_WRITE(l) if (asi_locking) { slapi_rwlock_wrlock(l); }
  67. #define AS_UNLOCK_READ(l) if (asi_locking) { slapi_rwlock_unlock(l); }
  68. #define AS_UNLOCK_WRITE(l) if (asi_locking) { slapi_rwlock_unlock(l); }
  69. static struct asyntaxinfo *default_asi = NULL;
  70. static void *attr_syntax_get_plugin_by_name_with_default( const char *type );
  71. static void attr_syntax_delete_no_lock( struct asyntaxinfo *asip,
  72. PRBool remove_from_oid_table );
  73. static struct asyntaxinfo *attr_syntax_get_by_oid_locking_optional( const
  74. char *oid, PRBool use_lock);
  75. #ifdef ATTR_LDAP_DEBUG
  76. static void attr_syntax_print();
  77. #endif
  78. static int attr_syntax_init(void);
  79. void
  80. attr_syntax_read_lock(void)
  81. {
  82. if (0 != attr_syntax_init()) return;
  83. AS_LOCK_READ(oid2asi_lock);
  84. AS_LOCK_READ(name2asi_lock);
  85. }
  86. void
  87. attr_syntax_write_lock(void)
  88. {
  89. if (0 != attr_syntax_init()) return;
  90. AS_LOCK_WRITE(oid2asi_lock);
  91. AS_LOCK_WRITE(name2asi_lock);
  92. }
  93. void
  94. attr_syntax_unlock_read(void)
  95. {
  96. AS_UNLOCK_READ(name2asi_lock);
  97. AS_UNLOCK_READ(oid2asi_lock);
  98. }
  99. void
  100. attr_syntax_unlock_write(void)
  101. {
  102. AS_UNLOCK_WRITE(name2asi_lock);
  103. AS_UNLOCK_WRITE(oid2asi_lock);
  104. }
  105. #if 0
  106. static int
  107. check_oid( const char *oid ) {
  108. int i = 0, length_oid = 0, rc = 0;
  109. if ( oid == NULL) {
  110. /* this is bad */
  111. LDAPDebug (LDAP_DEBUG_ANY, "NULL passed to check_oid\n",0,0,0);
  112. return 0;
  113. }
  114. length_oid = strlen(oid);
  115. if (length_oid < 4) {
  116. /* this is probably bad */
  117. LDAPDebug (LDAP_DEBUG_ANY, "Bad oid %s passed to check_oid\n",oid,0,0);
  118. return 0;
  119. }
  120. rc = strcasecmp(oid+(length_oid-4), "-oid");
  121. if ( 0 == rc ) {
  122. return 1;
  123. }
  124. /* If not, the OID must begin and end with a digit, and contain only
  125. digits and dots */
  126. if ( !isdigit(oid[0]) ||
  127. !isdigit(oid[length_oid-1]) ) {
  128. LDAPDebug (LDAP_DEBUG_ANY, "Non numeric oid %s passed to check_oid\n",oid,0,0);
  129. return 0;
  130. }
  131. /* check to see that it contains only digits and dots */
  132. for ( i = 0; i < length_oid; i++ ) {
  133. if ( !isdigit(oid[i]) && oid[i] != '.' ){
  134. LDAPDebug (LDAP_DEBUG_ANY, "Non numeric oid %s passed to check_oid\n",oid,0,0);
  135. return 0;
  136. }
  137. }
  138. /* The oid is OK if we're here */
  139. return 1;
  140. }
  141. #endif
  142. #define NBUCKETS(ht) (1 << (PL_HASH_BITS - (ht)->shift))
  143. #if 0
  144. static int
  145. attr_syntax_check_oids()
  146. {
  147. int ii = 0;
  148. int nbad = 0;
  149. AS_LOCK_READ(oid2asi_lock);
  150. ii = NBUCKETS(oid2asi);
  151. for (;ii;--ii) {
  152. PLHashEntry *he = oid2asi->buckets[ii-1];
  153. for (; he; he = he->next) {
  154. if (!check_oid(he->key)) {
  155. LDAPDebug(LDAP_DEBUG_ANY, "Error: bad oid %s in bucket %d\n",
  156. he->key, ii-1, 0);
  157. nbad++;
  158. }
  159. }
  160. }
  161. AS_UNLOCK_READ(oid2asi_lock);
  162. return nbad;
  163. }
  164. #endif
  165. void
  166. attr_syntax_free( struct asyntaxinfo *a )
  167. {
  168. PR_ASSERT( a->asi_refcnt == 0 );
  169. cool_charray_free( a->asi_aliases );
  170. slapi_ch_free( (void**)&a->asi_name );
  171. slapi_ch_free( (void **)&a->asi_desc );
  172. slapi_ch_free( (void **)&a->asi_oid );
  173. slapi_ch_free( (void **)&a->asi_superior );
  174. slapi_ch_free( (void **)&a->asi_mr_equality );
  175. slapi_ch_free( (void **)&a->asi_mr_ordering );
  176. slapi_ch_free( (void **)&a->asi_mr_substring );
  177. schema_free_extensions(a->asi_extensions);
  178. slapi_ch_free( (void **) &a );
  179. }
  180. static struct asyntaxinfo *
  181. attr_syntax_new()
  182. {
  183. return (struct asyntaxinfo *)slapi_ch_calloc(1, sizeof(struct asyntaxinfo));
  184. }
  185. /*
  186. * Given an OID, return the syntax info. If there is more than one
  187. * attribute syntax with the same OID (i.e. aliases), the first one
  188. * will be returned. This is usually the "canonical" one, but it may
  189. * not be.
  190. *
  191. * Note: once the caller is finished using it, the structure returned must
  192. * be returned by calling to attr_syntax_return().
  193. */
  194. struct asyntaxinfo *
  195. attr_syntax_get_by_oid(const char *oid)
  196. {
  197. return attr_syntax_get_by_oid_locking_optional( oid, PR_TRUE);
  198. }
  199. /*
  200. * A version of attr_syntax_get_by_oid() that allows you to bypass using
  201. * a lock to access the global oid hash table.
  202. *
  203. * Note: once the caller is finished using it, the structure must be
  204. * returned by calling attr_syntax_return_locking_optional() with the
  205. * same use_lock parameter.
  206. */
  207. static struct asyntaxinfo *
  208. attr_syntax_get_by_oid_locking_optional( const char *oid, PRBool use_lock )
  209. {
  210. struct asyntaxinfo *asi = 0;
  211. if (oid2asi)
  212. {
  213. if ( use_lock ) {
  214. AS_LOCK_READ(oid2asi_lock);
  215. }
  216. asi = (struct asyntaxinfo *)PL_HashTableLookup_const(oid2asi, oid);
  217. if (asi)
  218. {
  219. PR_AtomicIncrement( &asi->asi_refcnt );
  220. }
  221. if ( use_lock ) {
  222. AS_UNLOCK_READ(oid2asi_lock);
  223. }
  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. }
  241. PL_HashTableAdd(oid2asi, oid, a);
  242. if (lock) {
  243. AS_UNLOCK_WRITE(oid2asi_lock);
  244. }
  245. }
  246. /*
  247. * Return the syntax info given an attribute name. The name may be the
  248. * "canonical" name, an alias, or an OID. The given name need not be
  249. * normalized since the look up is done case insensitively.
  250. *
  251. * Note: once the caller is finished using it, the structure returned must
  252. * be returned by calling to attr_syntax_return().
  253. */
  254. struct asyntaxinfo *
  255. attr_syntax_get_by_name(const char *name)
  256. {
  257. return attr_syntax_get_by_name_locking_optional(name, PR_TRUE);
  258. }
  259. struct asyntaxinfo *
  260. attr_syntax_get_by_name_with_default(const char *name)
  261. {
  262. struct asyntaxinfo *asi = NULL;
  263. asi = attr_syntax_get_by_name_locking_optional(name, PR_TRUE);
  264. if (asi == NULL)
  265. asi = attr_syntax_get_by_name(ATTR_WITH_OCTETSTRING_SYNTAX);
  266. if ( asi == NULL )
  267. asi = default_asi;
  268. return asi;
  269. }
  270. /*
  271. * A version of attr_syntax_get_by_name() that allows you to bypass using
  272. * a lock around the global name hashtable.
  273. *
  274. * Note: once the caller is finished using it, the structure must be
  275. * returned by calling attr_syntax_return_locking_optional() with the
  276. * same use_lock parameter.
  277. */
  278. struct asyntaxinfo *
  279. attr_syntax_get_by_name_locking_optional(const char *name, PRBool use_lock)
  280. {
  281. struct asyntaxinfo *asi = 0;
  282. if (name2asi)
  283. {
  284. if ( use_lock ) {
  285. AS_LOCK_READ(name2asi_lock);
  286. }
  287. asi = (struct asyntaxinfo *)PL_HashTableLookup_const(name2asi, name);
  288. if ( NULL != asi ) {
  289. PR_AtomicIncrement( &asi->asi_refcnt );
  290. }
  291. if ( use_lock ) {
  292. AS_UNLOCK_READ(name2asi_lock);
  293. }
  294. }
  295. if (!asi) /* given name may be an OID */
  296. asi = attr_syntax_get_by_oid_locking_optional(name, use_lock);
  297. return asi;
  298. }
  299. /*
  300. * Give up a reference to an asi.
  301. * If the asi has been marked for delete, free it. This would be a bit
  302. * easier if we could upgrade a read lock to a write one... but NSPR does
  303. * not support that paradigm.
  304. */
  305. void
  306. attr_syntax_return( struct asyntaxinfo *asi )
  307. {
  308. attr_syntax_return_locking_optional( asi, PR_TRUE );
  309. }
  310. void
  311. attr_syntax_return_locking_optional(struct asyntaxinfo *asi, PRBool use_lock)
  312. {
  313. int locked = 0;
  314. if(use_lock) {
  315. AS_LOCK_READ(name2asi_lock);
  316. locked = 1;
  317. }
  318. if ( NULL != asi ) {
  319. PRBool delete_it = PR_FALSE;
  320. if ( 0 == PR_AtomicDecrement( &asi->asi_refcnt )) {
  321. delete_it = asi->asi_marked_for_delete;
  322. }
  323. if (delete_it) {
  324. if ( asi->asi_marked_for_delete ) { /* one final check */
  325. if(use_lock) {
  326. AS_UNLOCK_READ(name2asi_lock);
  327. AS_LOCK_WRITE(name2asi_lock);
  328. }
  329. /* ref count is 0 and it's flagged for
  330. * deletion, so it's safe to free now */
  331. attr_syntax_free(asi);
  332. if(use_lock) {
  333. AS_UNLOCK_WRITE(name2asi_lock);
  334. locked = 0;
  335. }
  336. }
  337. }
  338. }
  339. if(locked) {
  340. AS_UNLOCK_READ(name2asi_lock);
  341. }
  342. }
  343. /*
  344. * Add the syntax info to the look-up-by-name table. The asi_name and
  345. * elements of the asi_aliasses field of the syntax info are the keys.
  346. * These need not be normalized since the look up table is case insensitive.
  347. * The lock parameter is used by the initialization code. Normally, we want
  348. * to acquire a write lock before we modify the table, but during
  349. * initialization, we are running in single threaded mode, so we don't have
  350. * to worry about resource contention.
  351. */
  352. static void
  353. attr_syntax_add_by_name(struct asyntaxinfo *a, int lock)
  354. {
  355. if (0 != attr_syntax_init()) return;
  356. if (lock) {
  357. AS_LOCK_WRITE(name2asi_lock);
  358. }
  359. PL_HashTableAdd(name2asi, a->asi_name, a);
  360. if ( a->asi_aliases != NULL ) {
  361. int i;
  362. for ( i = 0; a->asi_aliases[i] != NULL; ++i ) {
  363. PL_HashTableAdd(name2asi, a->asi_aliases[i], a);
  364. }
  365. }
  366. if (lock) {
  367. AS_UNLOCK_WRITE(name2asi_lock);
  368. }
  369. }
  370. /*
  371. * Delete the attribute syntax and all entries corresponding to aliases
  372. * and oids.
  373. */
  374. void
  375. attr_syntax_delete( struct asyntaxinfo *asi )
  376. {
  377. PR_ASSERT( asi );
  378. if (oid2asi && name2asi) {
  379. AS_LOCK_WRITE(oid2asi_lock);
  380. AS_LOCK_WRITE(name2asi_lock);
  381. attr_syntax_delete_no_lock( asi, PR_TRUE );
  382. AS_UNLOCK_WRITE(name2asi_lock);
  383. AS_UNLOCK_WRITE(oid2asi_lock);
  384. }
  385. }
  386. /*
  387. * Dispose of a node. The caller is responsible for locking. See
  388. * attr_syntax_delete() for an example.
  389. */
  390. static void
  391. attr_syntax_delete_no_lock( struct asyntaxinfo *asi,
  392. PRBool remove_from_oidtable )
  393. {
  394. int i;
  395. if (oid2asi && remove_from_oidtable ) {
  396. PL_HashTableRemove(oid2asi, asi->asi_oid);
  397. }
  398. if(name2asi) {
  399. PL_HashTableRemove(name2asi, asi->asi_name);
  400. if ( asi->asi_aliases != NULL ) {
  401. for ( i = 0; asi->asi_aliases[i] != NULL; ++i ) {
  402. PL_HashTableRemove(name2asi, asi->asi_aliases[i]);
  403. }
  404. }
  405. if ( asi->asi_refcnt > 0 ) {
  406. asi->asi_marked_for_delete = PR_TRUE;
  407. } else {
  408. /* This is ok, but the correct thing is to call delete first,
  409. * then to call return. The last return will then take care of
  410. * the free. The only way this free would happen here is if
  411. * you return the syntax before calling delete. */
  412. attr_syntax_free(asi);
  413. }
  414. }
  415. }
  416. /*
  417. * Look up the attribute type in the syntaxes and return a copy of the
  418. * normalised attribute type. If it's not there then return a normalised
  419. * copy of what the caller gave us.
  420. *
  421. * Warning: The caller must free the returned string.
  422. */
  423. char *
  424. slapi_attr_syntax_normalize( const char *s )
  425. {
  426. struct asyntaxinfo *asi = NULL;
  427. char *r = NULL;
  428. if((asi=attr_syntax_get_by_name(s)) != NULL ) {
  429. r = slapi_ch_strdup(asi->asi_name);
  430. attr_syntax_return( asi );
  431. }
  432. if ( NULL == asi ) {
  433. slapi_ch_free_string( &r );
  434. r = attr_syntax_normalize_no_lookup( s );
  435. }
  436. return r;
  437. }
  438. /*
  439. * flags:
  440. * 0 -- same as slapi_attr_syntax_normalize
  441. * ATTR_SYNTAX_NORM_ORIG_ATTR -- In addition to slapi_attr_syntax_normalize,
  442. * a space and following characters are removed
  443. * from the given string 's'.
  444. */
  445. char *
  446. slapi_attr_syntax_normalize_ext( char *s, int flags )
  447. {
  448. struct asyntaxinfo *asi = NULL;
  449. char *r = NULL;
  450. if((asi=attr_syntax_get_by_name(s)) != NULL ) {
  451. r = slapi_ch_strdup(asi->asi_name);
  452. attr_syntax_return( asi );
  453. }
  454. if ( NULL == asi ) {
  455. slapi_ch_free_string( &r );
  456. r = attr_syntax_normalize_no_lookup_ext( s, flags );
  457. }
  458. return r;
  459. }
  460. /*
  461. * attr_syntax_exists: return 1 if attr_name exists, 0 otherwise
  462. *
  463. */
  464. int
  465. attr_syntax_exists(const char *attr_name)
  466. {
  467. struct asyntaxinfo *asi;
  468. char *check_attr_name = NULL;
  469. char *p = NULL;
  470. int free_attr = 0;
  471. /* Ignore any attribute subtypes. */
  472. if ((p = strchr(attr_name, ';'))) {
  473. int check_attr_len = p - attr_name + 1;
  474. check_attr_name = (char *)slapi_ch_malloc(check_attr_len);
  475. PR_snprintf(check_attr_name, check_attr_len, "%s", attr_name);
  476. free_attr = 1;
  477. } else {
  478. check_attr_name = (char *)attr_name;
  479. }
  480. asi = attr_syntax_get_by_name(check_attr_name);
  481. attr_syntax_return( asi );
  482. if (free_attr) {
  483. slapi_ch_free_string(&check_attr_name);
  484. }
  485. if ( asi != NULL )
  486. {
  487. return 1;
  488. }
  489. return 0;
  490. }
  491. static void default_dirstring_normalize_int(char *s, int trim_spaces);
  492. static
  493. int default_dirstring_filter_ava( struct berval *bvfilter, Slapi_Value **bvals,int ftype, Slapi_Value **retVal )
  494. {
  495. return(0);
  496. }
  497. static
  498. int default_dirstring_values2keys( Slapi_PBlock *pb, Slapi_Value **bvals,Slapi_Value ***ivals, int ftype )
  499. {
  500. int numbvals = 0;
  501. Slapi_Value **nbvals, **nbvlp;
  502. Slapi_Value **bvlp;
  503. char *c;
  504. if (NULL == ivals) {
  505. return 1;
  506. }
  507. *ivals = NULL;
  508. if (NULL == bvals) {
  509. return 1;
  510. }
  511. switch ( ftype ) {
  512. case LDAP_FILTER_EQUALITY:
  513. /* allocate a new array for the normalized values */
  514. for ( bvlp = bvals; bvlp && *bvlp; bvlp++ ) {
  515. numbvals++;
  516. }
  517. nbvals = (Slapi_Value **) slapi_ch_calloc( (numbvals + 1), sizeof(Slapi_Value *));
  518. for ( bvlp = bvals, nbvlp = nbvals; bvlp && *bvlp; bvlp++, nbvlp++ ) {
  519. c = slapi_ch_strdup(slapi_value_get_string(*bvlp));
  520. default_dirstring_normalize_int( c, 1 );
  521. *nbvlp = slapi_value_new_string_passin(c);
  522. c = NULL;
  523. }
  524. *ivals = nbvals;
  525. break;
  526. case LDAP_FILTER_APPROX:
  527. case LDAP_FILTER_SUBSTRINGS:
  528. default:
  529. /* default plugin only handles equality so far */
  530. LDAPDebug( LDAP_DEBUG_ANY,
  531. "default_dirstring_values2keys: unsupported ftype 0x%x\n",
  532. ftype, 0, 0 );
  533. break;
  534. }
  535. return(0);
  536. }
  537. static
  538. int default_dirstring_assertion2keys_ava(Slapi_PBlock *pb,Slapi_Value *val,Slapi_Value ***ivals,int ftype )
  539. {
  540. return(0);
  541. }
  542. static
  543. int default_dirstring_cmp(struct berval *v1,struct berval *v2, int normalize)
  544. {
  545. return(0);
  546. }
  547. static
  548. void default_dirstring_normalize(Slapi_PBlock *pb, char *s, int trim_spaces, char **alt)
  549. {
  550. default_dirstring_normalize_int(s, trim_spaces);
  551. }
  552. static
  553. void default_dirstring_normalize_int(char *s, int trim_spaces)
  554. {
  555. char *head = s;
  556. char *d;
  557. int prevspace, curspace;
  558. if (NULL == s) {
  559. return;
  560. }
  561. d = s;
  562. if (trim_spaces) {
  563. /* strip leading blanks */
  564. while (ldap_utf8isspace(s)) {
  565. LDAP_UTF8INC(s);
  566. }
  567. }
  568. /* handle value of all spaces - turn into single space */
  569. if ( *s == '\0' && s != d ) {
  570. *d++ = ' ';
  571. *d = '\0';
  572. return;
  573. }
  574. prevspace = 0;
  575. while ( *s ) {
  576. int ssz, dsz;
  577. curspace = ldap_utf8isspace(s);
  578. /* compress multiple blanks */
  579. if ( prevspace && curspace ) {
  580. LDAP_UTF8INC(s);
  581. continue;
  582. }
  583. prevspace = curspace;
  584. slapi_utf8ToLower((unsigned char*)s, (unsigned char *)d, &ssz, &dsz);
  585. s += ssz;
  586. d += dsz;
  587. }
  588. *d = '\0';
  589. /* strip trailing blanks */
  590. if (prevspace && trim_spaces) {
  591. char *nd;
  592. nd = ldap_utf8prev(d);
  593. while (nd && nd >= head && ldap_utf8isspace(nd)) {
  594. d = nd;
  595. nd = ldap_utf8prev(d);
  596. *d = '\0';
  597. }
  598. }
  599. }
  600. static struct slapdplugin *
  601. attr_syntax_default_plugin ( const char *nameoroid )
  602. {
  603. struct slapdplugin *pi = NULL;
  604. /*
  605. * create a new plugin structure and
  606. * set the plugin function pointers.
  607. */
  608. pi = (struct slapdplugin *)slapi_ch_calloc(1, sizeof(struct slapdplugin));
  609. pi->plg_dn = slapi_ch_strdup("default plugin for directory string syntax");
  610. pi->plg_closed = 0;
  611. pi->plg_syntax_oid = slapi_ch_strdup(nameoroid);
  612. pi->plg_syntax_filter_ava = (IFP) default_dirstring_filter_ava;
  613. pi->plg_syntax_values2keys = (IFP) default_dirstring_values2keys;
  614. pi->plg_syntax_assertion2keys_ava = (IFP) default_dirstring_assertion2keys_ava;
  615. pi->plg_syntax_compare = (IFP) default_dirstring_cmp;
  616. pi->plg_syntax_normalize = (VFPV) default_dirstring_normalize;
  617. return (pi);
  618. }
  619. /* check syntax */
  620. static void *
  621. attr_syntax_get_plugin_by_name_with_default( const char *type )
  622. {
  623. struct asyntaxinfo *asi;
  624. void *plugin = NULL;
  625. /*
  626. * first we look for this attribute type explictly
  627. */
  628. if ( (asi = attr_syntax_get_by_name(type)) == NULL ) {
  629. /*
  630. * no syntax for this type... return Octet String
  631. * syntax. we accomplish this by looking up a well known
  632. * attribute type that has that syntax.
  633. */
  634. asi = attr_syntax_get_by_name(ATTR_WITH_OCTETSTRING_SYNTAX);
  635. if (asi == NULL)
  636. asi = default_asi;
  637. }
  638. if ( NULL != asi ) {
  639. plugin = asi->asi_plugin;
  640. attr_syntax_return( asi );
  641. }
  642. return( plugin );
  643. }
  644. static struct asyntaxinfo *
  645. attr_syntax_dup( struct asyntaxinfo *a )
  646. {
  647. struct asyntaxinfo *newas = attr_syntax_new();
  648. newas->asi_aliases = cool_charray_dup( a->asi_aliases );
  649. newas->asi_name = slapi_ch_strdup( a->asi_name );
  650. newas->asi_desc = slapi_ch_strdup( a->asi_desc );
  651. newas->asi_superior = slapi_ch_strdup( a->asi_superior );
  652. newas->asi_mr_equality = slapi_ch_strdup( a->asi_mr_equality );
  653. newas->asi_mr_ordering = slapi_ch_strdup( a->asi_mr_ordering );
  654. newas->asi_mr_substring = slapi_ch_strdup( a->asi_mr_substring );
  655. newas->asi_extensions = schema_copy_extensions( a->asi_extensions );
  656. newas->asi_plugin = a->asi_plugin;
  657. newas->asi_flags = a->asi_flags;
  658. newas->asi_oid = slapi_ch_strdup( a->asi_oid);
  659. newas->asi_syntaxlength = a->asi_syntaxlength;
  660. newas->asi_mr_eq_plugin = a->asi_mr_eq_plugin;
  661. newas->asi_mr_ord_plugin = a->asi_mr_ord_plugin;
  662. newas->asi_mr_sub_plugin = a->asi_mr_sub_plugin;
  663. return( newas );
  664. }
  665. /*
  666. * Add a new attribute type to the schema.
  667. *
  668. * Returns an LDAP error code (LDAP_SUCCESS if all goes well).
  669. */
  670. int
  671. attr_syntax_add( struct asyntaxinfo *asip )
  672. {
  673. int i, rc = LDAP_SUCCESS;
  674. int nolock = asip->asi_flags & SLAPI_ATTR_FLAG_NOLOCKING;
  675. struct asyntaxinfo *oldas_from_oid = NULL, *oldas_from_name = NULL;
  676. /* attr names may have subtypes in them, and we may not want this
  677. if strip_subtypes is true, the ; and anything after it in the
  678. attr name or alias will be stripped */
  679. /*int strip_subtypes = 1;*/
  680. /* make sure the oid is unique */
  681. if ( NULL != ( oldas_from_oid = attr_syntax_get_by_oid_locking_optional(
  682. asip->asi_oid, !nolock))) {
  683. if ( 0 == (asip->asi_flags & SLAPI_ATTR_FLAG_OVERRIDE)) {
  684. /* failure - OID is in use; no override flag */
  685. rc = LDAP_TYPE_OR_VALUE_EXISTS;
  686. goto cleanup_and_return;
  687. }
  688. }
  689. /*
  690. * Make sure the primary name is unique OR, if override is allowed, that
  691. * the primary name and OID point to the same schema definition.
  692. */
  693. if ( NULL != ( oldas_from_name = attr_syntax_get_by_name_locking_optional(
  694. asip->asi_name, !nolock))) {
  695. if ( 0 == (asip->asi_flags & SLAPI_ATTR_FLAG_OVERRIDE)
  696. || ( oldas_from_oid != oldas_from_name )) {
  697. /* failure; no override flag OR OID and name don't match */
  698. rc = LDAP_TYPE_OR_VALUE_EXISTS;
  699. goto cleanup_and_return;
  700. }
  701. /* Flag for deletion. We are going to override this attr */
  702. attr_syntax_delete(oldas_from_name);
  703. } else if ( NULL != oldas_from_oid ) {
  704. /* failure - OID is in use but name does not exist */
  705. rc = LDAP_TYPE_OR_VALUE_EXISTS;
  706. goto cleanup_and_return;
  707. }
  708. if ( NULL != asip->asi_aliases ) {
  709. /* make sure the aliases are unique */
  710. for (i = 0; asip->asi_aliases[i] != NULL; ++i) {
  711. struct asyntaxinfo *tmpasi;
  712. if ( NULL != ( tmpasi =
  713. attr_syntax_get_by_name_locking_optional(
  714. asip->asi_aliases[i], !nolock))) {
  715. if (asip->asi_flags & SLAPI_ATTR_FLAG_OVERRIDE) {
  716. /* Flag for tmpasi for deletion. It will be free'd
  717. * when attr_syntax_return is called. */
  718. attr_syntax_delete(tmpasi);
  719. } else {
  720. /* failure - one of the aliases is already in use */
  721. rc = LDAP_TYPE_OR_VALUE_EXISTS;
  722. }
  723. attr_syntax_return_locking_optional( tmpasi, !nolock );
  724. if ( LDAP_SUCCESS != rc ) {
  725. goto cleanup_and_return;
  726. }
  727. }
  728. }
  729. }
  730. /* the no lock flag is not worth keeping around */
  731. asip->asi_flags &= ~SLAPI_ATTR_FLAG_NOLOCKING;
  732. /* ditto for the override one */
  733. asip->asi_flags &= ~SLAPI_ATTR_FLAG_OVERRIDE;
  734. attr_syntax_add_by_oid( asip->asi_oid, asip, !nolock);
  735. attr_syntax_add_by_name( asip, !nolock);
  736. cleanup_and_return:
  737. attr_syntax_return_locking_optional( oldas_from_oid, !nolock );
  738. attr_syntax_return_locking_optional( oldas_from_name, !nolock );
  739. return rc;
  740. }
  741. static int
  742. attr_syntax_create_default( const char *name, const char *oid,
  743. const char *syntax, unsigned long extraflags )
  744. {
  745. int rc = 0;
  746. char *names[2];
  747. unsigned long std_flags = SLAPI_ATTR_FLAG_STD_ATTR | SLAPI_ATTR_FLAG_OPATTR;
  748. names[0] = (char *)name;
  749. names[1] = NULL;
  750. if (default_asi)
  751. return (rc);
  752. rc = attr_syntax_create( oid, names,
  753. "internal server defined attribute type",
  754. NULL, /* superior */
  755. NULL, NULL, NULL, /* matching rules */
  756. NULL, syntax,
  757. SLAPI_SYNTAXLENGTH_NONE,
  758. std_flags | extraflags,
  759. &default_asi );
  760. if ( rc == 0 && default_asi->asi_plugin == 0)
  761. default_asi->asi_plugin = attr_syntax_default_plugin (syntax );
  762. return (rc);
  763. }
  764. /*
  765. * Returns an LDAP result code.
  766. */
  767. int
  768. attr_syntax_create(
  769. const char *attr_oid,
  770. char *const *attr_names,
  771. const char *attr_desc,
  772. const char *attr_superior,
  773. const char *mr_equality,
  774. const char *mr_ordering,
  775. const char *mr_substring,
  776. schemaext *extensions,
  777. const char *attr_syntax,
  778. int syntaxlength,
  779. unsigned long flags,
  780. struct asyntaxinfo **asip
  781. )
  782. {
  783. char *s;
  784. struct asyntaxinfo a;
  785. int rc = LDAP_SUCCESS;
  786. /* XXXmcs: had to cast away const in many places below */
  787. memset(&a, 0, sizeof(a));
  788. *asip = NULL;
  789. a.asi_name = slapi_ch_strdup(attr_names[0]);
  790. if ( NULL != attr_names[1] ) {
  791. a.asi_aliases = (char **)&attr_names[1]; /* all but the zero'th element */
  792. }
  793. a.asi_desc = (char*)attr_desc;
  794. a.asi_oid = (char*)attr_oid;
  795. a.asi_superior = (char*)attr_superior;
  796. a.asi_mr_equality = (char*)mr_equality;
  797. a.asi_mr_ordering = (char*)mr_ordering;
  798. a.asi_mr_substring = (char*)mr_substring;
  799. a.asi_extensions = extensions;
  800. a.asi_plugin = plugin_syntax_find( attr_syntax );
  801. a.asi_syntaxlength = syntaxlength;
  802. /* ideally, we would report an error and fail to start if there was some problem
  803. with the matching rule - but since this functionality is new, and we might
  804. cause havoc if lots of servers failed to start because of bogus schema, we
  805. just report an error here - at some point in the future, we should actually
  806. report an error and exit, or allow the user to control the behavior - for
  807. now, just log an error, and address each case
  808. */
  809. if (mr_equality && !slapi_matchingrule_is_compat(mr_equality, attr_syntax)) {
  810. slapi_log_error(SLAPI_LOG_FATAL, "attr_syntax_create",
  811. "Error: the EQUALITY matching rule [%s] is not compatible "
  812. "with the syntax [%s] for the attribute [%s]\n",
  813. mr_equality, attr_syntax, attr_names[0]);
  814. #ifdef ENFORCE_MR_SYNTAX_COMPAT
  815. rc = LDAP_INAPPROPRIATE_MATCHING;
  816. goto done;
  817. #endif /* ENFORCE_MR_SYNTAX_COMPAT */
  818. }
  819. a.asi_mr_eq_plugin = plugin_mr_find( mr_equality );
  820. if (mr_ordering && !slapi_matchingrule_is_compat(mr_ordering, attr_syntax)) {
  821. slapi_log_error(SLAPI_LOG_FATAL, "attr_syntax_create",
  822. "Error: the ORDERING matching rule [%s] is not compatible "
  823. "with the syntax [%s] for the attribute [%s]\n",
  824. mr_ordering, attr_syntax, attr_names[0]);
  825. #ifdef ENFORCE_MR_SYNTAX_COMPAT
  826. rc = LDAP_INAPPROPRIATE_MATCHING;
  827. goto done;
  828. #endif /* ENFORCE_MR_SYNTAX_COMPAT */
  829. }
  830. a.asi_mr_ord_plugin = plugin_mr_find( mr_ordering );
  831. if (mr_substring && !slapi_matchingrule_is_compat(mr_substring, attr_syntax)) {
  832. slapi_log_error(SLAPI_LOG_FATAL, "attr_syntax_create",
  833. "Error: the SUBSTR matching rule [%s] is not compatible "
  834. "with the syntax [%s] for the attribute [%s]\n",
  835. mr_substring, attr_syntax, attr_names[0]);
  836. #ifdef ENFORCE_MR_SYNTAX_COMPAT
  837. rc = LDAP_INAPPROPRIATE_MATCHING;
  838. goto done;
  839. #endif /* ENFORCE_MR_SYNTAX_COMPAT */
  840. }
  841. a.asi_mr_sub_plugin = plugin_mr_find( mr_substring );
  842. a.asi_flags = flags;
  843. /*
  844. * If the 'return exact case' option is on (the default), we store the
  845. * first name (the canonical one) unchanged so that attribute names are
  846. * returned exactly as they appear in the schema configuration files.
  847. * But if 'return exact case' has been turned off, we convert the name
  848. * to lowercase. In Netscape Directory Server 4.x and earlier versions,
  849. * the default was to convert to lowercase.
  850. */
  851. if (!config_get_return_exact_case()) {
  852. for (s = a.asi_name; *s; ++s) {
  853. *s = TOLOWER(*s);
  854. }
  855. }
  856. *asip = attr_syntax_dup(&a);
  857. #ifdef ENFORCE_MR_SYNTAX_COMPAT
  858. done:
  859. #endif /* ENFORCE_MR_SYNTAX_COMPAT */
  860. slapi_ch_free((void **)&a.asi_name);
  861. return rc;
  862. }
  863. /*
  864. * slapi_attr_type2plugin - return the plugin handling the attribute type
  865. * if type is unknown, we return the caseIgnoreString plugin used by the
  866. * objectClass attribute type.
  867. */
  868. int
  869. slapi_attr_type2plugin( const char *type, void **pi )
  870. {
  871. char buf[SLAPD_TYPICAL_ATTRIBUTE_NAME_MAX_LENGTH];
  872. char *tmp, *basetype;
  873. int rc;
  874. basetype = buf;
  875. if ( (tmp = slapi_attr_basetype( type, buf, sizeof(buf) )) != NULL ) {
  876. basetype = tmp;
  877. }
  878. rc = -1;
  879. *pi = attr_syntax_get_plugin_by_name_with_default( basetype );
  880. if ( NULL != *pi ) {
  881. rc = 0;
  882. }
  883. slapi_ch_free_string(&tmp);
  884. return( rc );
  885. }
  886. /* deprecated -- not MT safe (pointer into asi is returned!) */
  887. int
  888. slapi_attr_get_oid( const Slapi_Attr *a, char **oid )
  889. {
  890. struct asyntaxinfo *asi = attr_syntax_get_by_name(a->a_type);
  891. if (asi) {
  892. *oid = asi->asi_oid;
  893. attr_syntax_return(asi);
  894. return( 0 );
  895. } else {
  896. *oid = NULL;
  897. return( -1 );
  898. }
  899. }
  900. /* The caller must dispose of oid by calling slapi_ch_free(). */
  901. int
  902. slapi_attr_get_oid_copy( const Slapi_Attr *a, char **oidp )
  903. {
  904. struct asyntaxinfo *asi = attr_syntax_get_by_name(a->a_type);
  905. if (asi) {
  906. *oidp = slapi_ch_strdup( asi->asi_oid );
  907. attr_syntax_return(asi);
  908. return( 0 );
  909. } else {
  910. *oidp = NULL;
  911. return( -1 );
  912. }
  913. }
  914. /* Returns the oid of the syntax of the Slapi_Attr that's passed in.
  915. * The caller must dispose of oid by calling slapi_ch_free_string(). */
  916. int
  917. slapi_attr_get_syntax_oid_copy( const Slapi_Attr *a, char **oidp )
  918. {
  919. const char *oid;
  920. if (a && ((oid = attr_get_syntax_oid(a)))) {
  921. *oidp = slapi_ch_strdup(oid);
  922. return( 0 );
  923. } else {
  924. *oidp = NULL;
  925. return( -1 );
  926. }
  927. }
  928. int
  929. slapi_attr_is_dn_syntax_attr(Slapi_Attr *attr)
  930. {
  931. const char *syntaxoid = NULL;
  932. int dn_syntax = 0; /* not DN, by default */
  933. if (attr && attr->a_flags & SLAPI_ATTR_FLAG_SYNTAX_IS_DN)
  934. /* it was checked before */
  935. return(1);
  936. if (attr && attr->a_plugin == NULL) {
  937. slapi_attr_init_syntax (attr);
  938. }
  939. if (attr && attr->a_plugin) { /* If not set, there is no way to get the info */
  940. if ((syntaxoid = attr_get_syntax_oid(attr))) {
  941. dn_syntax = ((0 == strcmp(syntaxoid, NAMEANDOPTIONALUID_SYNTAX_OID))
  942. || (0 == strcmp(syntaxoid, DN_SYNTAX_OID)));
  943. }
  944. if (dn_syntax)
  945. attr->a_flags |= SLAPI_ATTR_FLAG_SYNTAX_IS_DN;
  946. }
  947. return dn_syntax;
  948. }
  949. int
  950. slapi_attr_is_dn_syntax_type(char *type)
  951. {
  952. const char *syntaxoid = NULL;
  953. int dn_syntax = 0; /* not DN, by default */
  954. struct asyntaxinfo * asi;
  955. asi = attr_syntax_get_by_name(type);
  956. if (asi && asi->asi_plugin) { /* If not set, there is no way to get the info */
  957. if ((syntaxoid = asi->asi_plugin->plg_syntax_oid)) {
  958. dn_syntax = ((0 == strcmp(syntaxoid, NAMEANDOPTIONALUID_SYNTAX_OID))
  959. || (0 == strcmp(syntaxoid, DN_SYNTAX_OID)));
  960. }
  961. }
  962. return dn_syntax;
  963. }
  964. #ifdef ATTR_LDAP_DEBUG
  965. PRIntn
  966. attr_syntax_printnode(PLHashEntry *he, PRIntn i, void *arg)
  967. {
  968. char *alias = (char *)he->key;
  969. struct asyntaxinfo *a = (struct asyntaxinfo *)he->value;
  970. schemaext *ext = a->asi_extensions;
  971. printf( " name: %s\n", a->asi_name );
  972. printf( "\t flags : 0x%x\n", a->asi_flags );
  973. printf( "\t alias : %s\n", alias );
  974. printf( "\t desc : %s\n", a->asi_desc );
  975. printf( "\t oid : %s\n", a->asi_oid );
  976. printf( "\t superior : %s\n", a->asi_superior );
  977. printf( "\t mr_equality : %s\n", a->asi_mr_equality );
  978. printf( "\t mr_ordering : %s\n", a->asi_mr_ordering );
  979. printf( "\t mr_substring: %s\n", a->asi_mr_substring );
  980. while( ext ) {
  981. for ( i = 0; ext->values && ext->values[i]; i++ ) {
  982. printf( "\t %s : %s\n", ext->term, ext->values[i]);
  983. }
  984. ext = ext->next;
  985. }
  986. printf( "\tplugin: %p\n", a->asi_plugin );
  987. printf( "--------------\n" );
  988. return HT_ENUMERATE_NEXT;
  989. }
  990. void
  991. attr_syntax_print()
  992. {
  993. printf( "*** attr_syntax_print ***\n" );
  994. PL_HashTableEnumerateEntries(name2asi, attr_syntax_printnode, 0);
  995. }
  996. #endif
  997. /* lowercase the attr name and chop trailing spaces */
  998. /* note that s may contain options also, e.g., userCertificate;binary */
  999. char *
  1000. attr_syntax_normalize_no_lookup_ext( char *s, int flags )
  1001. {
  1002. char *save, *tmps;
  1003. tmps = slapi_ch_strdup(s);
  1004. for ( save = tmps; (*tmps != '\0') && (*tmps != ' '); tmps++ )
  1005. {
  1006. *tmps = TOLOWER( *tmps );
  1007. }
  1008. *tmps = '\0';
  1009. if (flags & ATTR_SYNTAX_NORM_ORIG_ATTR) {
  1010. /* Chop trailing spaces + following strings */
  1011. *(s + (tmps - save)) = '\0';
  1012. }
  1013. return save;
  1014. }
  1015. char *
  1016. attr_syntax_normalize_no_lookup( const char *s )
  1017. {
  1018. char *save, *tmps;
  1019. tmps = slapi_ch_strdup(s);
  1020. for ( save = tmps; (*tmps != '\0') && (*tmps != ' '); tmps++ )
  1021. {
  1022. *tmps = TOLOWER( *tmps );
  1023. }
  1024. *tmps = '\0';
  1025. return save;
  1026. }
  1027. struct enum_arg_wrapper {
  1028. AttrEnumFunc aef;
  1029. void *arg;
  1030. };
  1031. PRIntn
  1032. attr_syntax_enumerate_internal(PLHashEntry *he, PRIntn i, void *arg)
  1033. {
  1034. struct enum_arg_wrapper *eaw = (struct enum_arg_wrapper *)arg;
  1035. int rc;
  1036. rc = (eaw->aef)((struct asyntaxinfo *)he->value, eaw->arg);
  1037. if ( ATTR_SYNTAX_ENUM_STOP == rc ) {
  1038. rc = HT_ENUMERATE_STOP;
  1039. } else if ( ATTR_SYNTAX_ENUM_REMOVE == rc ) {
  1040. rc = HT_ENUMERATE_REMOVE;
  1041. } else {
  1042. rc = HT_ENUMERATE_NEXT;
  1043. }
  1044. return rc;
  1045. }
  1046. static void
  1047. attr_syntax_enumerate_attrs_ext( PLHashTable *ht,
  1048. AttrEnumFunc aef, void *arg )
  1049. {
  1050. struct enum_arg_wrapper eaw;
  1051. eaw.aef = aef;
  1052. eaw.arg = arg;
  1053. if (!ht)
  1054. return;
  1055. PL_HashTableEnumerateEntries(ht, attr_syntax_enumerate_internal, &eaw);
  1056. }
  1057. void
  1058. attr_syntax_enumerate_attrs(AttrEnumFunc aef, void *arg, PRBool writelock )
  1059. {
  1060. if (!oid2asi)
  1061. return;
  1062. if ( writelock ) {
  1063. AS_LOCK_WRITE(oid2asi_lock);
  1064. AS_LOCK_WRITE(name2asi_lock);
  1065. } else {
  1066. AS_LOCK_READ(oid2asi_lock);
  1067. AS_LOCK_READ(name2asi_lock);
  1068. }
  1069. attr_syntax_enumerate_attrs_ext(oid2asi, aef, arg);
  1070. if ( writelock ) {
  1071. AS_UNLOCK_WRITE(name2asi_lock);
  1072. AS_UNLOCK_WRITE(oid2asi_lock);
  1073. } else {
  1074. AS_UNLOCK_READ(name2asi_lock);
  1075. AS_UNLOCK_READ(oid2asi_lock);
  1076. }
  1077. }
  1078. struct attr_syntax_enum_flaginfo {
  1079. unsigned long asef_flag;
  1080. };
  1081. static int
  1082. attr_syntax_clear_flag_callback(struct asyntaxinfo *asip, void *arg)
  1083. {
  1084. struct attr_syntax_enum_flaginfo *fi;
  1085. PR_ASSERT( asip != NULL );
  1086. fi = (struct attr_syntax_enum_flaginfo *)arg;
  1087. PR_ASSERT( fi != NULL );
  1088. asip->asi_flags &= ~(fi->asef_flag);
  1089. return ATTR_SYNTAX_ENUM_NEXT;
  1090. }
  1091. static int
  1092. attr_syntax_delete_if_not_flagged(struct asyntaxinfo *asip, void *arg)
  1093. {
  1094. struct attr_syntax_enum_flaginfo *fi;
  1095. PR_ASSERT( asip != NULL );
  1096. fi = (struct attr_syntax_enum_flaginfo *)arg;
  1097. PR_ASSERT( fi != NULL );
  1098. if ( 0 == ( asip->asi_flags & fi->asef_flag )) {
  1099. attr_syntax_delete_no_lock( asip, PR_FALSE );
  1100. return ATTR_SYNTAX_ENUM_REMOVE;
  1101. } else {
  1102. return ATTR_SYNTAX_ENUM_NEXT;
  1103. }
  1104. }
  1105. static int
  1106. attr_syntax_force_to_delete(struct asyntaxinfo *asip, void *arg)
  1107. {
  1108. struct attr_syntax_enum_flaginfo *fi;
  1109. PR_ASSERT( asip != NULL );
  1110. fi = (struct attr_syntax_enum_flaginfo *)arg;
  1111. PR_ASSERT( fi != NULL );
  1112. attr_syntax_delete_no_lock( asip, PR_FALSE );
  1113. return ATTR_SYNTAX_ENUM_REMOVE;
  1114. }
  1115. /*
  1116. * Clear 'flag' within all attribute definitions.
  1117. */
  1118. void
  1119. attr_syntax_all_clear_flag( unsigned long flag )
  1120. {
  1121. struct attr_syntax_enum_flaginfo fi;
  1122. memset( &fi, 0, sizeof(fi));
  1123. fi.asef_flag = flag;
  1124. attr_syntax_enumerate_attrs( attr_syntax_clear_flag_callback,
  1125. (void *)&fi, PR_TRUE );
  1126. }
  1127. /*
  1128. * Delete all attribute definitions that do not contain any bits of 'flag'
  1129. * in their flags.
  1130. */
  1131. void
  1132. attr_syntax_delete_all_not_flagged( unsigned long flag )
  1133. {
  1134. struct attr_syntax_enum_flaginfo fi;
  1135. memset( &fi, 0, sizeof(fi));
  1136. fi.asef_flag = flag;
  1137. attr_syntax_enumerate_attrs( attr_syntax_delete_if_not_flagged,
  1138. (void *)&fi, PR_TRUE );
  1139. }
  1140. /*
  1141. * Delete all attribute definitions
  1142. */
  1143. void
  1144. attr_syntax_delete_all()
  1145. {
  1146. struct attr_syntax_enum_flaginfo fi;
  1147. memset( &fi, 0, sizeof(fi));
  1148. attr_syntax_enumerate_attrs( attr_syntax_force_to_delete,
  1149. (void *)&fi, PR_TRUE );
  1150. }
  1151. /*
  1152. * Delete all attribute definitions without attr_syntax lock.
  1153. * The caller is responsible for the lock.
  1154. */
  1155. void
  1156. attr_syntax_delete_all_for_schemareload(unsigned long flag)
  1157. {
  1158. struct attr_syntax_enum_flaginfo fi;
  1159. memset(&fi, 0, sizeof(fi));
  1160. fi.asef_flag = flag;
  1161. attr_syntax_enumerate_attrs_ext(oid2asi, attr_syntax_delete_if_not_flagged,
  1162. (void *)&fi);
  1163. }
  1164. #define ATTR_DEFAULT_SYNTAX_OID "1.1"
  1165. #define ATTR_DEFAULT_SYNTAX "defaultdirstringsyntax"
  1166. static int
  1167. attr_syntax_init(void)
  1168. {
  1169. int schema_modify_enabled = config_get_schemamod();
  1170. if (!schema_modify_enabled) asi_locking = 0;
  1171. if (!oid2asi)
  1172. {
  1173. oid2asi = PL_NewHashTable(2047, hashNocaseString,
  1174. hashNocaseCompare,
  1175. PL_CompareValues, 0, 0);
  1176. if ( asi_locking && NULL == ( oid2asi_lock = slapi_new_rwlock())) {
  1177. if(oid2asi) PL_HashTableDestroy(oid2asi);
  1178. oid2asi = NULL;
  1179. slapi_log_error( SLAPI_LOG_FATAL, "attr_syntax_init",
  1180. "slapi_new_rwlock() for oid2asi lock failed\n" );
  1181. return 1;
  1182. }
  1183. }
  1184. if (!name2asi)
  1185. {
  1186. name2asi = PL_NewHashTable(2047, hashNocaseString,
  1187. hashNocaseCompare,
  1188. PL_CompareValues, 0, 0);
  1189. if ( asi_locking && NULL == ( name2asi_lock = slapi_new_rwlock())) {
  1190. if(name2asi) PL_HashTableDestroy(name2asi);
  1191. name2asi = NULL;
  1192. slapi_log_error( SLAPI_LOG_FATAL, "attr_syntax_init",
  1193. "slapi_new_rwlock() for oid2asi lock failed\n" );
  1194. return 1;
  1195. }
  1196. /* add a default syntax plugin as fallback, required during startup
  1197. */
  1198. attr_syntax_create_default( ATTR_DEFAULT_SYNTAX,
  1199. ATTR_DEFAULT_SYNTAX_OID,
  1200. DIRSTRING_SYNTAX_OID,
  1201. SLAPI_ATTR_FLAG_NOUSERMOD| SLAPI_ATTR_FLAG_NOEXPOSE);
  1202. }
  1203. return 0;
  1204. }
  1205. int
  1206. slapi_attr_syntax_exists(const char *attr_name)
  1207. {
  1208. return attr_syntax_exists(attr_name);
  1209. }
  1210. /*
  1211. * Keep the internally added schema in the hash table,
  1212. * which are re-added if the schema is reloaded.
  1213. */
  1214. static int
  1215. attr_syntax_internal_asi_add_ht(struct asyntaxinfo *asip)
  1216. {
  1217. if (!internalasi) {
  1218. internalasi = PL_NewHashTable(64, hashNocaseString,
  1219. hashNocaseCompare,
  1220. PL_CompareValues, 0, 0);
  1221. }
  1222. if (!internalasi) {
  1223. slapi_log_error(SLAPI_LOG_FATAL, "attr_syntax_internal_asi_add_ht",
  1224. "Failed to create HashTable.\n");
  1225. return 1;
  1226. }
  1227. if (!PL_HashTableLookup(internalasi, asip->asi_oid)) {
  1228. struct asyntaxinfo *asip_copy = attr_syntax_dup(asip);
  1229. if (!asip_copy) {
  1230. slapi_log_error(SLAPI_LOG_FATAL, "attr_syntax_internal_asi_add_ht",
  1231. "Failed to duplicate asyntaxinfo: %s.\n",
  1232. asip->asi_name);
  1233. return 1;
  1234. }
  1235. PL_HashTableAdd(internalasi, asip_copy->asi_oid, asip_copy);
  1236. }
  1237. return 0;
  1238. }
  1239. /*
  1240. * Add an attribute syntax using some default flags, etc.
  1241. * Returns an LDAP error code (LDAP_SUCCESS if all goes well)
  1242. */
  1243. int
  1244. slapi_add_internal_attr_syntax( const char *name, const char *oid,
  1245. const char *syntax, const char *mr_equality, unsigned long extraflags )
  1246. {
  1247. int rc = LDAP_SUCCESS;
  1248. struct asyntaxinfo *asip;
  1249. char *names[2];
  1250. unsigned long std_flags = SLAPI_ATTR_FLAG_STD_ATTR | SLAPI_ATTR_FLAG_OPATTR;
  1251. names[0] = (char *)name;
  1252. names[1] = NULL;
  1253. rc = attr_syntax_create( oid, names,
  1254. "internal server defined attribute type",
  1255. NULL, /* superior */
  1256. mr_equality, NULL, NULL, /* matching rules */
  1257. NULL, syntax,
  1258. SLAPI_SYNTAXLENGTH_NONE,
  1259. std_flags | extraflags,
  1260. &asip );
  1261. if ( rc == LDAP_SUCCESS ) {
  1262. rc = attr_syntax_add( asip );
  1263. if ( rc == LDAP_SUCCESS ) {
  1264. if (attr_syntax_internal_asi_add_ht(asip)) {
  1265. slapi_log_error(SLAPI_LOG_FATAL,
  1266. "slapi_add_internal_attr_syntax",
  1267. "Failed to stash internal asyntaxinfo: %s.\n",
  1268. asip->asi_name);
  1269. }
  1270. }
  1271. }
  1272. return rc;
  1273. }
  1274. /* Adding internal asyncinfo via slapi_reload_internal_attr_syntax */
  1275. static int
  1276. attr_syntax_internal_asi_add(struct asyntaxinfo *asip, void *arg)
  1277. {
  1278. struct asyntaxinfo *asip_copy;
  1279. int rc = 0;
  1280. if (!asip) {
  1281. return 1;
  1282. }
  1283. /* Copy is needed since when reloading the schema,
  1284. * existing syntax info is cleaned up. */
  1285. asip_copy = attr_syntax_dup(asip);
  1286. rc = attr_syntax_add(asip_copy);
  1287. if (LDAP_SUCCESS != rc) {
  1288. attr_syntax_free(asip_copy);
  1289. }
  1290. return rc;
  1291. }
  1292. /* Reload internal attribute syntax stashed in the internalasi hashtable. */
  1293. int
  1294. slapi_reload_internal_attr_syntax()
  1295. {
  1296. int rc = LDAP_SUCCESS;
  1297. if (!internalasi) {
  1298. slapi_log_error(SLAPI_LOG_TRACE, "attr_reload_internal_attr_syntax",
  1299. "No internal attribute syntax to reload.\n");
  1300. return rc;
  1301. }
  1302. attr_syntax_enumerate_attrs_ext(internalasi, attr_syntax_internal_asi_add, NULL);
  1303. return rc;
  1304. }