attrsyntax.c 42 KB

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