schema.c 149 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056
  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. /* schema.c - routines to enforce schema definitions */
  42. #include <stdio.h>
  43. #include <string.h>
  44. #include <sys/types.h>
  45. #include <sys/stat.h>
  46. #include <prio.h>
  47. #include <plstr.h>
  48. #include <plhash.h>
  49. #include "slap.h"
  50. typedef struct sizedbuffer
  51. {
  52. char *buffer;
  53. size_t size;
  54. } sizedbuffer;
  55. typedef char *(*schema_strstr_fn_t)( const char *big, const char *little);
  56. /*
  57. * The schema_oc_kind_strings array is indexed by oc_kind values, i.e.,
  58. * OC_KIND_STRUCTURAL (0), OC_KIND_AUXILIARY (1), or OC_KIND_ABSTRACT (2).
  59. * The leading and trailing spaces are intentional.
  60. */
  61. #define SCHEMA_OC_KIND_COUNT 3
  62. static char *schema_oc_kind_strings_with_spaces[] = {
  63. " STRUCTURAL ",
  64. " AUXILIARY ",
  65. " ABSTRACT ",
  66. };
  67. /* constant strings (used in a few places) */
  68. static const char *schema_obsolete_with_spaces = " OBSOLETE ";
  69. static const char *schema_collective_with_spaces = " COLLECTIVE ";
  70. static const char *schema_nousermod_with_spaces = " NO-USER-MODIFICATION ";
  71. /* user defined origin array */
  72. static char *schema_user_defined_origin[] = {
  73. "user defined",
  74. NULL
  75. };
  76. /*
  77. * pschemadse is based on the general implementation in dse
  78. */
  79. static struct dse *pschemadse= NULL;
  80. static void oc_add_nolock(struct objclass *newoc);
  81. static int oc_delete_nolock (char *ocname);
  82. static int oc_replace_nolock(const char *ocname, struct objclass *newoc);
  83. static int oc_check_required(Slapi_PBlock *, Slapi_Entry *,struct objclass *);
  84. static int oc_check_allowed_sv(Slapi_PBlock *, Slapi_Entry *e, const char *type, struct objclass **oclist );
  85. static char **read_dollar_values ( char *vals);
  86. static int schema_delete_objectclasses ( Slapi_Entry *entryBefore,
  87. LDAPMod *mod, char *errorbuf, size_t errorbufsize,
  88. int schema_ds4x_compat );
  89. static int schema_delete_attributes ( Slapi_Entry *entryBefore,
  90. LDAPMod *mod, char *errorbuf, size_t errorbufsize);
  91. static int schema_add_attribute ( Slapi_PBlock *pb, LDAPMod *mod,
  92. char *errorbuf, size_t errorbufsize, int schema_ds4x_compat );
  93. static int schema_add_objectclass ( Slapi_PBlock *pb, LDAPMod *mod,
  94. char *errorbuf, size_t errorbufsize, int schema_ds4x_compat );
  95. static int schema_replace_attributes ( Slapi_PBlock *pb, LDAPMod *mod,
  96. char *errorbuf, size_t errorbufsize );
  97. static int schema_replace_objectclasses ( Slapi_PBlock *pb, LDAPMod *mod,
  98. char *errorbuf, size_t errorbufsize );
  99. static int read_oc_ldif ( const char *input, struct objclass **oc,
  100. char *errorbuf, size_t errorbufsize, PRUint32 flags, int is_user_defined,
  101. int schema_ds4x_compat );
  102. static int schema_check_name(char *name, PRBool isAttribute, char *errorbuf,
  103. size_t errorbufsize );
  104. static int schema_check_oid(const char *name, const char *oid,
  105. PRBool isAttribute, char *errorbuf, size_t errorbufsize);
  106. static int has_smart_referral( Slapi_Entry *e );
  107. static int isExtensibleObjectclass(const char *objectclass);
  108. static int strip_oc_options ( struct objclass *poc );
  109. static char *stripOption (char *attr);
  110. static int read_at_ldif(const char *input, struct asyntaxinfo **asipp,
  111. char *errorbuf, size_t errorbufsize, PRUint32 flags,
  112. int is_user_defined, int schema_ds4x_compat, int is_remote);
  113. static char **parse_qdlist(const char *s, int *n, int strip_options);
  114. static void free_qdlist(char **vals, int n);
  115. static char **parse_qdescrs(const char *s, int *n);
  116. static char **parse_qdstrings(const char *s, int *n);
  117. static int get_flag_keyword( const char *keyword, int flag_value,
  118. const char **inputp, schema_strstr_fn_t strstr_fn );
  119. static char *get_tagged_oid( const char *tag, const char **inputp,
  120. schema_strstr_fn_t strstr_fn );
  121. static int put_tagged_oid( char *outp, const char *tag, const char *oid,
  122. const char *suffix, int enquote );
  123. static void strcat_oids( char *buf, char *prefix, char **oids,
  124. int schema_ds4x_compat );
  125. static size_t strcat_qdlist( char *buf, char *prefix, char **qdlist );
  126. static size_t strlen_null_ok(const char *s);
  127. static int strcpy_count( char *dst, const char *src );
  128. static int element_is_user_defined( char * const * origins );
  129. static char **parse_origin_list( const char *schema_value, int *num_originsp,
  130. char **default_list );
  131. static int refresh_user_defined_schema(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg);
  132. static int schema_check_oc_attrs ( struct objclass *poc, char *errorbuf,
  133. size_t errorbufsize, int stripOptions );
  134. static struct objclass *oc_find_nolock( const char *ocname_or_oid );
  135. static struct objclass *oc_find_oid_nolock( const char *ocoid );
  136. static void oc_free( struct objclass **ocp );
  137. static PRBool oc_equal( struct objclass *oc1, struct objclass *oc2 );
  138. static PRBool attr_syntax_equal( struct asyntaxinfo *asi1,
  139. struct asyntaxinfo *asi2 );
  140. static int schema_strcmp( const char *s1, const char *s2 );
  141. static int schema_strcmp_array( char **sa1, char **sa2,
  142. const char *ignorestr );
  143. static PRBool schema_type_is_interesting( const char *type );
  144. static void schema_create_errormsg( char *errorbuf, size_t errorbufsize,
  145. const char *prefix, const char *name, const char *fmt, ... )
  146. #ifdef __GNUC__
  147. __attribute__ ((format (printf, 5, 6)));
  148. #else
  149. ;
  150. #endif
  151. /* Some utility functions for dealing with a dynamic buffer */
  152. static struct sizedbuffer *sizedbuffer_construct(size_t size);
  153. static void sizedbuffer_destroy(struct sizedbuffer *p);
  154. static void sizedbuffer_allocate(struct sizedbuffer *p, size_t sizeneeded);
  155. /*
  156. * Constant strings that we pass to schema_create_errormsg().
  157. */
  158. static const char *schema_errprefix_oc = "object class %s: ";
  159. static const char *schema_errprefix_at = "attribute type %s: ";
  160. static const char *schema_errprefix_generic = "%s: ";
  161. /*
  162. * A "cached" copy of the "ignore trailing spaces" config. setting.
  163. * This is set during initialization only (server restart required for
  164. * changes to take effect). We do things this way to avoid lock/unlock
  165. * mutex sequences inside performance critical code.
  166. */
  167. static int schema_ignore_trailing_spaces =
  168. SLAPD_DEFAULT_SCHEMA_IGNORE_TRAILING_SPACES;
  169. /* R/W lock used to serialize access to the schema DSE */
  170. static PRRWLock *schema_dse_lock = NULL;
  171. /*
  172. * The schema_dse_mandatory_init_callonce structure is used by NSPR to ensure
  173. * that schema_dse_mandatory_init() is called at most once.
  174. */
  175. static PRCallOnceType schema_dse_mandatory_init_callonce = { 0, 0, 0 };
  176. /* Essential initialization. Returns PRSuccess if successful */
  177. static PRStatus
  178. schema_dse_mandatory_init( void )
  179. {
  180. if ( NULL == ( schema_dse_lock = PR_NewRWLock( PR_RWLOCK_RANK_NONE,
  181. "schema DSE rwlock" ))) {
  182. slapi_log_error( SLAPI_LOG_FATAL, "schema_dse_mandatory_init",
  183. "PR_NewRWLock() for schema DSE lock failed\n" );
  184. return PR_FAILURE;
  185. }
  186. schema_ignore_trailing_spaces = config_get_schema_ignore_trailing_spaces();
  187. return PR_SUCCESS;
  188. }
  189. static void
  190. schema_dse_lock_read( void )
  191. {
  192. if ( NULL != schema_dse_lock ||
  193. PR_SUCCESS == PR_CallOnce( &schema_dse_mandatory_init_callonce,
  194. schema_dse_mandatory_init )) {
  195. PR_RWLock_Rlock( schema_dse_lock );
  196. }
  197. }
  198. static void
  199. schema_dse_lock_write( void )
  200. {
  201. if ( NULL != schema_dse_lock ||
  202. PR_SUCCESS == PR_CallOnce( &schema_dse_mandatory_init_callonce,
  203. schema_dse_mandatory_init )) {
  204. PR_RWLock_Wlock( schema_dse_lock );
  205. }
  206. }
  207. static void
  208. schema_dse_unlock( void )
  209. {
  210. if ( schema_dse_lock != NULL ) {
  211. PR_RWLock_Unlock( schema_dse_lock );
  212. }
  213. }
  214. static int
  215. dont_allow_that(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg)
  216. {
  217. *returncode = LDAP_UNWILLING_TO_PERFORM;
  218. return SLAPI_DSE_CALLBACK_ERROR;
  219. }
  220. #if 0
  221. /*
  222. * hashNocaseString - used for case insensitive hash lookups
  223. */
  224. static PLHashNumber
  225. hashNocaseString(const void *key)
  226. {
  227. PLHashNumber h = 0;
  228. const unsigned char *s;
  229. for (s = key; *s; s++)
  230. h = (h >> 28) ^ (h << 4) ^ (tolower(*s));
  231. return h;
  232. }
  233. #endif
  234. static const char *
  235. skipWS(const char *s)
  236. {
  237. while (s && isascii(*s) && isspace(*s) )
  238. ++s;
  239. if ((isascii(*s)) == 0) {
  240. return NULL;
  241. }
  242. return s;
  243. }
  244. /*
  245. * like strchr() but strings within single quotes are skipped.
  246. */
  247. static char *
  248. strchr_skip_quoted_strings( char *s, int c )
  249. {
  250. int in_quote = 0;
  251. while ( *s != '\0' ) {
  252. if ( *s == '\'' ) {
  253. in_quote = 1 - in_quote; /* toggle */
  254. } else if ( !in_quote && *s == c ) {
  255. return s;
  256. }
  257. ++s;
  258. }
  259. return( NULL );
  260. }
  261. /**
  262. * parses a string containing a qdescrs or qdstrings (as described by
  263. * RFC 2252, section 4.1) into an array of strings; the second parameter
  264. * will hold the actual number of strings in the array. The returned array
  265. * is NULL terminated.
  266. *
  267. * This function can handle qdescrs or qdstrings because the only
  268. * difference between the two is that fewer characters are allowed in
  269. * a qdescr (our parsing code does not check anyway) and we want to
  270. * strip attribute options when parsing qdescrs (indicated by a non-zero
  271. * strip_options parameter).
  272. */
  273. static char **
  274. parse_qdlist(const char *s, int *n, int strip_options)
  275. {
  276. char **retval = 0;
  277. char *work = 0;
  278. char *start = 0, *end = 0;
  279. int num = 0;
  280. int in_quote = 0;
  281. if (n)
  282. *n = 0;
  283. if (!s || !*s || !n) {
  284. return retval;
  285. }
  286. /* make a working copy of the given string */
  287. work = slapi_ch_strdup(s);
  288. /* count the number of qdescr items in the string e.g. just count
  289. the number of spaces */
  290. /* for a single qdescr, the terminal character will be the final
  291. single quote; for a qdesclist, the terminal will be the close
  292. parenthesis */
  293. end = strrchr(work, '\'');
  294. if ((start = strchr_skip_quoted_strings(work, '(')) != NULL)
  295. end = strchr_skip_quoted_strings(work, ')');
  296. else
  297. start = strchr(work, '\'');
  298. if (!end) /* already nulled out */
  299. end = work + strlen(work);
  300. if (start) {
  301. num = 1;
  302. /* first pass: count number of items and zero out non useful tokens */
  303. for (; *start && (start != end); ++start) {
  304. if (*start == '\'' ) {
  305. in_quote = 1 - in_quote; /* toggle */
  306. *start = 0;
  307. } else if ( !in_quote && ((*start == ' ') || (*start == '(') ||
  308. (*start == ')'))) {
  309. if (*start == ' ') {
  310. num++;
  311. }
  312. *start = 0;
  313. }
  314. }
  315. *start = 0;
  316. /* allocate retval; num will be >= actual number of items */
  317. retval = (char**)slapi_ch_calloc(num+1, sizeof(char *));
  318. /* second pass: copy strings into the return value and set the
  319. actual number of items returned */
  320. start = work;
  321. while (start != end) {
  322. /* skip over nulls */
  323. while (!*start && (start != end))
  324. ++start;
  325. if (start == end)
  326. break;
  327. retval[*n] = slapi_ch_strdup(start);
  328. /*
  329. * A qdescr list may contain attribute options; we just strip
  330. * them here. In the future, we may want to support them or do
  331. * something really fancy with them
  332. */
  333. if ( strip_options ) {
  334. stripOption(retval[*n]);
  335. }
  336. (*n)++;
  337. start += strlen(start);
  338. }
  339. PR_ASSERT( *n <= num ); /* sanity check */
  340. retval[*n] = NULL;
  341. } else {
  342. /* syntax error - no start and/or end delimiters */
  343. }
  344. /* free the working string */
  345. slapi_ch_free((void **)&work);
  346. return retval;
  347. }
  348. static void
  349. free_qdlist(char **vals, int n)
  350. {
  351. int ii;
  352. for (ii = 0; ii < n; ++ii)
  353. slapi_ch_free((void **)&(vals[ii]));
  354. slapi_ch_free((void **)&vals);
  355. }
  356. /**
  357. * parses a string containing a qdescrs (as described by RFC 2252, section 4.1)
  358. * into an array of strings; the second parameter will hold the actual number
  359. * of strings in the array. The returned array is NULL terminated.
  360. */
  361. static char **
  362. parse_qdescrs(const char *s, int *n)
  363. {
  364. return parse_qdlist( s, n, 1 /* strip attribute options */ );
  365. }
  366. /*
  367. * Parses a string containing a qdstrings (see RFC 2252, section 4.1) into
  368. * an array of strings; the second parameter will hold the actual number
  369. * of strings in the array.
  370. */
  371. static char **
  372. parse_qdstrings(const char *s, int *n)
  373. {
  374. return parse_qdlist( s, n, 0 /* DO NOT strip attribute options */ );
  375. }
  376. /*
  377. * slapi_entry_schema_check - check that entry e conforms to the schema
  378. * required by its object class(es). returns 0 if so, non-zero otherwise.
  379. * [ the pblock is only used to check if this is a replicated operation.
  380. * you may pass in NULL if this isn't part of an operation. ]
  381. */
  382. int
  383. slapi_entry_schema_check( Slapi_PBlock *pb, Slapi_Entry *e )
  384. {
  385. struct objclass **oclist;
  386. struct objclass *oc;
  387. const char *ocname;
  388. Slapi_Attr *a, *aoc;
  389. Slapi_Value *v;
  390. int ret = 0;
  391. int schemacheck = config_get_schemacheck();
  392. int is_replicated_operation = 0;
  393. int is_extensible_object = 0;
  394. int i, oc_count = 0;
  395. int unknown_class = 0;
  396. char errtext[ BUFSIZ ];
  397. PRUint32 schema_flags = 0;
  398. /* smart referrals are not allowed in Directory Lite */
  399. if ( config_is_slapd_lite() ) {
  400. if ( has_smart_referral(e) ) {
  401. return 1;
  402. }
  403. }
  404. /*
  405. * say the schema checked out ok if we're not checking schema at
  406. * all, or if this is a replication update.
  407. */
  408. if (pb != NULL) {
  409. slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &is_replicated_operation);
  410. slapi_pblock_get(pb, SLAPI_SCHEMA_FLAGS, &schema_flags);
  411. }
  412. if ( schemacheck == 0 || is_replicated_operation ) {
  413. return( 0 );
  414. }
  415. /* find the object class attribute - could error out here */
  416. if ( (aoc = attrlist_find( e->e_attrs, "objectclass" )) == NULL ) {
  417. char ebuf[ BUFSIZ ];
  418. LDAPDebug( LDAP_DEBUG_ANY,
  419. "Entry \"%s\" required attribute \"objectclass\" missing\n",
  420. escape_string( slapi_entry_get_dn_const(e), ebuf ), 0, 0 );
  421. if (pb) {
  422. PR_snprintf( errtext, sizeof( errtext ),
  423. "missing required attribute \"objectclass\"\n" );
  424. slapi_pblock_set( pb, SLAPI_PB_RESULT_TEXT, errtext );
  425. }
  426. return( 1 );
  427. }
  428. /*
  429. * Create an array of pointers to the objclass definitions.
  430. */
  431. i= slapi_attr_first_value(aoc,&v);
  432. while (i != -1) {
  433. oc_count++;
  434. i= slapi_attr_next_value(aoc,i,&v);
  435. }
  436. oclist = (struct objclass**)
  437. slapi_ch_malloc((oc_count+1)*sizeof(struct objclass*));
  438. /*
  439. * Need the read lock to create the oc array and while we use it.
  440. */
  441. if (!(schema_flags & DSE_SCHEMA_LOCKED))
  442. oc_lock_read();
  443. oc_count = 0;
  444. for (i= slapi_attr_first_value(aoc,&v); i != -1;
  445. i= slapi_attr_next_value(aoc,i,&v)) {
  446. ocname = slapi_value_get_string(v);
  447. if ( isExtensibleObjectclass( ocname )) {
  448. /*
  449. * if the entry is an extensibleObject, just check to see if
  450. * the required attributes for whatever other objectclasses the
  451. * entry might be are present. All other attributes are allowed
  452. */
  453. is_extensible_object = 1;
  454. continue;
  455. }
  456. if ((oc = oc_find_nolock( ocname )) != NULL ) {
  457. oclist[oc_count++] = oc;
  458. } else {
  459. /* we don't know about the oc; return an appropriate error message */
  460. char ebuf[ BUFSIZ ];
  461. char ebuf2[ BUFSIZ ];
  462. size_t ocname_len = ( ocname == NULL ) ? 0 : strlen( ocname );
  463. const char *extra_msg = "";
  464. if ( ocname_len > 0 && isspace( ocname[ ocname_len-1 ] )) {
  465. if ( ocname_len > 1 && isspace( ocname[ ocname_len-2 ] )) {
  466. extra_msg = " (remove the trailing spaces)";
  467. } else {
  468. extra_msg = " (remove the trailing space)";
  469. }
  470. }
  471. LDAPDebug( LDAP_DEBUG_ANY,
  472. "Entry \"%s\" has unknown object class \"%s\"%s\n",
  473. escape_string( slapi_entry_get_dn_const(e), ebuf ),
  474. escape_string(ocname, ebuf2), extra_msg );
  475. if (pb) {
  476. PR_snprintf( errtext, sizeof( errtext ),
  477. "unknown object class \"%s\"%s\n",
  478. escape_string(ocname, ebuf2), extra_msg );
  479. slapi_pblock_set( pb, SLAPI_PB_RESULT_TEXT, errtext );
  480. }
  481. unknown_class = 1;
  482. }
  483. }
  484. oclist[oc_count] = NULL;
  485. if (unknown_class) {
  486. /* failure */
  487. ret = 1;
  488. goto out;
  489. }
  490. /*
  491. * go through all the checking so we can log everything
  492. * wrong with the entry. some day, we might want to return
  493. * this information to the client as an error message.
  494. */
  495. /*
  496. * check that the entry has required attrs for each oc
  497. */
  498. for (i = 0; oclist[i] != NULL; i++) {
  499. if ( oc_check_required( pb, e, oclist[i] ) != 0 ) {
  500. ret = 1;
  501. goto out;
  502. }
  503. }
  504. /*
  505. * check that each attr in the entry is allowed by some oc,
  506. * and that single-valued attrs only have one value
  507. */
  508. {
  509. Slapi_Attr *prevattr;
  510. i = slapi_entry_first_attr(e, &a);
  511. while (-1 != i && 0 == ret)
  512. {
  513. if (is_extensible_object == 0 &&
  514. unknown_class == 0 &&
  515. !slapi_attr_flag_is_set(a, SLAPI_ATTR_FLAG_OPATTR))
  516. {
  517. char *attrtype;
  518. slapi_attr_get_type(a, &attrtype);
  519. if (oc_check_allowed_sv(pb, e, attrtype, oclist) != 0)
  520. {
  521. ret = 1;
  522. }
  523. }
  524. if ( slapi_attr_flag_is_set( a, SLAPI_ATTR_FLAG_SINGLE ) ) {
  525. if (slapi_valueset_count(&a->a_present_values) > 1)
  526. {
  527. char ebuf[ BUFSIZ ];
  528. LDAPDebug( LDAP_DEBUG_ANY,
  529. "Entry \"%s\" single-valued attribute \"%s\" has multiple values\n",
  530. escape_string( slapi_entry_get_dn_const(e), ebuf ),
  531. a->a_type, 0 );
  532. if (pb) {
  533. PR_snprintf( errtext, sizeof( errtext ),
  534. "single-valued attribute \"%s\" has multiple values\n",
  535. a->a_type );
  536. slapi_pblock_set( pb, SLAPI_PB_RESULT_TEXT, errtext );
  537. }
  538. ret = 1;
  539. }
  540. }
  541. prevattr = a;
  542. i = slapi_entry_next_attr(e, prevattr, &a);
  543. }
  544. }
  545. out:
  546. /* Done with the oc array so can release the lock */
  547. if (!(schema_flags & DSE_SCHEMA_LOCKED))
  548. oc_unlock();
  549. slapi_ch_free((void**)&oclist);
  550. return( ret );
  551. }
  552. /*
  553. * The caller must obtain a read lock first by calling oc_lock_read().
  554. */
  555. static int
  556. oc_check_required( Slapi_PBlock *pb, Slapi_Entry *e, struct objclass *oc )
  557. {
  558. int i;
  559. int rc = 0; /* success, by default */
  560. Slapi_Attr *a;
  561. if (oc == NULL || oc->oc_required == NULL || oc->oc_required[0] == NULL) {
  562. return 0; /* success, as none required */
  563. }
  564. /* for each required attribute */
  565. for ( i = 0; oc->oc_required[i] != NULL; i++ ) {
  566. /* see if it's in the entry */
  567. for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
  568. if ( slapi_attr_type_cmp( oc->oc_required[i], a->a_type,
  569. SLAPI_TYPE_CMP_SUBTYPE ) == 0 ) {
  570. break;
  571. }
  572. }
  573. /* not there => schema violation */
  574. if ( a == NULL ) {
  575. char errtext[ BUFSIZ ];
  576. char ebuf[ BUFSIZ ];
  577. LDAPDebug( LDAP_DEBUG_ANY,
  578. "Entry \"%s\" missing attribute \"%s\" required"
  579. " by object class \"%s\"\n",
  580. escape_string( slapi_entry_get_dn_const(e), ebuf ),
  581. oc->oc_required[i], oc->oc_name);
  582. if (pb) {
  583. PR_snprintf( errtext, sizeof( errtext ),
  584. "missing attribute \"%s\" required"
  585. " by object class \"%s\"\n",
  586. oc->oc_required[i], oc->oc_name );
  587. slapi_pblock_set( pb, SLAPI_PB_RESULT_TEXT, errtext );
  588. }
  589. rc = 1; /* failure */
  590. }
  591. }
  592. return rc;
  593. }
  594. /*
  595. * The caller must obtain a read lock first by calling oc_lock_read().
  596. */
  597. static int
  598. oc_check_allowed_sv(Slapi_PBlock *pb, Slapi_Entry *e, const char *type, struct objclass **oclist )
  599. {
  600. struct objclass *oc;
  601. int i, j;
  602. int rc = 1; /* failure */
  603. /* always allow objectclass and entryid attributes */
  604. /* MFW XXX THESE SHORTCUTS SHOULD NOT BE NECESSARY BUT THEY MASK
  605. * MFW XXX OTHER BUGS IN THE SERVER.
  606. */
  607. if ( slapi_attr_type_cmp( type, "objectclass", SLAPI_TYPE_CMP_EXACT ) == 0 ) {
  608. return( 0 );
  609. } else if ( slapi_attr_type_cmp( type, "entryid", SLAPI_TYPE_CMP_EXACT ) == 0 ) {
  610. return( 0 );
  611. }
  612. /* check that the type appears as req or opt in at least one oc */
  613. for (i = 0; rc != 0 && oclist[i] != NULL; i++) {
  614. oc = oclist[i];
  615. /* does it require the type? */
  616. for ( j = 0; oc->oc_required && oc->oc_required[j] != NULL; j++ ) {
  617. if ( slapi_attr_type_cmp( oc->oc_required[j],
  618. type, SLAPI_TYPE_CMP_SUBTYPE ) == 0 ) {
  619. rc = 0;
  620. break;
  621. }
  622. }
  623. if ( 0 != rc ) {
  624. /* does it allow the type? */
  625. for ( j = 0; oc->oc_allowed && oc->oc_allowed[j] != NULL; j++ ) {
  626. if ( slapi_attr_type_cmp( oc->oc_allowed[j],
  627. type, SLAPI_TYPE_CMP_SUBTYPE ) == 0 ||
  628. strcmp( oc->oc_allowed[j],"*" ) == 0 ) {
  629. rc = 0;
  630. break;
  631. }
  632. }
  633. /* maybe the next oc allows it */
  634. }
  635. }
  636. if ( 0 != rc ) {
  637. char errtext[ BUFSIZ ];
  638. char ebuf[ BUFSIZ ];
  639. char ebuf2[ BUFSIZ ];
  640. LDAPDebug( LDAP_DEBUG_ANY,
  641. "Entry \"%s\" -- attribute \"%s\" not allowed\n",
  642. escape_string( slapi_entry_get_dn_const(e), ebuf ),
  643. escape_string( type, ebuf2 ),
  644. 0);
  645. if (pb) {
  646. PR_snprintf( errtext, sizeof( errtext ),
  647. "attribute \"%s\" not allowed\n",
  648. escape_string( type, ebuf2 ) );
  649. slapi_pblock_set( pb, SLAPI_PB_RESULT_TEXT, errtext );
  650. }
  651. }
  652. return rc;
  653. }
  654. /*
  655. * oc_find_name() will return a strdup'd string or NULL if the objectclass
  656. * could not be found.
  657. */
  658. char *
  659. oc_find_name( const char *name_or_oid )
  660. {
  661. struct objclass *oc;
  662. char *ocname = NULL;
  663. oc_lock_read();
  664. if ( NULL != ( oc = oc_find_nolock( name_or_oid ))) {
  665. ocname = slapi_ch_strdup( oc->oc_name );
  666. }
  667. oc_unlock();
  668. return ocname;
  669. }
  670. /*
  671. * oc_find_nolock will return a pointer to the objectclass which has the
  672. * same name OR oid.
  673. * NULL is returned if no match is found or `name_or_oid' is NULL.
  674. */
  675. static struct objclass *
  676. oc_find_nolock( const char *ocname_or_oid )
  677. {
  678. struct objclass *oc;
  679. if ( NULL != ocname_or_oid ) {
  680. if ( !schema_ignore_trailing_spaces ) {
  681. for ( oc = g_get_global_oc_nolock(); oc != NULL; oc = oc->oc_next ) {
  682. if ( ( strcasecmp( oc->oc_name, ocname_or_oid ) == 0 )
  683. || ( oc->oc_oid &&
  684. strcasecmp( oc->oc_oid, ocname_or_oid ) == 0 )) {
  685. return( oc );
  686. }
  687. }
  688. } else {
  689. const char *p;
  690. size_t len;
  691. /*
  692. * Ignore trailing spaces when comparing object class names.
  693. */
  694. for ( p = ocname_or_oid, len = 0; (*p != '\0') && (*p != ' ');
  695. p++, len++ ) {
  696. ; /* NULL */
  697. }
  698. for ( oc = g_get_global_oc_nolock(); oc != NULL; oc = oc->oc_next ) {
  699. if ( ( (strncasecmp( oc->oc_name, ocname_or_oid, len ) == 0)
  700. && (len == strlen(oc->oc_name)) )
  701. ||
  702. ( oc->oc_oid &&
  703. ( strncasecmp( oc->oc_oid, ocname_or_oid, len ) == 0)
  704. && (len == strlen(oc->oc_oid)) ) ) {
  705. return( oc );
  706. }
  707. }
  708. }
  709. }
  710. return( NULL );
  711. }
  712. /*
  713. * oc_find_oid_nolock will return a pointer to the objectclass which has
  714. * the same oid.
  715. * NULL is returned if no match is found or `ocoid' is NULL.
  716. */
  717. static struct objclass *
  718. oc_find_oid_nolock( const char *ocoid )
  719. {
  720. struct objclass *oc;
  721. if ( NULL != ocoid ) {
  722. for ( oc = g_get_global_oc_nolock(); oc != NULL; oc = oc->oc_next ) {
  723. if ( ( oc->oc_oid &&
  724. ( strcasecmp( oc->oc_oid, ocoid ) == 0)) ){
  725. return( oc );
  726. }
  727. }
  728. }
  729. return( NULL );
  730. }
  731. /*
  732. We need to keep the objectclasses in the same order as defined in the ldif files. If not
  733. SUP dependencies will break. When the user redefines an existing objectclass this code
  734. makes sure it is put back in the same order it was read to from the ldif file. It also
  735. verifies that the entries oc_superior value preceeds it in the chain. If not it will not
  736. allow the entry to be added. This makes sure that the ldif will be written back correctly.
  737. */
  738. static int
  739. oc_replace_nolock(const char *ocname, struct objclass *newoc) {
  740. struct objclass *oc, *pnext;
  741. int rc = LDAP_SUCCESS;
  742. PRBool saw_sup=PR_FALSE;
  743. oc = g_get_global_oc_nolock();
  744. if(newoc->oc_superior == NULL)
  745. {
  746. saw_sup=PR_TRUE;
  747. }
  748. /* don't check SUP dependency for first one because it always/should be top */
  749. if (strcasecmp (oc->oc_name, ocname) == 0) {
  750. newoc->oc_next=oc->oc_next;
  751. g_set_global_oc_nolock ( newoc );
  752. oc_free( &oc );
  753. } else {
  754. for (pnext = oc ; pnext != NULL;
  755. oc = pnext, pnext = pnext->oc_next) {
  756. if((pnext->oc_name != NULL) && (newoc->oc_superior != NULL)) {
  757. if(strcasecmp( pnext->oc_name, newoc->oc_superior) == 0)
  758. {
  759. saw_sup=PR_TRUE;
  760. }
  761. }
  762. if (strcasecmp ( pnext->oc_name, ocname ) == 0) {
  763. if(saw_sup)
  764. {
  765. oc->oc_next=newoc;
  766. newoc->oc_next=pnext->oc_next;
  767. oc_free( &pnext );
  768. break;
  769. } else
  770. {
  771. rc = LDAP_TYPE_OR_VALUE_EXISTS;
  772. break;
  773. }
  774. }
  775. }
  776. }
  777. return rc;
  778. }
  779. static int
  780. oc_delete_nolock (char *ocname)
  781. {
  782. struct objclass *oc, *pnext;
  783. int rc = 0; /* failure */
  784. oc = g_get_global_oc_nolock();
  785. /* special case if we're removing the first oc */
  786. if (strcasecmp (oc->oc_name, ocname) == 0) {
  787. g_set_global_oc_nolock ( oc->oc_next );
  788. oc_free( &oc );
  789. rc = 1;
  790. } else {
  791. for (pnext = oc->oc_next ; pnext != NULL;
  792. oc = pnext, pnext = pnext->oc_next) {
  793. if (strcasecmp ( pnext->oc_name, ocname ) == 0) {
  794. oc->oc_next = pnext->oc_next;
  795. oc_free( &pnext );
  796. rc = 1;
  797. break;
  798. }
  799. }
  800. }
  801. return rc;
  802. }
  803. static void
  804. oc_delete_all_nolock( void )
  805. {
  806. struct objclass *oc, *pnext;
  807. oc = g_get_global_oc_nolock();
  808. for (pnext = oc->oc_next; oc;
  809. oc = pnext, pnext = oc?oc->oc_next:NULL) {
  810. oc_free( &oc );
  811. }
  812. g_set_global_oc_nolock ( NULL );
  813. }
  814. /*
  815. * Compare two objectclass definitions for equality. Return PR_TRUE if
  816. * they are equivalent and PR_FALSE if not.
  817. *
  818. * The oc_required and oc_allowed arrays are ignored.
  819. * The string "user defined" is ignored within the origins array.
  820. * The following flags are ignored:
  821. * OC_FLAG_STANDARD_OC
  822. * OC_FLAG_USER_OC
  823. * OC_FLAG_REDEFINED_OC
  824. */
  825. static PRBool
  826. oc_equal( struct objclass *oc1, struct objclass *oc2 )
  827. {
  828. PRUint8 flagmask;
  829. if ( schema_strcmp( oc1->oc_name, oc2->oc_name ) != 0
  830. || schema_strcmp( oc1->oc_desc, oc2->oc_desc ) != 0
  831. || schema_strcmp( oc1->oc_oid, oc2->oc_oid ) != 0
  832. || schema_strcmp( oc1->oc_superior, oc2->oc_superior ) != 0 ) {
  833. return PR_FALSE;
  834. }
  835. flagmask = ~(OC_FLAG_STANDARD_OC | OC_FLAG_USER_OC | OC_FLAG_REDEFINED_OC);
  836. if ( oc1->oc_kind != oc2->oc_kind
  837. || ( oc1->oc_flags & flagmask ) != ( oc2->oc_flags & flagmask )) {
  838. return PR_FALSE;
  839. }
  840. if ( schema_strcmp_array( oc1->oc_orig_required, oc2->oc_orig_required,
  841. NULL ) != 0
  842. || schema_strcmp_array( oc1->oc_orig_allowed, oc2->oc_orig_allowed,
  843. NULL ) != 0
  844. || schema_strcmp_array( oc1->oc_origin, oc2->oc_origin,
  845. schema_user_defined_origin[0] ) != 0 ) {
  846. return PR_FALSE;
  847. }
  848. return PR_TRUE;
  849. }
  850. #ifdef OC_DEBUG
  851. static int
  852. oc_print( struct objclass *oc )
  853. {
  854. int i;
  855. printf( "object class %s\n", oc->oc_name );
  856. if ( oc->oc_required != NULL ) {
  857. printf( "\trequires %s", oc->oc_required[0] );
  858. for ( i = 1; oc->oc_required[i] != NULL; i++ ) {
  859. printf( ",%s", oc->oc_required[i] );
  860. }
  861. printf( "\n" );
  862. }
  863. if ( oc->oc_allowed != NULL ) {
  864. printf( "\tallows %s", oc->oc_allowed[0] );
  865. for ( i = 1; oc->oc_allowed[i] != NULL; i++ ) {
  866. printf( ",%s", oc->oc_allowed[i] );
  867. }
  868. printf( "\n" );
  869. }
  870. return 0;
  871. }
  872. #endif
  873. /*
  874. * Compare two attrsyntax definitions for equality. Return PR_TRUE if
  875. * they are equivalent and PR_FALSE if not.
  876. *
  877. * The string "user defined" is ignored within the origins array.
  878. * The following flags are ignored:
  879. * SLAPI_ATTR_FLAG_STD_ATTR
  880. * SLAPI_ATTR_FLAG_NOLOCKING
  881. * SLAPI_ATTR_FLAG_OVERRIDE
  882. */
  883. static PRBool
  884. attr_syntax_equal( struct asyntaxinfo *asi1, struct asyntaxinfo *asi2 )
  885. {
  886. unsigned long flagmask;
  887. flagmask = ~( SLAPI_ATTR_FLAG_STD_ATTR | SLAPI_ATTR_FLAG_NOLOCKING
  888. | SLAPI_ATTR_FLAG_OVERRIDE );
  889. if ( schema_strcmp( asi1->asi_oid, asi2->asi_oid ) != 0
  890. || schema_strcmp( asi1->asi_name, asi2->asi_name ) != 0
  891. || schema_strcmp( asi1->asi_desc, asi2->asi_desc ) != 0
  892. || schema_strcmp( asi1->asi_superior, asi2->asi_superior ) != 0
  893. || schema_strcmp( asi1->asi_mr_equality, asi2->asi_mr_equality )
  894. != 0
  895. || schema_strcmp( asi1->asi_mr_ordering, asi2->asi_mr_ordering )
  896. != 0
  897. || schema_strcmp( asi1->asi_mr_substring,
  898. asi2->asi_mr_substring ) != 0 ) {
  899. return PR_FALSE;
  900. }
  901. if ( schema_strcmp_array( asi1->asi_aliases, asi2->asi_aliases, NULL ) != 0
  902. || schema_strcmp_array( asi1->asi_origin, asi2->asi_origin,
  903. schema_user_defined_origin[0] ) != 0
  904. || asi1->asi_plugin != asi2->asi_plugin
  905. || ( asi1->asi_flags & flagmask ) !=
  906. ( asi2->asi_flags & flagmask )
  907. || asi1->asi_syntaxlength != asi2->asi_syntaxlength ) {
  908. return PR_FALSE;
  909. }
  910. return PR_TRUE;
  911. }
  912. /*
  913. * Like strcmp(), but a NULL string pointer is treated as equivalent to
  914. * another NULL one and NULL is treated as "less than" all non-NULL values.
  915. */
  916. static int
  917. schema_strcmp( const char *s1, const char *s2 )
  918. {
  919. if ( s1 == NULL ) {
  920. if ( s2 == NULL ) {
  921. return 0; /* equal */
  922. }
  923. return -1; /* s1 < s2 */
  924. }
  925. if ( s2 == NULL ) {
  926. return 1; /* s1 > s2 */
  927. }
  928. return strcmp( s1, s2 );
  929. }
  930. /*
  931. * Invoke strcmp() on each string in an array. If one array has fewer elements
  932. * than the other, it is treated as "less than" the other. Two NULL or
  933. * empty arrays (or one NULL and one empty) are considered to be equivalent.
  934. *
  935. * If ignorestr is non-NULL, occurrences of that string are ignored.
  936. */
  937. static int
  938. schema_strcmp_array( char **sa1, char **sa2, const char *ignorestr )
  939. {
  940. int i1, i2, rc;
  941. if ( sa1 == NULL || *sa1 == NULL ) {
  942. if ( sa2 == NULL || *sa2 == NULL ) {
  943. return 0; /* equal */
  944. }
  945. return -1; /* sa1 < sa2 */
  946. }
  947. if ( sa2 == NULL || *sa2 == NULL ) {
  948. return 1; /* sa1 > sa2 */
  949. }
  950. rc = 0;
  951. i1 = i2 = 0;
  952. while ( sa1[i1] != NULL && sa2[i2] != NULL ) {
  953. if ( NULL != ignorestr ) {
  954. if ( 0 == strcmp( sa1[i1], ignorestr )) {
  955. ++i1;
  956. continue;
  957. }
  958. if ( 0 == strcmp( sa2[i2], ignorestr )) {
  959. ++i2;
  960. continue;
  961. }
  962. }
  963. rc = strcmp( sa1[i1], sa2[i2] );
  964. ++i1;
  965. ++i2;
  966. }
  967. if ( rc == 0 ) { /* all matched so far */
  968. /* get rid of trailing ignored strings (if any) */
  969. if ( NULL != ignorestr ) {
  970. if ( sa1[i1] != NULL && 0 == strcmp( sa1[i1], ignorestr )) {
  971. ++i1;
  972. }
  973. if ( sa2[i2] != NULL && 0 == strcmp( sa2[i2], ignorestr )) {
  974. ++i2;
  975. }
  976. }
  977. /* check for differing array lengths */
  978. if ( sa2[i2] != NULL ) {
  979. rc = -1; /* sa1 < sa2 -- fewer elements */
  980. } else if ( sa1[i1] != NULL ) {
  981. rc = 1; /* sa1 > sa2 -- more elements */
  982. }
  983. }
  984. return rc;
  985. }
  986. struct attr_enum_wrapper {
  987. Slapi_Attr **attrs;
  988. int enquote_sup_oc;
  989. struct sizedbuffer *psbAttrTypes;
  990. int user_defined_only;
  991. int schema_ds4x_compat;
  992. };
  993. static int
  994. schema_attr_enum_callback(struct asyntaxinfo *asip, void *arg)
  995. {
  996. struct attr_enum_wrapper *aew = (struct attr_enum_wrapper *)arg;
  997. int aliaslen = 0;
  998. struct berval val;
  999. struct berval *vals[2] = {0, 0};
  1000. const char *attr_desc, *syntaxoid;
  1001. char *outp, syntaxlengthbuf[ 128 ];
  1002. int i;
  1003. vals[0] = &val;
  1004. if (!asip) {
  1005. LDAPDebug(LDAP_DEBUG_ANY,
  1006. "Error: no attribute types in schema_attr_enum_callback\n",
  1007. 0, 0, 0);
  1008. return ATTR_SYNTAX_ENUM_NEXT;
  1009. }
  1010. if (aew->user_defined_only &&
  1011. (asip->asi_flags & SLAPI_ATTR_FLAG_STD_ATTR)) {
  1012. return ATTR_SYNTAX_ENUM_NEXT; /* not user defined */
  1013. }
  1014. if ( aew->schema_ds4x_compat ) {
  1015. attr_desc = ( asip->asi_flags & SLAPI_ATTR_FLAG_STD_ATTR)
  1016. ? ATTR_STANDARD_STRING : ATTR_USERDEF_STRING;
  1017. } else {
  1018. attr_desc = asip->asi_desc;
  1019. }
  1020. if ( asip->asi_aliases != NULL ) {
  1021. for ( i = 0; asip->asi_aliases[i] != NULL; ++i ) {
  1022. aliaslen += strlen( asip->asi_aliases[i] );
  1023. }
  1024. }
  1025. syntaxoid = plugin_syntax2oid(asip->asi_plugin);
  1026. if ( !aew->schema_ds4x_compat &&
  1027. asip->asi_syntaxlength != SLAPI_SYNTAXLENGTH_NONE ) {
  1028. /* sprintf() is safe because syntaxlengthbuf is large enough */
  1029. sprintf( syntaxlengthbuf, "{%d}", asip->asi_syntaxlength );
  1030. } else {
  1031. *syntaxlengthbuf = '\0';
  1032. }
  1033. /*
  1034. * XXX: 256 is a magic number... it must be big enough to account for
  1035. * all of the fixed sized items we output.
  1036. */
  1037. sizedbuffer_allocate(aew->psbAttrTypes,256+strlen(asip->asi_oid)+
  1038. strlen(asip->asi_name) +
  1039. aliaslen + strlen_null_ok(attr_desc) +
  1040. strlen(syntaxoid) +
  1041. strlen_null_ok(asip->asi_superior) +
  1042. strlen_null_ok(asip->asi_mr_equality) +
  1043. strlen_null_ok(asip->asi_mr_ordering) +
  1044. strlen_null_ok(asip->asi_mr_substring) +
  1045. strcat_qdlist( NULL, "X-ORIGIN", asip->asi_origin ));
  1046. /*
  1047. * Overall strategy is to maintain a pointer to the next location in
  1048. * the output buffer so we can do simple strcpy's, sprintf's, etc.
  1049. * That pointer is `outp'. Each item that is output includes a trailing
  1050. * space, so there is no need to include a leading one in the next item.
  1051. */
  1052. outp = aew->psbAttrTypes->buffer;
  1053. outp += sprintf(outp, "( %s NAME ", asip->asi_oid);
  1054. if ( asip->asi_aliases == NULL || asip->asi_aliases[0] == NULL ) {
  1055. /* only one name */
  1056. outp += sprintf(outp, "'%s' ", asip->asi_name);
  1057. } else {
  1058. /* several names */
  1059. outp += sprintf(outp, "( '%s' ", asip->asi_name);
  1060. for ( i = 0; asip->asi_aliases[i] != NULL; ++i ) {
  1061. outp += sprintf(outp, "'%s' ", asip->asi_aliases[i]);
  1062. }
  1063. outp += strcpy_count(outp, ") ");
  1064. }
  1065. /* DESC is optional */
  1066. if (attr_desc && *attr_desc) {
  1067. outp += sprintf( outp, "DESC '%s'", attr_desc );
  1068. }
  1069. if ( !aew->schema_ds4x_compat &&
  1070. ( asip->asi_flags & SLAPI_ATTR_FLAG_OBSOLETE )) {
  1071. outp += strcpy_count( outp, schema_obsolete_with_spaces );
  1072. } else {
  1073. outp += strcpy_count( outp, " " );
  1074. }
  1075. if ( !aew->schema_ds4x_compat ) {
  1076. outp += put_tagged_oid( outp, "SUP ",
  1077. asip->asi_superior, NULL, aew->enquote_sup_oc );
  1078. outp += put_tagged_oid( outp, "EQUALITY ",
  1079. asip->asi_mr_equality, NULL, aew->enquote_sup_oc );
  1080. outp += put_tagged_oid( outp, "ORDERING ",
  1081. asip->asi_mr_ordering, NULL, aew->enquote_sup_oc );
  1082. outp += put_tagged_oid( outp, "SUBSTR ",
  1083. asip->asi_mr_substring, NULL, aew->enquote_sup_oc );
  1084. }
  1085. outp += put_tagged_oid( outp, "SYNTAX ", syntaxoid, syntaxlengthbuf,
  1086. aew->enquote_sup_oc );
  1087. if (asip->asi_flags & SLAPI_ATTR_FLAG_SINGLE) {
  1088. outp += strcpy_count(outp, "SINGLE-VALUE ");
  1089. }
  1090. if ( !aew->schema_ds4x_compat ) {
  1091. if (asip->asi_flags & SLAPI_ATTR_FLAG_COLLECTIVE ) {
  1092. outp += strcpy_count( outp, 1 + schema_collective_with_spaces );
  1093. }
  1094. if (asip->asi_flags & SLAPI_ATTR_FLAG_NOUSERMOD ) {
  1095. outp += strcpy_count( outp, 1 + schema_nousermod_with_spaces );
  1096. }
  1097. if (asip->asi_flags & SLAPI_ATTR_FLAG_OPATTR) {
  1098. outp += strcpy_count(outp, "USAGE directoryOperation ");
  1099. }
  1100. outp += strcat_qdlist( outp, "X-ORIGIN", asip->asi_origin );
  1101. }
  1102. outp += strcpy_count(outp, ")");
  1103. val.bv_val = aew->psbAttrTypes->buffer;
  1104. val.bv_len = outp - aew->psbAttrTypes->buffer;
  1105. attrlist_merge(aew->attrs, "attributetypes", vals);
  1106. return ATTR_SYNTAX_ENUM_NEXT;
  1107. }
  1108. struct syntax_enum_wrapper {
  1109. Slapi_Attr **attrs;
  1110. struct sizedbuffer *psbSyntaxDescription;
  1111. };
  1112. static int
  1113. schema_syntax_enum_callback(char **names, Slapi_PluginDesc *plugindesc,
  1114. void *arg)
  1115. {
  1116. struct syntax_enum_wrapper *sew = (struct syntax_enum_wrapper *)arg;
  1117. char *oid, *desc;
  1118. int i;
  1119. struct berval val;
  1120. struct berval *vals[2] = {0, 0};
  1121. vals[0] = &val;
  1122. oid = NULL;
  1123. if ( names != NULL ) {
  1124. for ( i = 0; names[i] != NULL; ++i ) {
  1125. if ( isdigit( names[i][0] )) {
  1126. oid = names[i];
  1127. break;
  1128. }
  1129. }
  1130. }
  1131. if ( oid == NULL ) { /* must have an OID */
  1132. LDAPDebug(LDAP_DEBUG_ANY, "Error: no OID found in"
  1133. " schema_syntax_enum_callback for syntax %s\n",
  1134. ( names == NULL ) ? "unknown" : names[0], 0, 0);
  1135. return 1;
  1136. }
  1137. desc = names[0]; /* by convention, the first name is the "official" one */
  1138. /*
  1139. * RFC 2252 section 4.3.3 Syntax Description says:
  1140. *
  1141. * The following BNF may be used to associate a short description with a
  1142. * syntax OBJECT IDENTIFIER. Implementors should note that future
  1143. * versions of this document may expand this definition to include
  1144. * additional terms. Terms whose identifier begins with "X-" are
  1145. * reserved for private experiments, and MUST be followed by a
  1146. * <qdstrings>.
  1147. *
  1148. * SyntaxDescription = "(" whsp
  1149. * numericoid whsp
  1150. * [ "DESC" qdstring ]
  1151. * whsp ")"
  1152. *
  1153. * And section 5.3.1 ldapSyntaxes says:
  1154. *
  1155. * Servers MAY use this attribute to list the syntaxes which are
  1156. * implemented. Each value corresponds to one syntax.
  1157. *
  1158. * ( 1.3.6.1.4.1.1466.101.120.16 NAME 'ldapSyntaxes'
  1159. * EQUALITY objectIdentifierFirstComponentMatch
  1160. * SYNTAX 1.3.6.1.4.1.1466.115.121.1.54 USAGE directoryOperation )
  1161. */
  1162. if ( desc == NULL ) {
  1163. /* allocate enough room for "( )" and '\0' at end */
  1164. sizedbuffer_allocate(sew->psbSyntaxDescription, strlen(oid) + 5);
  1165. sprintf(sew->psbSyntaxDescription->buffer, "( %s )", oid );
  1166. } else {
  1167. /* allocate enough room for "( ) DESC '' " and '\0' at end */
  1168. sizedbuffer_allocate(sew->psbSyntaxDescription,
  1169. strlen(oid) + strlen(desc) + 13);
  1170. sprintf(sew->psbSyntaxDescription->buffer, "( %s DESC '%s' )",
  1171. oid, desc );
  1172. }
  1173. val.bv_val = sew->psbSyntaxDescription->buffer;
  1174. val.bv_len = strlen(sew->psbSyntaxDescription->buffer);
  1175. attrlist_merge(sew->attrs, "ldapSyntaxes", vals);
  1176. return 1;
  1177. }
  1178. struct listargs{
  1179. char **attrs;
  1180. unsigned long flag;
  1181. };
  1182. static int
  1183. schema_list_attributes_callback(struct asyntaxinfo *asi, void *arg)
  1184. {
  1185. struct listargs *aew = (struct listargs *)arg;
  1186. if (!asi) {
  1187. LDAPDebug(LDAP_DEBUG_ANY, "Error: no attribute types in schema_list_attributes_callback\n",
  1188. 0, 0, 0);
  1189. return ATTR_SYNTAX_ENUM_NEXT;
  1190. }
  1191. if (aew->flag && (asi->asi_flags & aew->flag)) {
  1192. charray_add(&aew->attrs, slapi_ch_strdup(asi->asi_name));
  1193. if (NULL != asi->asi_aliases) {
  1194. int i;
  1195. for ( i = 0; asi->asi_aliases[i] != NULL; ++i ) {
  1196. charray_add(&aew->attrs,
  1197. slapi_ch_strdup(asi->asi_aliases[i]));
  1198. }
  1199. }
  1200. }
  1201. return ATTR_SYNTAX_ENUM_NEXT;
  1202. }
  1203. /* Return the list of attributes names matching attribute flags */
  1204. char **
  1205. slapi_schema_list_attribute_names(unsigned long flag)
  1206. {
  1207. struct listargs aew;
  1208. memset(&aew,0,sizeof(struct listargs));
  1209. aew.flag=flag;
  1210. attr_syntax_enumerate_attrs(schema_list_attributes_callback, &aew,
  1211. PR_FALSE);
  1212. return aew.attrs;
  1213. }
  1214. /*
  1215. * returntext is always at least SLAPI_DSE_RETURNTEXT_SIZE bytes in size.
  1216. */
  1217. int
  1218. read_schema_dse(
  1219. Slapi_PBlock *pb,
  1220. Slapi_Entry *pschema_info_e,
  1221. Slapi_Entry *entryAfter,
  1222. int *returncode,
  1223. char *returntext /* not used */,
  1224. void *arg /* not used */ )
  1225. {
  1226. struct berval val;
  1227. struct berval *vals[2];
  1228. int i;
  1229. struct objclass *oc;
  1230. struct matchingRuleList *mrl=NULL;
  1231. struct sizedbuffer *psbObjectClasses= sizedbuffer_construct(BUFSIZ);
  1232. struct sizedbuffer *psbAttrTypes= sizedbuffer_construct(BUFSIZ);
  1233. struct sizedbuffer *psbMatchingRule= sizedbuffer_construct(BUFSIZ);
  1234. struct sizedbuffer *psbSyntaxDescription = sizedbuffer_construct(BUFSIZ);
  1235. struct attr_enum_wrapper aew;
  1236. struct syntax_enum_wrapper sew;
  1237. int enquote_sup_oc = config_get_enquote_sup_oc();
  1238. PRUint32 schema_flags = 0;
  1239. int user_defined_only = 0;
  1240. char **allowed, **required;
  1241. char *mr_desc, *mr_name, *oc_description;
  1242. int schema_ds4x_compat = config_get_ds4_compatible_schema();
  1243. const CSN *csn;
  1244. vals[0] = &val;
  1245. vals[1] = NULL;
  1246. slapi_pblock_get(pb, SLAPI_SCHEMA_FLAGS, (void*)&schema_flags);
  1247. user_defined_only = (schema_flags & DSE_SCHEMA_USER_DEFINED_ONLY) ? 1 : 0;
  1248. attrlist_delete (&pschema_info_e->e_attrs, "objectclasses");
  1249. attrlist_delete (&pschema_info_e->e_attrs, "attributetypes");
  1250. attrlist_delete (&pschema_info_e->e_attrs, "matchingRules");
  1251. attrlist_delete (&pschema_info_e->e_attrs, "ldapSyntaxes");
  1252. /*
  1253. attrlist_delete (&pschema_info_e->e_attrs, "matchingRuleUse");
  1254. */
  1255. schema_dse_lock_read();
  1256. /* return the objectclasses */
  1257. oc_lock_read();
  1258. for (oc = g_get_global_oc_nolock(); oc != NULL; oc = oc->oc_next)
  1259. {
  1260. size_t size= 0;
  1261. int need_extra_space = 1;
  1262. if (user_defined_only &&
  1263. !(oc->oc_flags & OC_FLAG_USER_OC ||
  1264. oc->oc_flags & OC_FLAG_REDEFINED_OC)) {
  1265. continue;
  1266. }
  1267. /*
  1268. * XXX: 256 is a magic number... it must be large enough to fit
  1269. * all of the fixed size items including description (DESC),
  1270. * kind (STRUCTURAL, AUXILIARY, or ABSTRACT), and the OBSOLETE flag.
  1271. */
  1272. if ( schema_ds4x_compat ) {
  1273. oc_description = (oc->oc_flags & OC_FLAG_STANDARD_OC) ?
  1274. OC_STANDARD_STRING : OC_USERDEF_STRING;
  1275. } else {
  1276. oc_description = oc->oc_desc;
  1277. }
  1278. size= 256+strlen_null_ok(oc->oc_oid) + strlen(oc->oc_name) +
  1279. strlen_null_ok(oc_description) +
  1280. strcat_qdlist( NULL, "X-ORIGIN", oc->oc_origin );
  1281. required = schema_ds4x_compat ? oc->oc_required : oc->oc_orig_required;
  1282. if (required && required[0]) {
  1283. for (i = 0 ; required[i]; i++)
  1284. size+= 16 + strlen(required[i]);
  1285. }
  1286. allowed = schema_ds4x_compat ? oc->oc_allowed : oc->oc_orig_allowed;
  1287. if (allowed && allowed[0]) {
  1288. for (i = 0 ; allowed[i]; i++)
  1289. size+= 16 + strlen(allowed[i]);
  1290. }
  1291. sizedbuffer_allocate(psbObjectClasses,size);
  1292. /* put the OID and the NAME */
  1293. sprintf (psbObjectClasses->buffer,
  1294. "( %s NAME '%s'",
  1295. (oc->oc_oid) ? oc->oc_oid : "",
  1296. oc->oc_name);
  1297. /* The DESC (description) is OPTIONAL */
  1298. if (oc_description) {
  1299. strcat(psbObjectClasses->buffer, " DESC '");
  1300. /* We want to list an empty description
  1301. * element if it was defined that way. */
  1302. if (*oc_description) {
  1303. strcat(psbObjectClasses->buffer, oc_description);
  1304. }
  1305. strcat(psbObjectClasses->buffer, "'");
  1306. need_extra_space = 1;
  1307. }
  1308. /* put the OBSOLETE keyword */
  1309. if (!schema_ds4x_compat && (oc->oc_flags & OC_FLAG_OBSOLETE)) {
  1310. strcat(psbObjectClasses->buffer, schema_obsolete_with_spaces);
  1311. need_extra_space = 0;
  1312. }
  1313. /* put the SUP superior objectclass */
  1314. if (0 != strcasecmp(oc->oc_name, "top")) { /* top has no SUP */
  1315. /* some AUXILIARY AND ABSTRACT objectclasses may not have a SUP either */
  1316. /* for compatability, every objectclass other than top must have a SUP */
  1317. if (schema_ds4x_compat || (oc->oc_superior && *oc->oc_superior)) {
  1318. if (need_extra_space) {
  1319. strcat(psbObjectClasses->buffer, " ");
  1320. }
  1321. strcat(psbObjectClasses->buffer, "SUP ");
  1322. strcat(psbObjectClasses->buffer, (enquote_sup_oc ? "'" : ""));
  1323. strcat(psbObjectClasses->buffer,
  1324. ((oc->oc_superior && *oc->oc_superior) ?
  1325. oc->oc_superior : "top"));
  1326. strcat(psbObjectClasses->buffer, (enquote_sup_oc ? "'" : ""));
  1327. need_extra_space = 1;
  1328. }
  1329. }
  1330. /* put the kind of objectclass */
  1331. if (schema_ds4x_compat) {
  1332. if (need_extra_space) {
  1333. strcat(psbObjectClasses->buffer, " ");
  1334. }
  1335. } else {
  1336. strcat(psbObjectClasses->buffer, schema_oc_kind_strings_with_spaces[oc->oc_kind]);
  1337. }
  1338. strcat_oids( psbObjectClasses->buffer, "MUST", required,
  1339. schema_ds4x_compat );
  1340. strcat_oids( psbObjectClasses->buffer, "MAY", allowed,
  1341. schema_ds4x_compat );
  1342. if ( !schema_ds4x_compat ) {
  1343. strcat_qdlist( psbObjectClasses->buffer, "X-ORIGIN", oc->oc_origin );
  1344. }
  1345. strcat( psbObjectClasses->buffer, ")");
  1346. val.bv_val = psbObjectClasses->buffer;
  1347. val.bv_len = strlen (psbObjectClasses->buffer);
  1348. attrlist_merge (&pschema_info_e->e_attrs, "objectclasses", vals);
  1349. }
  1350. oc_unlock();
  1351. /* now return the attrs */
  1352. aew.attrs = &pschema_info_e->e_attrs;
  1353. aew.enquote_sup_oc = enquote_sup_oc;
  1354. aew.psbAttrTypes = psbAttrTypes;
  1355. aew.user_defined_only = user_defined_only;
  1356. aew.schema_ds4x_compat = schema_ds4x_compat;
  1357. attr_syntax_enumerate_attrs(schema_attr_enum_callback, &aew, PR_FALSE);
  1358. /* return the set of matching rules we support */
  1359. for (mrl = g_get_global_mrl(); !user_defined_only && mrl != NULL; mrl = mrl->mrl_next) {
  1360. mr_name = mrl->mr_entry->mr_name ? mrl->mr_entry->mr_name : "";
  1361. mr_desc = mrl->mr_entry->mr_desc ? mrl->mr_entry->mr_desc : "";
  1362. sizedbuffer_allocate(psbMatchingRule,128+
  1363. strlen_null_ok(mrl->mr_entry->mr_oid) +
  1364. strlen(mr_name)+ strlen(mr_desc)+
  1365. strlen_null_ok(mrl->mr_entry->mr_syntax));
  1366. if ( schema_ds4x_compat ) {
  1367. sprintf(psbMatchingRule->buffer,
  1368. "( %s NAME '%s' DESC '%s' SYNTAX %s%s%s )",
  1369. (mrl->mr_entry->mr_oid ? mrl->mr_entry->mr_oid : ""),
  1370. mr_name, mr_desc,
  1371. enquote_sup_oc ? "'" : "",
  1372. mrl->mr_entry->mr_syntax ? mrl->mr_entry->mr_syntax : "" ,
  1373. enquote_sup_oc ? "'" : "");
  1374. } else if ( NULL != mrl->mr_entry->mr_oid &&
  1375. NULL != mrl->mr_entry->mr_syntax ) {
  1376. char *p;
  1377. sprintf(psbMatchingRule->buffer, "( %s ", mrl->mr_entry->mr_oid );
  1378. p = psbMatchingRule->buffer + strlen(psbMatchingRule->buffer);
  1379. if ( *mr_name != '\0' ) {
  1380. sprintf(p, "NAME '%s' ", mr_name );
  1381. p += strlen(p);
  1382. }
  1383. if ( *mr_desc != '\0' ) {
  1384. sprintf(p, "DESC '%s' ", mr_desc );
  1385. p += strlen(p);
  1386. }
  1387. sprintf(p, "SYNTAX %s )", mrl->mr_entry->mr_syntax );
  1388. }
  1389. val.bv_val = psbMatchingRule->buffer;
  1390. val.bv_len = strlen (psbMatchingRule->buffer);
  1391. attrlist_merge (&pschema_info_e->e_attrs, "matchingRules", vals);
  1392. }
  1393. if ( !schema_ds4x_compat && !user_defined_only ) {
  1394. /* return the set of syntaxes we support */
  1395. sew.attrs = &pschema_info_e->e_attrs;
  1396. sew.psbSyntaxDescription = psbSyntaxDescription;
  1397. plugin_syntax_enumerate(schema_syntax_enum_callback, &sew);
  1398. }
  1399. csn = g_get_global_schema_csn();
  1400. if (NULL != csn) {
  1401. char csn_str[CSN_STRSIZE + 1];
  1402. csn_as_string(csn, PR_FALSE, csn_str);
  1403. slapi_entry_attr_delete(pschema_info_e, "nsschemacsn");
  1404. slapi_entry_add_string(pschema_info_e, "nsschemacsn", csn_str);
  1405. }
  1406. schema_dse_unlock();
  1407. sizedbuffer_destroy(psbObjectClasses);
  1408. sizedbuffer_destroy(psbAttrTypes);
  1409. sizedbuffer_destroy(psbMatchingRule);
  1410. sizedbuffer_destroy(psbSyntaxDescription);
  1411. *returncode= LDAP_SUCCESS;
  1412. return SLAPI_DSE_CALLBACK_OK;
  1413. }
  1414. /* helper for deleting mods (we do not want to be applied) from the mods array */
  1415. static void
  1416. mod_free(LDAPMod *mod)
  1417. {
  1418. ber_bvecfree(mod->mod_bvalues);
  1419. slapi_ch_free((void**)&(mod->mod_type));
  1420. slapi_ch_free((void**)&mod);
  1421. }
  1422. /*
  1423. * modify_schema_dse: called by do_modify() when target is cn=schema
  1424. *
  1425. * Add/Delete attributes and objectclasses from the schema
  1426. * Supported mod_ops are LDAP_MOD_DELETE and LDAP_MOD_ADD
  1427. *
  1428. * Note that the in-memory DSE Slapi_Entry object does NOT hold the
  1429. * attributeTypes and objectClasses attributes -- it only holds
  1430. * non-schema related attributes such as aci.
  1431. *
  1432. * returntext is always at least SLAPI_DSE_RETURNTEXT_SIZE bytes in size.
  1433. */
  1434. int
  1435. modify_schema_dse (Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg)
  1436. {
  1437. int i, rc= SLAPI_DSE_CALLBACK_OK; /* default is to apply changes to the DSE */
  1438. char *schema_dse_attr_name;
  1439. LDAPMod **mods = NULL;
  1440. int num_mods = 0; /* count the number of mods */
  1441. int schema_ds4x_compat = config_get_ds4_compatible_schema();
  1442. int reapply_mods = 0;
  1443. int is_replicated_operation = 0;
  1444. slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
  1445. slapi_pblock_get( pb, SLAPI_IS_REPLICATED_OPERATION, &is_replicated_operation);
  1446. schema_dse_lock_write();
  1447. /*
  1448. * Process each modification. Stop as soon as we hit an error.
  1449. *
  1450. * XXXmcs: known bugs: we don't operate on a copy of the schema, so it
  1451. * is possible for some schema changes to be made but not all of them.
  1452. * True for DS 4.x as well, although it tried to keep going even after
  1453. * an error was detected (which was very wrong).
  1454. */
  1455. for (i = 0; rc == SLAPI_DSE_CALLBACK_OK && mods[i]; i++) {
  1456. schema_dse_attr_name = (char *) mods[i]->mod_type;
  1457. num_mods++; /* incr the number of mods */
  1458. /*
  1459. * skip attribute types that we do not recognize (the DSE code will
  1460. * handle them).
  1461. */
  1462. if ( !schema_type_is_interesting( schema_dse_attr_name )) {
  1463. continue;
  1464. }
  1465. /*
  1466. * Delete an objectclass or attribute
  1467. */
  1468. if (SLAPI_IS_MOD_DELETE(mods[i]->mod_op)) {
  1469. if (strcasecmp (mods[i]->mod_type, "objectclasses") == 0) {
  1470. *returncode = schema_delete_objectclasses (entryBefore, mods[i],
  1471. returntext, SLAPI_DSE_RETURNTEXT_SIZE, schema_ds4x_compat );
  1472. }
  1473. else if (strcasecmp (mods[i]->mod_type, "attributetypes") == 0) {
  1474. *returncode = schema_delete_attributes (entryBefore, mods[i],
  1475. returntext, SLAPI_DSE_RETURNTEXT_SIZE );
  1476. }
  1477. else {
  1478. *returncode= LDAP_NO_SUCH_ATTRIBUTE;
  1479. schema_create_errormsg( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  1480. schema_errprefix_generic, mods[i]->mod_type,
  1481. "Only object classes and attribute types may be deleted" );
  1482. }
  1483. if ( LDAP_SUCCESS != *returncode ) {
  1484. rc= SLAPI_DSE_CALLBACK_ERROR;
  1485. } else {
  1486. reapply_mods = 1;
  1487. }
  1488. }
  1489. /*
  1490. * Replace an objectclass,attribute, or schema CSN
  1491. */
  1492. else if (SLAPI_IS_MOD_REPLACE(mods[i]->mod_op)) {
  1493. int replace_allowed = 0;
  1494. slapdFrontendConfig_t *slapdFrontendConfig;
  1495. slapdFrontendConfig = getFrontendConfig();
  1496. CFG_LOCK_READ( slapdFrontendConfig );
  1497. if ( 0 == strcasecmp( slapdFrontendConfig->schemareplace,
  1498. CONFIG_SCHEMAREPLACE_STR_ON )) {
  1499. replace_allowed = 1;
  1500. } else if ( 0 == strcasecmp( slapdFrontendConfig->schemareplace,
  1501. CONFIG_SCHEMAREPLACE_STR_REPLICATION_ONLY )) {
  1502. replace_allowed = is_replicated_operation;
  1503. }
  1504. CFG_UNLOCK_READ( slapdFrontendConfig );
  1505. if ( !replace_allowed ) {
  1506. *returncode= LDAP_UNWILLING_TO_PERFORM;
  1507. schema_create_errormsg( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  1508. schema_errprefix_generic, mods[i]->mod_type,
  1509. "Replace is not allowed on the subschema subentry" );
  1510. rc = SLAPI_DSE_CALLBACK_ERROR;
  1511. } else {
  1512. if (strcasecmp (mods[i]->mod_type, "attributetypes") == 0) {
  1513. /*
  1514. * Replace all attribute types
  1515. */
  1516. *returncode = schema_replace_attributes( pb, mods[i], returntext,
  1517. SLAPI_DSE_RETURNTEXT_SIZE );
  1518. } else if (strcasecmp (mods[i]->mod_type, "objectclasses") == 0) {
  1519. /*
  1520. * Replace all objectclasses
  1521. */
  1522. *returncode = schema_replace_objectclasses( pb, mods[i],
  1523. returntext, SLAPI_DSE_RETURNTEXT_SIZE );
  1524. } else if (strcasecmp (mods[i]->mod_type, "nsschemacsn") == 0) {
  1525. if (is_replicated_operation) {
  1526. /* Update the schema CSN */
  1527. if (mods[i]->mod_bvalues && mods[i]->mod_bvalues[0] &&
  1528. mods[i]->mod_bvalues[0]->bv_val &&
  1529. mods[i]->mod_bvalues[0]->bv_len > 0) {
  1530. char new_csn_string[CSN_STRSIZE + 1];
  1531. CSN *new_schema_csn;
  1532. memcpy(new_csn_string, mods[i]->mod_bvalues[0]->bv_val,
  1533. mods[i]->mod_bvalues[0]->bv_len);
  1534. new_csn_string[mods[i]->mod_bvalues[0]->bv_len] = '\0';
  1535. new_schema_csn = csn_new_by_string(new_csn_string);
  1536. if (NULL != new_schema_csn) {
  1537. g_set_global_schema_csn(new_schema_csn); /* csn is consumed */
  1538. }
  1539. }
  1540. }
  1541. } else {
  1542. *returncode= LDAP_UNWILLING_TO_PERFORM; /* XXXmcs: best error? */
  1543. schema_create_errormsg( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  1544. schema_errprefix_generic, mods[i]->mod_type,
  1545. "Only object classes and attribute types may be replaced" );
  1546. }
  1547. }
  1548. if ( LDAP_SUCCESS != *returncode ) {
  1549. rc= SLAPI_DSE_CALLBACK_ERROR;
  1550. } else {
  1551. reapply_mods = 1; /* we have at least some modifications we need to reapply */
  1552. }
  1553. }
  1554. /*
  1555. * Add an objectclass or attribute
  1556. */
  1557. else if (SLAPI_IS_MOD_ADD(mods[i]->mod_op)) {
  1558. if (strcasecmp (mods[i]->mod_type, "attributetypes") == 0) {
  1559. /*
  1560. * Add a new attribute
  1561. */
  1562. *returncode = schema_add_attribute ( pb, mods[i], returntext,
  1563. SLAPI_DSE_RETURNTEXT_SIZE, schema_ds4x_compat );
  1564. }
  1565. else if (strcasecmp (mods[i]->mod_type, "objectclasses") == 0) {
  1566. /*
  1567. * Add a new objectclass
  1568. */
  1569. *returncode = schema_add_objectclass ( pb, mods[i], returntext,
  1570. SLAPI_DSE_RETURNTEXT_SIZE, schema_ds4x_compat );
  1571. }
  1572. else {
  1573. if ( schema_ds4x_compat ) {
  1574. *returncode= LDAP_NO_SUCH_ATTRIBUTE;
  1575. } else {
  1576. *returncode= LDAP_UNWILLING_TO_PERFORM; /* XXXmcs: best error? */
  1577. }
  1578. schema_create_errormsg( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  1579. schema_errprefix_generic, mods[i]->mod_type,
  1580. "Only object classes and attribute types may be added" );
  1581. }
  1582. if ( LDAP_SUCCESS != *returncode ) {
  1583. rc= SLAPI_DSE_CALLBACK_ERROR;
  1584. } else {
  1585. reapply_mods = 1; /* we have at least some modifications we need to reapply */
  1586. }
  1587. }
  1588. /*
  1589. ** No value was specified to modify, the user probably tried
  1590. ** to delete all attributetypes or all objectclasses, which
  1591. ** isn't allowed
  1592. */
  1593. if (!mods[i]->mod_vals.modv_strvals)
  1594. {
  1595. if ( schema_ds4x_compat ) {
  1596. *returncode= LDAP_INVALID_SYNTAX;
  1597. } else {
  1598. *returncode= LDAP_UNWILLING_TO_PERFORM; /* XXXmcs: best error? */
  1599. }
  1600. schema_create_errormsg( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  1601. schema_errprefix_generic, mods[i]->mod_type,
  1602. "No target attribute type or object class specified" );
  1603. rc= SLAPI_DSE_CALLBACK_ERROR;
  1604. }
  1605. }
  1606. if(rc==SLAPI_DSE_CALLBACK_OK && reapply_mods)
  1607. {
  1608. CSN *new_schema_csn;
  1609. int newindex = 0; /* mods array index */
  1610. /* tell the "unholy" dse_modify code to reapply the mods and use
  1611. that result instead of the initial result; we must remove the attributes
  1612. we manage in this code from the mods
  1613. */
  1614. slapi_pblock_set(pb, SLAPI_DSE_REAPPLY_MODS, (void *)&reapply_mods);
  1615. /* because we are reapplying the mods, we want the entryAfter to
  1616. look just like the entryBefore, except that "our" attributes
  1617. will have been removed
  1618. */
  1619. /* delete the mods from the mods array */
  1620. for (i = 0; i < num_mods ; i++) {
  1621. const char *attrname = mods[i]->mod_type;
  1622. /* delete this attr from the entry */
  1623. slapi_entry_attr_delete(entryAfter, attrname);
  1624. if ( schema_type_is_interesting( attrname )) {
  1625. mod_free(mods[i]);
  1626. mods[i] = NULL;
  1627. } else {
  1628. /* add the original value of the attr back to the entry after */
  1629. Slapi_Attr *origattr = NULL;
  1630. Slapi_ValueSet *origvalues = NULL;
  1631. slapi_entry_attr_find(entryBefore, attrname, &origattr);
  1632. if (NULL != origattr) {
  1633. slapi_attr_get_valueset(origattr, &origvalues);
  1634. if (NULL != origvalues) {
  1635. slapi_entry_add_valueset(entryAfter, attrname, origvalues);
  1636. slapi_valueset_free(origvalues);
  1637. }
  1638. }
  1639. mods[newindex++] = mods[i];
  1640. }
  1641. }
  1642. mods[newindex] = NULL;
  1643. /*
  1644. * Since we successfully updated the schema, we need to generate
  1645. * a new schema CSN for non-replicated operations.
  1646. */
  1647. /* XXXmcs: I wonder if we should update the schema CSN even when no
  1648. * attribute types or OCs were changed? That way, an administrator
  1649. * could force schema replication to occur by submitting a modify
  1650. * operation that did not really do anything, such as:
  1651. *
  1652. * dn:cn=schema
  1653. * changetype:modify
  1654. * replace:cn
  1655. * cn:schema
  1656. */
  1657. if (!is_replicated_operation)
  1658. {
  1659. new_schema_csn = csn_new();
  1660. if (NULL != new_schema_csn) {
  1661. char csn_str[CSN_STRSIZE + 1];
  1662. csn_set_replicaid(new_schema_csn, 0);
  1663. csn_set_time(new_schema_csn, current_time());
  1664. g_set_global_schema_csn(new_schema_csn);
  1665. slapi_entry_attr_delete(entryBefore, "nsschemacsn");
  1666. csn_as_string(new_schema_csn, PR_FALSE, csn_str);
  1667. slapi_entry_add_string(entryBefore, "nsschemacsn", csn_str);
  1668. }
  1669. }
  1670. }
  1671. schema_dse_unlock();
  1672. return rc;
  1673. }
  1674. CSN *
  1675. dup_global_schema_csn()
  1676. {
  1677. CSN *schema_csn;
  1678. schema_dse_lock_read();
  1679. schema_csn = csn_dup ( g_get_global_schema_csn() );
  1680. schema_dse_unlock();
  1681. return schema_csn;
  1682. }
  1683. /*
  1684. * Remove all attribute types and objectclasses from the entry and
  1685. * then add back the user defined ones based on the contents of the
  1686. * schema hash tables.
  1687. *
  1688. * Returns SLAPI_DSE_CALLBACK_OK is all goes well.
  1689. *
  1690. * returntext is always at least SLAPI_DSE_RETURNTEXT_SIZE bytes in size.
  1691. */
  1692. static int
  1693. refresh_user_defined_schema( Slapi_PBlock *pb, Slapi_Entry *pschema_info_e, Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg /* not used */ )
  1694. {
  1695. int rc;
  1696. Slapi_PBlock *mypbptr = pb;
  1697. Slapi_PBlock mypb;
  1698. const CSN *schema_csn;
  1699. PRUint32 schema_flags = DSE_SCHEMA_USER_DEFINED_ONLY;
  1700. pblock_init(&mypb);
  1701. slapi_entry_attr_delete( pschema_info_e, "objectclasses");
  1702. slapi_entry_attr_delete( pschema_info_e, "attributetypes");
  1703. /* for write callbacks, no pb is supplied, so use our own */
  1704. if (!mypbptr) {
  1705. mypbptr = &mypb;
  1706. }
  1707. slapi_pblock_set(mypbptr, SLAPI_SCHEMA_FLAGS, &schema_flags);
  1708. rc = read_schema_dse(mypbptr, pschema_info_e, NULL, returncode, returntext, NULL);
  1709. schema_csn = g_get_global_schema_csn();
  1710. if (NULL != schema_csn) {
  1711. char csn_str[CSN_STRSIZE + 1];
  1712. slapi_entry_attr_delete(pschema_info_e, "nsschemacsn");
  1713. csn_as_string(schema_csn, PR_FALSE, csn_str);
  1714. slapi_entry_add_string(pschema_info_e, "nsschemacsn", csn_str);
  1715. }
  1716. pblock_done(&mypb);
  1717. return rc;
  1718. }
  1719. /* oc_add_nolock
  1720. * Add the objectClass newoc to the global list of objectclasses
  1721. */
  1722. static void
  1723. oc_add_nolock(struct objclass *newoc)
  1724. {
  1725. struct objclass *poc;
  1726. poc = g_get_global_oc_nolock();
  1727. if ( NULL == poc ) {
  1728. g_set_global_oc_nolock(newoc);
  1729. } else {
  1730. for ( ; (poc != NULL) && (poc->oc_next != NULL); poc = poc->oc_next) {
  1731. ;
  1732. }
  1733. poc->oc_next = newoc;
  1734. newoc->oc_next = NULL;
  1735. }
  1736. }
  1737. static char **read_dollar_values ( char *vals) {
  1738. int i,k;
  1739. char **retVal;
  1740. static const char *charsToRemove = " ()";
  1741. /* get rid of all the parens and spaces */
  1742. for ( i = 0, k = 0; vals[i]; i++) {
  1743. if (!strchr(charsToRemove, vals[i])) {
  1744. vals[k++] = vals[i];
  1745. }
  1746. }
  1747. vals[k] = '\0';
  1748. retVal = slapi_str2charray (vals, "$");
  1749. return retVal;
  1750. }
  1751. /*
  1752. * Delete one or more objectClasses from our internal data structure.
  1753. *
  1754. * Return an LDAP error code (LDAP_SUCCESS if all goes well).
  1755. * If an error occurs, explanatory text is copied into 'errorbuf'.
  1756. *
  1757. * This function should not send an LDAP result; that is the caller's
  1758. * responsibility.
  1759. */
  1760. static int
  1761. schema_delete_objectclasses( Slapi_Entry *entryBefore, LDAPMod *mod,
  1762. char *errorbuf, size_t errorbufsize, int schema_ds4x_compat )
  1763. {
  1764. int i;
  1765. int rc = LDAP_SUCCESS; /* optimistic */
  1766. struct objclass *poc, *poc2, *delete_oc = NULL;
  1767. if ( NULL == mod->mod_bvalues ) {
  1768. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
  1769. NULL, "Cannot remove all schema object classes" );
  1770. return LDAP_UNWILLING_TO_PERFORM;
  1771. }
  1772. for (i = 0; mod->mod_bvalues[i]; i++) {
  1773. if ( LDAP_SUCCESS != ( rc = read_oc_ldif (
  1774. (const char *)mod->mod_bvalues[i]->bv_val, &delete_oc,
  1775. errorbuf, errorbufsize, 0, 0, schema_ds4x_compat))) {
  1776. return rc;
  1777. }
  1778. oc_lock_write();
  1779. if ((poc = oc_find_nolock(delete_oc->oc_name)) != NULL) {
  1780. /* check to see if any objectclasses inherit from this oc */
  1781. for (poc2 = g_get_global_oc_nolock(); poc2 != NULL; poc2 = poc2->oc_next) {
  1782. if (poc2->oc_superior &&
  1783. (strcasecmp (poc2->oc_superior, delete_oc->oc_name) == 0)) {
  1784. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
  1785. delete_oc->oc_name, "Cannot delete an object class"
  1786. " which has child object classes" );
  1787. rc = LDAP_UNWILLING_TO_PERFORM;
  1788. goto unlock_and_return;
  1789. }
  1790. }
  1791. if ( (poc->oc_flags & OC_FLAG_STANDARD_OC) == 0) {
  1792. oc_delete_nolock (poc->oc_name);
  1793. }
  1794. else {
  1795. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
  1796. delete_oc->oc_name, "Cannot delete a standard object class" );
  1797. rc = LDAP_UNWILLING_TO_PERFORM;
  1798. goto unlock_and_return;
  1799. }
  1800. }
  1801. else {
  1802. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
  1803. delete_oc->oc_name, "Is unknown. Cannot delete." );
  1804. rc = schema_ds4x_compat ? LDAP_NO_SUCH_OBJECT : LDAP_NO_SUCH_ATTRIBUTE;
  1805. goto unlock_and_return;
  1806. }
  1807. oc_free( &delete_oc );
  1808. oc_unlock();
  1809. }
  1810. return rc;
  1811. unlock_and_return:
  1812. oc_free( &delete_oc );
  1813. oc_unlock();
  1814. return rc;
  1815. }
  1816. static int
  1817. schema_return(int rc,struct sizedbuffer * psb1,struct sizedbuffer *psb2,struct sizedbuffer *psb3,struct sizedbuffer *psb4)
  1818. {
  1819. sizedbuffer_destroy(psb1);
  1820. sizedbuffer_destroy(psb2);
  1821. sizedbuffer_destroy(psb3);
  1822. sizedbuffer_destroy(psb4);
  1823. return rc;
  1824. }
  1825. /*
  1826. * Delete one or more attributeTypes from our internal data structure.
  1827. *
  1828. * Return an LDAP error code (LDAP_SUCCESS if all goes well).
  1829. * If an error occurs, explanatory text is copied into 'errorbuf'.
  1830. *
  1831. * This function should not send an LDAP result; that is the caller's
  1832. * responsibility.
  1833. */
  1834. static int
  1835. schema_delete_attributes ( Slapi_Entry *entryBefore, LDAPMod *mod,
  1836. char *errorbuf, size_t errorbufsize)
  1837. {
  1838. char *attr_ldif, *oc_list_type = "";
  1839. asyntaxinfo *a;
  1840. struct objclass *oc = NULL;
  1841. int i, k, attr_in_use_by_an_oc = 0;
  1842. struct sizedbuffer *psbAttrName= sizedbuffer_construct(BUFSIZ);
  1843. struct sizedbuffer *psbAttrOid= sizedbuffer_construct(BUFSIZ);
  1844. struct sizedbuffer *psbAttrSyntax= sizedbuffer_construct(BUFSIZ);
  1845. if (NULL == mod->mod_bvalues) {
  1846. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
  1847. NULL, "Cannot remove all schema attribute types" );
  1848. return schema_return(LDAP_UNWILLING_TO_PERFORM,psbAttrOid,psbAttrName,
  1849. psbAttrSyntax,NULL);
  1850. }
  1851. for (i = 0; mod->mod_bvalues[i]; i++) {
  1852. attr_ldif =(char *) mod->mod_bvalues[i]->bv_val;
  1853. /* normalize the attr ldif */
  1854. for ( k = 0; attr_ldif[k]; k++) {
  1855. if (attr_ldif[k] == '\'' ||
  1856. attr_ldif[k] == '(' ||
  1857. attr_ldif[k] == ')' ) {
  1858. attr_ldif[k] = ' ';
  1859. }
  1860. attr_ldif[k] = tolower (attr_ldif[k]);
  1861. }
  1862. sizedbuffer_allocate(psbAttrName,strlen(attr_ldif));
  1863. sizedbuffer_allocate(psbAttrOid,strlen(attr_ldif));
  1864. sizedbuffer_allocate(psbAttrSyntax,strlen(attr_ldif));
  1865. sscanf (attr_ldif, "%s name %s syntax %s",
  1866. psbAttrOid->buffer, psbAttrName->buffer, psbAttrSyntax->buffer);
  1867. if ((a = attr_syntax_get_by_name ( psbAttrName->buffer)) != NULL ) {
  1868. /* only modify attrs which were user defined */
  1869. if (a->asi_flags & SLAPI_ATTR_FLAG_STD_ATTR) {
  1870. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
  1871. psbAttrName->buffer,
  1872. "Cannot delete a standard attribute type" );
  1873. attr_syntax_return( a );
  1874. return schema_return(LDAP_UNWILLING_TO_PERFORM,psbAttrOid,psbAttrName,
  1875. psbAttrSyntax,NULL);
  1876. }
  1877. /* Do not allow deletion if referenced by an object class. */
  1878. oc_lock_read();
  1879. attr_in_use_by_an_oc = 0;
  1880. for ( oc = g_get_global_oc_nolock(); oc != NULL; oc = oc->oc_next ) {
  1881. if (NULL != oc->oc_required) {
  1882. for ( k = 0; oc->oc_required[k] != NULL; k++ ) {
  1883. if ( 0 == slapi_attr_type_cmp( oc->oc_required[k], a->asi_name,
  1884. SLAPI_TYPE_CMP_EXACT )) {
  1885. oc_list_type = "MUST";
  1886. attr_in_use_by_an_oc = 1;
  1887. break;
  1888. }
  1889. }
  1890. }
  1891. if (!attr_in_use_by_an_oc && NULL != oc->oc_allowed) {
  1892. for ( k = 0; oc->oc_allowed[k] != NULL; k++ ) {
  1893. if ( 0 == slapi_attr_type_cmp( oc->oc_allowed[k], a->asi_name,
  1894. SLAPI_TYPE_CMP_EXACT )) {
  1895. oc_list_type = "MAY";
  1896. attr_in_use_by_an_oc = 1;
  1897. break;
  1898. }
  1899. }
  1900. }
  1901. if (attr_in_use_by_an_oc) {
  1902. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
  1903. psbAttrName->buffer, "Is included in the %s list for object class %s. Cannot delete.",
  1904. oc_list_type, oc->oc_name );
  1905. break;
  1906. }
  1907. }
  1908. oc_unlock();
  1909. if (attr_in_use_by_an_oc) {
  1910. attr_syntax_return( a );
  1911. return schema_return(LDAP_UNWILLING_TO_PERFORM,psbAttrOid,psbAttrName,
  1912. psbAttrSyntax,NULL);
  1913. }
  1914. /* Delete it. */
  1915. attr_syntax_delete( a );
  1916. attr_syntax_return( a );
  1917. }
  1918. else {
  1919. /* unknown attribute */
  1920. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
  1921. psbAttrName->buffer, "Is unknown. Cannot delete." );
  1922. return schema_return(LDAP_NO_SUCH_ATTRIBUTE,psbAttrOid,psbAttrName,
  1923. psbAttrSyntax,NULL);
  1924. }
  1925. }
  1926. return schema_return(LDAP_SUCCESS,psbAttrOid,psbAttrName,psbAttrSyntax,
  1927. NULL);
  1928. }
  1929. static int
  1930. schema_add_attribute ( Slapi_PBlock *pb, LDAPMod *mod, char *errorbuf,
  1931. size_t errorbufsize, int schema_ds4x_compat )
  1932. {
  1933. int i;
  1934. char *attr_ldif;
  1935. /* LPXXX: Eventually, we should not allocate the buffers in read_at_ldif
  1936. * for each attribute, but use the same buffer for all.
  1937. * This is not done yet, so it's useless to allocate buffers for nothing.
  1938. */
  1939. /* struct sizedbuffer *psbAttrName= sizedbuffer_construct(BUFSIZ); */
  1940. /* struct sizedbuffer *psbAttrOid= sizedbuffer_construct(BUFSIZ); */
  1941. /* struct sizedbuffer *psbAttrDesc= sizedbuffer_construct(BUFSIZ); */
  1942. /* struct sizedbuffer *psbAttrSyntax= sizedbuffer_construct(BUFSIZ); */
  1943. int status = 0;
  1944. for (i = 0; LDAP_SUCCESS == status && mod->mod_bvalues[i]; i++) {
  1945. PRUint32 nolock = 0; /* lock global resources during normal operation */
  1946. attr_ldif = (char *) mod->mod_bvalues[i]->bv_val;
  1947. status = read_at_ldif(attr_ldif, NULL, errorbuf, errorbufsize,
  1948. nolock, 1 /* user defined */, schema_ds4x_compat, 1);
  1949. if ( LDAP_SUCCESS != status ) {
  1950. break; /* stop on first error */
  1951. }
  1952. }
  1953. /* free everything */
  1954. /* sizedbuffer_destroy(psbAttrOid); */
  1955. /* sizedbuffer_destroy(psbAttrName); */
  1956. /* sizedbuffer_destroy(psbAttrDesc); */
  1957. /* sizedbuffer_destroy(psbAttrSyntax); */
  1958. return status;
  1959. }
  1960. /*
  1961. * Returns an LDAP error code (LDAP_SUCCESS if all goes well)
  1962. */
  1963. static int
  1964. add_oc_internal(struct objclass *pnew_oc, char *errorbuf, size_t errorbufsize,
  1965. int schema_ds4x_compat, PRUint32 flags )
  1966. {
  1967. struct objclass *oldoc_by_name, *oldoc_by_oid, *psup_oc = NULL;
  1968. int redefined_oc = 0, rc=0;
  1969. asyntaxinfo *pasyntaxinfo = 0;
  1970. if (!(flags & DSE_SCHEMA_LOCKED))
  1971. oc_lock_write();
  1972. oldoc_by_name = oc_find_nolock (pnew_oc->oc_name);
  1973. oldoc_by_oid = oc_find_nolock (pnew_oc->oc_oid);
  1974. /* Check to see if the objectclass name and the objectclass oid are already
  1975. * in use by an existing objectclass. If an existing objectclass is already
  1976. * using the name or oid, the name and the oid should map to the same objectclass.
  1977. * Otherwise, return an error.
  1978. */
  1979. if ( oldoc_by_name != oldoc_by_oid ) {
  1980. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
  1981. pnew_oc->oc_name, "The name does not match the OID \"%s\". "
  1982. "Another object class is already using the name or OID.",
  1983. pnew_oc->oc_oid);
  1984. rc = LDAP_TYPE_OR_VALUE_EXISTS;
  1985. }
  1986. /*
  1987. * Set a flag so we know if we are updating an existing OC definition.
  1988. */
  1989. if ( !rc ) {
  1990. if ( NULL != oldoc_by_name ) {
  1991. redefined_oc = 1;
  1992. } else {
  1993. /*
  1994. * If we are not updating an existing OC, check that the new
  1995. * oid is not already in use.
  1996. */
  1997. if ( NULL != oldoc_by_oid ) {
  1998. schema_create_errormsg( errorbuf, errorbufsize,
  1999. schema_errprefix_oc, pnew_oc->oc_name,
  2000. "The OID \"%s\" is already used by the object class \"%s\"",
  2001. pnew_oc->oc_oid, oldoc_by_oid->oc_name);
  2002. rc = LDAP_TYPE_OR_VALUE_EXISTS;
  2003. }
  2004. }
  2005. }
  2006. /* check to see if the superior oc exists */
  2007. if (!rc && pnew_oc->oc_superior &&
  2008. ((psup_oc = oc_find_nolock (pnew_oc->oc_superior)) == NULL)) {
  2009. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
  2010. pnew_oc->oc_name, "Superior object class \"%s\" does not exist",
  2011. pnew_oc->oc_superior);
  2012. rc = LDAP_TYPE_OR_VALUE_EXISTS;
  2013. }
  2014. /* inherit the attributes from the superior oc */
  2015. if (!rc && psup_oc ) {
  2016. if ( psup_oc->oc_required ) {
  2017. charray_merge( &pnew_oc->oc_required, psup_oc->oc_required, 1 );
  2018. }
  2019. if ( psup_oc->oc_allowed ) {
  2020. charray_merge ( &pnew_oc->oc_allowed, psup_oc->oc_allowed, 1 );
  2021. }
  2022. }
  2023. /* check to see if the oid is already in use by an attribute */
  2024. if (!rc && (pasyntaxinfo = attr_syntax_get_by_oid(pnew_oc->oc_oid))) {
  2025. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
  2026. pnew_oc->oc_name,
  2027. "The OID \"%s\" is also used by the attribute type \"%s\"",
  2028. pnew_oc->oc_oid, pasyntaxinfo->asi_name);
  2029. rc = LDAP_TYPE_OR_VALUE_EXISTS;
  2030. attr_syntax_return( pasyntaxinfo );
  2031. }
  2032. /* check to see if the objectclass name is valid */
  2033. if (!rc && !(flags & DSE_SCHEMA_NO_CHECK) &&
  2034. schema_check_name ( pnew_oc->oc_name, PR_FALSE, errorbuf, errorbufsize )
  2035. == 0 ) {
  2036. rc = schema_ds4x_compat ? LDAP_OPERATIONS_ERROR : LDAP_INVALID_SYNTAX;
  2037. }
  2038. /* check to see if the oid is valid */
  2039. if (!rc && !(flags & DSE_SCHEMA_NO_CHECK))
  2040. {
  2041. struct sizedbuffer *psbOcOid, *psbOcName;
  2042. psbOcName = sizedbuffer_construct(strlen(pnew_oc->oc_name) + 1);
  2043. psbOcOid = sizedbuffer_construct(strlen(pnew_oc->oc_oid) + 1);
  2044. strcpy(psbOcName->buffer, pnew_oc->oc_name);
  2045. strcpy(psbOcOid->buffer, pnew_oc->oc_oid);
  2046. if (!schema_check_oid ( psbOcName->buffer, psbOcOid->buffer, PR_FALSE,
  2047. errorbuf, errorbufsize))
  2048. rc = schema_ds4x_compat ? LDAP_OPERATIONS_ERROR : LDAP_INVALID_SYNTAX;
  2049. sizedbuffer_destroy(psbOcName);
  2050. sizedbuffer_destroy(psbOcOid);
  2051. }
  2052. /* check to see if the oc's attributes are valid */
  2053. if (!rc && !(flags & DSE_SCHEMA_NO_CHECK) &&
  2054. schema_check_oc_attrs ( pnew_oc, errorbuf, errorbufsize,
  2055. 0 /* don't strip options */ ) == 0 ) {
  2056. rc = schema_ds4x_compat ? LDAP_OPERATIONS_ERROR : LDAP_INVALID_SYNTAX;
  2057. }
  2058. /* insert new objectclass exactly where the old one one in the linked list*/
  2059. if ( !rc && redefined_oc ) {
  2060. pnew_oc->oc_flags |= OC_FLAG_REDEFINED_OC;
  2061. rc=oc_replace_nolock( pnew_oc->oc_name, pnew_oc);
  2062. }
  2063. if (!rc && !redefined_oc ) {
  2064. oc_add_nolock(pnew_oc);
  2065. }
  2066. if (!rc && redefined_oc ) {
  2067. oc_update_inheritance_nolock( pnew_oc );
  2068. }
  2069. if (!(flags & DSE_SCHEMA_LOCKED))
  2070. oc_unlock();
  2071. return rc;
  2072. }
  2073. /*
  2074. * Process a replace modify suboperation for attributetypes.
  2075. *
  2076. * XXXmcs: At present, readonly (bundled) schema definitions can't be
  2077. * removed. If that is attempted, we just keep them without generating
  2078. * an error.
  2079. *
  2080. * Our algorithm is:
  2081. *
  2082. * Clear the "keep" flags on the all existing attr. definitions.
  2083. *
  2084. * For each replacement value:
  2085. * If the value exactly matches an existing schema definition,
  2086. * set that definition's keep flag.
  2087. *
  2088. * Else if the OID in the replacement value matches an existing
  2089. * definition, delete the old definition and add the new one. Set
  2090. * the keep flag on the newly added definition.
  2091. *
  2092. * Else add the new definition. Set the keep flag on the newly
  2093. * added definition.
  2094. *
  2095. * For each definition that is not flagged keep, delete.
  2096. *
  2097. * Clear all remaining "keep" flags.
  2098. *
  2099. * Note that replace was not supported at all before iDS 5.0.
  2100. */
  2101. static int
  2102. schema_replace_attributes ( Slapi_PBlock *pb, LDAPMod *mod, char *errorbuf,
  2103. size_t errorbufsize )
  2104. {
  2105. int i, rc = LDAP_SUCCESS;
  2106. struct asyntaxinfo *newasip, *oldasip;
  2107. if ( NULL == mod->mod_bvalues ) {
  2108. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
  2109. NULL, "Cannot remove all schema attribute types" );
  2110. return LDAP_UNWILLING_TO_PERFORM;
  2111. }
  2112. /* clear all of the "keep" flags */
  2113. attr_syntax_all_clear_flag( SLAPI_ATTR_FLAG_KEEP );
  2114. for ( i = 0; mod->mod_bvalues[i] != NULL; ++i ) {
  2115. if ( LDAP_SUCCESS != ( rc = read_at_ldif( mod->mod_bvalues[i]->bv_val,
  2116. &newasip, errorbuf, errorbufsize, 0, 1, 0, 0 ))) {
  2117. goto clean_up_and_return;
  2118. }
  2119. /*
  2120. * Check for a match with an existing type and
  2121. * handle the various cases.
  2122. */
  2123. if ( NULL == ( oldasip =
  2124. attr_syntax_get_by_oid( newasip->asi_oid ))) {
  2125. /* new attribute type */
  2126. LDAPDebug( LDAP_DEBUG_TRACE, "schema_replace_attributes:"
  2127. " new type %s (OID %s)\n",
  2128. newasip->asi_name, newasip->asi_oid, 0 );
  2129. } else {
  2130. /* the name matches -- check the rest */
  2131. if ( attr_syntax_equal( newasip, oldasip )) {
  2132. /* unchanged attribute type -- just mark it as one to keep */
  2133. oldasip->asi_flags |= SLAPI_ATTR_FLAG_KEEP;
  2134. attr_syntax_free( newasip );
  2135. newasip = NULL;
  2136. } else {
  2137. /* modified attribute type */
  2138. LDAPDebug( LDAP_DEBUG_TRACE, "schema_replace_attributes:"
  2139. " replacing type %s (OID %s)\n",
  2140. newasip->asi_name, newasip->asi_oid, 0 );
  2141. /* flag for deletion */
  2142. attr_syntax_delete( oldasip );
  2143. }
  2144. attr_syntax_return( oldasip );
  2145. }
  2146. if ( NULL != newasip ) { /* add new or replacement definition */
  2147. rc = attr_syntax_add( newasip );
  2148. if ( LDAP_SUCCESS != rc ) {
  2149. schema_create_errormsg( errorbuf, errorbufsize,
  2150. schema_errprefix_at, newasip->asi_name,
  2151. "Could not be added (OID is \"%s\")",
  2152. newasip->asi_oid );
  2153. attr_syntax_free( newasip );
  2154. goto clean_up_and_return;
  2155. }
  2156. newasip->asi_flags |= SLAPI_ATTR_FLAG_KEEP;
  2157. }
  2158. }
  2159. /*
  2160. * Delete all of the definitions that are not marked "keep" or "standard".
  2161. *
  2162. * XXXmcs: we should consider reporting an error if any read only types
  2163. * remain....
  2164. */
  2165. attr_syntax_delete_all_not_flagged( SLAPI_ATTR_FLAG_KEEP
  2166. | SLAPI_ATTR_FLAG_STD_ATTR );
  2167. clean_up_and_return:
  2168. /* clear all of the "keep" flags */
  2169. attr_syntax_all_clear_flag( SLAPI_ATTR_FLAG_KEEP );
  2170. return rc;
  2171. }
  2172. static int
  2173. schema_add_objectclass ( Slapi_PBlock *pb, LDAPMod *mod, char *errorbuf,
  2174. size_t errorbufsize, int schema_ds4x_compat )
  2175. {
  2176. struct objclass *pnew_oc;
  2177. char *newoc_ldif;
  2178. int j, rc=0;
  2179. for (j = 0; mod->mod_bvalues[j]; j++) {
  2180. newoc_ldif = (char *) mod->mod_bvalues[j]->bv_val;
  2181. if ( LDAP_SUCCESS != (rc = read_oc_ldif ( newoc_ldif, &pnew_oc,
  2182. errorbuf, errorbufsize, 0, 1 /* user defined */,
  2183. schema_ds4x_compat))) {
  2184. return rc;
  2185. }
  2186. if ( LDAP_SUCCESS != (rc = add_oc_internal(pnew_oc, errorbuf,
  2187. errorbufsize, schema_ds4x_compat, 0/* no restriction */))) {
  2188. oc_free( &pnew_oc );
  2189. return rc;
  2190. }
  2191. normalize_oc();
  2192. }
  2193. return LDAP_SUCCESS;
  2194. }
  2195. /*
  2196. * Process a replace modify suboperation for objectclasses.
  2197. *
  2198. * XXXmcs: At present, readonly (bundled) schema definitions can't be
  2199. * removed. If that is attempted, we just keep them without generating
  2200. * an error.
  2201. *
  2202. * Our algorithm is:
  2203. *
  2204. * Lock the global objectclass linked list.
  2205. *
  2206. * Create a new empty (temporary) linked list, initially empty.
  2207. *
  2208. * For each replacement value:
  2209. * If the value exactly matches an existing schema definition,
  2210. * move the existing definition from the current global list to the
  2211. * temporary list
  2212. *
  2213. * Else if the OID in the replacement value matches an existing
  2214. * definition, delete the old definition from the current global
  2215. * list and add the new one to the temporary list.
  2216. *
  2217. * Else add the new definition to the temporary list.
  2218. *
  2219. * Delete all definitions that remain on the current global list.
  2220. *
  2221. * Make the temporary list the current global list.
  2222. *
  2223. * Note that since the objectclass definitions are stored in a linked list,
  2224. * this algorithm is O(N * M) where N is the number of existing objectclass
  2225. * definitions and M is the number of replacement definitions.
  2226. * XXXmcs: Yuck. We should use a hash table for the OC definitions.
  2227. *
  2228. * Note that replace was not supported at all by DS versions prior to 5.0
  2229. */
  2230. static int
  2231. schema_replace_objectclasses ( Slapi_PBlock *pb, LDAPMod *mod, char *errorbuf,
  2232. size_t errorbufsize )
  2233. {
  2234. struct objclass *newocp, *curlisthead, *prevocp, *tmpocp;
  2235. struct objclass *newlisthead = NULL, *newlistend = NULL;
  2236. int i, rc = LDAP_SUCCESS;
  2237. if ( NULL == mod->mod_bvalues ) {
  2238. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
  2239. NULL, "Cannot remove all schema object classes" );
  2240. return LDAP_UNWILLING_TO_PERFORM;
  2241. }
  2242. oc_lock_write();
  2243. curlisthead = g_get_global_oc_nolock();
  2244. for ( i = 0; mod->mod_bvalues[i] != NULL; ++i ) {
  2245. struct objclass *addocp = NULL;
  2246. if ( LDAP_SUCCESS != ( rc = read_oc_ldif( mod->mod_bvalues[i]->bv_val,
  2247. &newocp, errorbuf, errorbufsize, DSE_SCHEMA_NO_GLOCK,
  2248. 1 /* user defined */, 0 /* no DS 4.x compat issues */ ))) {
  2249. rc = LDAP_INVALID_SYNTAX;
  2250. goto clean_up_and_return;
  2251. }
  2252. prevocp = NULL;
  2253. for ( tmpocp = curlisthead; tmpocp != NULL; tmpocp = tmpocp->oc_next ) {
  2254. if ( 0 == strcasecmp( tmpocp->oc_oid, newocp->oc_oid ) ) {
  2255. /* the names match -- remove from the current list */
  2256. if ( tmpocp == curlisthead ) {
  2257. curlisthead = tmpocp->oc_next;
  2258. /* The global oc list is scanned in read_oc_ldif above,
  2259. if there are multiple objectclasses to be updated.
  2260. Needs to maintain the list dynamically. */
  2261. g_set_global_oc_nolock( curlisthead );
  2262. } else {
  2263. prevocp->oc_next = tmpocp->oc_next;
  2264. }
  2265. tmpocp->oc_next = NULL;
  2266. /* check for a full match */
  2267. if ( oc_equal( tmpocp, newocp )) {
  2268. /* no changes: keep existing definition and discard new */
  2269. oc_free( &newocp );
  2270. addocp = tmpocp;
  2271. } else {
  2272. /* some differences: discard old and keep the new one */
  2273. oc_free( &tmpocp );
  2274. LDAPDebug( LDAP_DEBUG_TRACE, "schema_replace_objectclasses:"
  2275. " replacing object class %s (OID %s)\n",
  2276. newocp->oc_name, newocp->oc_oid, 0 );
  2277. addocp = newocp;
  2278. }
  2279. break; /* we found it -- exit the loop */
  2280. }
  2281. prevocp = tmpocp;
  2282. }
  2283. if ( NULL == addocp ) {
  2284. LDAPDebug( LDAP_DEBUG_TRACE, "schema_replace_objectclasses:"
  2285. " new object class %s (OID %s)\n",
  2286. newocp->oc_name, newocp->oc_oid, 0 );
  2287. addocp = newocp;
  2288. }
  2289. /* add the objectclass to the end of the new list */
  2290. if ( NULL != addocp ) {
  2291. if ( NULL == newlisthead ) {
  2292. newlisthead = addocp;
  2293. } else {
  2294. newlistend->oc_next = addocp;
  2295. }
  2296. newlistend = addocp;
  2297. }
  2298. }
  2299. clean_up_and_return:
  2300. if ( LDAP_SUCCESS == rc ) {
  2301. /*
  2302. * Delete all remaining OCs that are on the old list AND are not
  2303. * "standard" classes.
  2304. */
  2305. struct objclass *nextocp;
  2306. prevocp = NULL;
  2307. for ( tmpocp = curlisthead; tmpocp != NULL; tmpocp = nextocp ) {
  2308. if ( 0 == ( tmpocp->oc_flags & OC_FLAG_STANDARD_OC )) {
  2309. /* not a standard definition -- remove it */
  2310. if ( tmpocp == curlisthead ) {
  2311. curlisthead = tmpocp->oc_next;
  2312. } else {
  2313. prevocp->oc_next = tmpocp->oc_next;
  2314. }
  2315. nextocp = tmpocp->oc_next;
  2316. oc_free( &tmpocp );
  2317. } else {
  2318. /*
  2319. * XXXmcs: we could generate an error, but for now we do not.
  2320. */
  2321. nextocp = tmpocp->oc_next;
  2322. prevocp = tmpocp;
  2323. #if 0
  2324. schema_create_errormsg( errorbuf, errorbufsize,
  2325. schema_errprefix_oc, tmpocp->oc_name,
  2326. "Cannot delete a standard object class" );
  2327. rc = LDAP_UNWILLING_TO_PERFORM;
  2328. break;
  2329. #endif
  2330. }
  2331. }
  2332. }
  2333. /*
  2334. * Combine the two lists by adding the new list to the end of the old
  2335. * one.
  2336. */
  2337. if ( NULL != curlisthead ) {
  2338. for ( tmpocp = curlisthead; tmpocp->oc_next != NULL;
  2339. tmpocp = tmpocp->oc_next ) {
  2340. ;/*NULL*/
  2341. }
  2342. tmpocp->oc_next = newlisthead;
  2343. newlisthead = curlisthead;
  2344. }
  2345. /*
  2346. * Install the new list as the global one, replacing the old one.
  2347. */
  2348. g_set_global_oc_nolock( newlisthead );
  2349. oc_unlock();
  2350. return rc;
  2351. }
  2352. /*
  2353. * read_oc_ldif_return
  2354. * Free all the memory that read_oc_ldif() allocated, and return the retVal
  2355. *
  2356. * It's nice to do all the freeing in one spot, as read_oc_ldif() returns sideways
  2357. */
  2358. static int
  2359. read_oc_ldif_return( int retVal,
  2360. char *oid,
  2361. struct sizedbuffer *name,
  2362. char *sup,
  2363. char **origins,
  2364. int num_origins,
  2365. char *desc )
  2366. {
  2367. slapi_ch_free((void **)&oid);
  2368. sizedbuffer_destroy( name );
  2369. slapi_ch_free((void **)&sup);
  2370. free_qdlist( origins, num_origins );
  2371. slapi_ch_free((void **)&desc);
  2372. return retVal;
  2373. }
  2374. /*
  2375. * read_oc_ldif
  2376. * Read the value of the objectclasses attribute in cn=schema, convert it
  2377. * into an objectclass struct.
  2378. *
  2379. * Arguments:
  2380. *
  2381. * input : value of objectclasses attribute to read
  2382. * oc : pointer write the objectclass to
  2383. * errorbuf : buffer to write any errors to
  2384. * is_user_defined : if non-zero, force objectclass to be user defined
  2385. * schema_flags : Any or none of the following bits could be set
  2386. * DSE_SCHEMA_NO_CHECK -- schema won't be checked
  2387. * DSE_SCHEMA_NO_GLOCK -- don't lock global resources
  2388. * DSE_SCHEMA_LOCKED -- already locked with
  2389. * reload_schemafile_lock;
  2390. * no further lock needed
  2391. * schema_ds4x_compat: if non-zero, act like Netscape DS 4.x
  2392. *
  2393. * Returns: an LDAP error code
  2394. *
  2395. * LDAP_SUCCESS if the objectclass was sucessfully read, the new
  2396. * objectclass will be written to oc
  2397. *
  2398. * All others: there was an error, an error message will
  2399. * be written to errorbuf
  2400. */
  2401. static int
  2402. read_oc_ldif ( const char *input, struct objclass **oc, char *errorbuf,
  2403. size_t errorbufsize, PRUint32 schema_flags, int is_user_defined,
  2404. int schema_ds4x_compat )
  2405. {
  2406. int i, j, num_origins;
  2407. const char *pstart, *nextinput;
  2408. struct objclass *pnew_oc, *psup_oc;
  2409. char **RequiredAttrsArray, **AllowedAttrsArray;
  2410. char **OrigRequiredAttrsArray, **OrigAllowedAttrsArray;
  2411. char **oc_origins;
  2412. char *pend, *pOcOid, *pOcSup, *pOcDesc;
  2413. struct sizedbuffer *psbOcName= sizedbuffer_construct(BUFSIZ);
  2414. PRUint8 kind, flags;
  2415. int invalid_syntax_error;
  2416. schema_strstr_fn_t keyword_strstr_fn;
  2417. /*
  2418. * From RFC 2252 section 4.4:
  2419. *
  2420. * ObjectClassDescription = "(" whsp
  2421. * numericoid whsp ; ObjectClass identifier
  2422. * [ "NAME" qdescrs ]
  2423. * [ "DESC" qdstring ]
  2424. * [ "OBSOLETE" whsp ]
  2425. * [ "SUP" oids ] ; Superior ObjectClasses
  2426. * [ ( "ABSTRACT" / "STRUCTURAL" / "AUXILIARY" ) whsp ]
  2427. * ; default structural
  2428. * [ "MUST" oids ] ; AttributeTypes
  2429. * [ "MAY" oids ] ; AttributeTypes
  2430. * whsp ")"
  2431. *
  2432. * XXXmcs: Our parsing technique is poor. In (Netscape) DS 4.12 and earlier
  2433. * releases, parsing was mostly done by looking anywhere within the input
  2434. * string for various keywords such as "MUST". But if, for example, a
  2435. * description contains the word "must", the parser would take assume that
  2436. * the tokens following the word were attribute types or OIDs. Bad news.
  2437. *
  2438. * In iDS 5.0 and later, we parse in order left to right and advance a
  2439. * pointer as we consume the input string (the nextinput variable). We
  2440. * also use a case-insensitive search when looking for keywords such as
  2441. * DESC. But the parser will still be fooled by sequences like:
  2442. *
  2443. * ( 1.2.3.4 NAME 'testOC' MUST ( DESC cn ) )
  2444. *
  2445. * Someday soon we will need to write a real parser.
  2446. *
  2447. * Compatibility notes: if schema_ds4x_compat is set, we:
  2448. * 1. always parse from the beginning of the string
  2449. * 2. use a case-insensitive compare when looking for keywords, e.g., MUST
  2450. */
  2451. if ( schema_ds4x_compat ) {
  2452. keyword_strstr_fn = PL_strcasestr;
  2453. invalid_syntax_error = LDAP_OPERATIONS_ERROR;
  2454. } else {
  2455. keyword_strstr_fn = PL_strstr;
  2456. invalid_syntax_error = LDAP_INVALID_SYNTAX;
  2457. }
  2458. flags = 0;
  2459. num_origins = 0;
  2460. oc_origins = NULL;
  2461. pOcOid = pOcSup = pOcDesc = NULL;
  2462. if ( NULL == input || '\0' == input[0] ) {
  2463. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc, NULL,
  2464. "One or more values are required for the objectClasses attribute" );
  2465. LDAPDebug ( LDAP_DEBUG_ANY, "NULL args passed to read_oc_ldif\n",0,0,0);
  2466. return read_oc_ldif_return( LDAP_OPERATIONS_ERROR, pOcOid, psbOcName,
  2467. pOcSup, oc_origins, num_origins, pOcDesc );
  2468. }
  2469. nextinput = input;
  2470. /* look for the OID */
  2471. if ( NULL == ( pOcOid = get_tagged_oid( "(", &nextinput,
  2472. keyword_strstr_fn ))) {
  2473. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
  2474. input, "Value is malformed. It must include a \"(\"");
  2475. return read_oc_ldif_return( invalid_syntax_error, pOcOid, psbOcName,
  2476. pOcSup, oc_origins, num_origins, pOcDesc );
  2477. }
  2478. if ( schema_ds4x_compat || ( strcasecmp(pOcOid, "NAME") == 0))
  2479. nextinput = input;
  2480. /* look for the NAME */
  2481. if ( (pstart = (*keyword_strstr_fn)(nextinput, "NAME '")) != NULL ) {
  2482. pstart += 6;
  2483. sizedbuffer_allocate(psbOcName,strlen(pstart));
  2484. if ( sscanf ( pstart, "%s", psbOcName->buffer ) > 0 ) {
  2485. /* strip the trailing single quote */
  2486. if ( psbOcName->buffer[strlen(psbOcName->buffer)-1] == '\'' ) {
  2487. psbOcName->buffer[strlen(psbOcName->buffer)-1] = '\0';
  2488. nextinput = pstart + strlen(psbOcName->buffer) + 1;
  2489. } else {
  2490. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
  2491. input, "Value is malformed. It must include a single quote around"
  2492. " the name" );
  2493. return read_oc_ldif_return( invalid_syntax_error, pOcOid, psbOcName,
  2494. pOcSup, oc_origins, num_origins, pOcDesc );
  2495. }
  2496. }
  2497. }
  2498. else {
  2499. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
  2500. input, "Value is malformed. It must include a \"NAME '\"");
  2501. return read_oc_ldif_return( invalid_syntax_error, pOcOid, psbOcName,
  2502. pOcSup, oc_origins, num_origins, pOcDesc );
  2503. }
  2504. /*
  2505. ** if the objectclass ldif doesn't have an OID, we'll make the oid
  2506. ** ocname-oid
  2507. */
  2508. if ( strcasecmp ( pOcOid, "NAME" ) == 0 ) {
  2509. slapi_ch_free_string( &pOcOid );
  2510. pOcOid = slapi_ch_smprintf("%s-oid", psbOcName->buffer );
  2511. }
  2512. if ( schema_ds4x_compat ) nextinput = input;
  2513. /* look for an optional DESCription */
  2514. if ( (pstart = (*keyword_strstr_fn) ( nextinput, " DESC '")) != NULL ) {
  2515. pstart += 7;
  2516. if (( pend = strchr( pstart, '\'' )) == NULL ) {
  2517. pend = (char *)(pstart + strlen(pstart));
  2518. }
  2519. pOcDesc = slapi_ch_malloc( pend - pstart + 1 );
  2520. memcpy( pOcDesc, pstart, pend - pstart );
  2521. pOcDesc[ pend - pstart ] = '\0';
  2522. nextinput = pend + 1;
  2523. }
  2524. if ( schema_ds4x_compat ) nextinput = input;
  2525. /* look for the optional OBSOLETE marker */
  2526. flags |= get_flag_keyword( schema_obsolete_with_spaces,
  2527. OC_FLAG_OBSOLETE, &nextinput, keyword_strstr_fn );
  2528. if (!(schema_flags & DSE_SCHEMA_NO_GLOCK)) {
  2529. oc_lock_read(); /* needed because we access the superior oc */
  2530. }
  2531. if ( schema_ds4x_compat ) nextinput = input;
  2532. /*
  2533. * Look for the superior objectclass. We first look for a parenthesized
  2534. * list and if not found we look for a simple OID.
  2535. *
  2536. * XXXmcs: Since we do not yet support multiple superior objectclasses, we
  2537. * just grab the first OID in a parenthesized list.
  2538. */
  2539. if ( NULL == ( pOcSup = get_tagged_oid( " SUP (", &nextinput,
  2540. keyword_strstr_fn ))) {
  2541. pOcSup = get_tagged_oid( " SUP ", &nextinput, keyword_strstr_fn );
  2542. }
  2543. psup_oc = oc_find_nolock ( pOcSup );
  2544. if ( schema_ds4x_compat ) nextinput = input;
  2545. /* look for the optional kind (ABSTRACT, STRUCTURAL, AUXILIARY) */
  2546. for ( i = 0; i < SCHEMA_OC_KIND_COUNT; ++i ) {
  2547. if ( NULL != ( pstart = (*keyword_strstr_fn)( nextinput,
  2548. schema_oc_kind_strings_with_spaces[i] ))) {
  2549. kind = i;
  2550. nextinput = pstart + strlen( schema_oc_kind_strings_with_spaces[i] ) - 1;
  2551. break;
  2552. }
  2553. }
  2554. if ( i >= SCHEMA_OC_KIND_COUNT ) { /* not found */
  2555. if ( NULL != psup_oc && OC_KIND_ABSTRACT != psup_oc->oc_kind ) {
  2556. /* inherit kind from superior class if not ABSTRACT */
  2557. kind = psup_oc->oc_kind;
  2558. } else {
  2559. /* according to RFC 2252, the default is structural */
  2560. kind = OC_KIND_STRUCTURAL;
  2561. }
  2562. }
  2563. if ( schema_ds4x_compat ) nextinput = input;
  2564. /* look for required attributes (MUST) */
  2565. if ( (pstart = (*keyword_strstr_fn) (nextinput, " MUST ")) != NULL ) {
  2566. char *pRequiredAttrs;
  2567. int saw_open_paren = 0;
  2568. pstart += 6;
  2569. pstart = skipWS( pstart ); /* skip past any extra white space */
  2570. if ( *pstart == '(' ) {
  2571. saw_open_paren = 1;
  2572. ++pstart;
  2573. }
  2574. pRequiredAttrs = slapi_ch_strdup ( pstart );
  2575. if ( saw_open_paren && (pend = strchr (pRequiredAttrs, ')')) != NULL ) {
  2576. *pend = '\0';
  2577. } else if ((pend = strchr (pRequiredAttrs, ' ' )) != NULL ) {
  2578. *pend = '\0';
  2579. } else {
  2580. pend = pRequiredAttrs + strlen(pRequiredAttrs); /* at end of string */
  2581. }
  2582. nextinput = pstart + ( pend - pRequiredAttrs );
  2583. RequiredAttrsArray = read_dollar_values (pRequiredAttrs);
  2584. slapi_ch_free((void**)&pRequiredAttrs);
  2585. } else {
  2586. RequiredAttrsArray = (char **) slapi_ch_malloc (1 * sizeof(char *)) ;
  2587. RequiredAttrsArray[0] = NULL;
  2588. }
  2589. if ( schema_ds4x_compat ) nextinput = input;
  2590. /* look for allowed attributes (MAY) */
  2591. if ( (pstart = (*keyword_strstr_fn) (nextinput, " MAY ")) != NULL ) {
  2592. char *pAllowedAttrs;
  2593. int saw_open_paren = 0;
  2594. pstart += 5;
  2595. pstart = skipWS( pstart ); /* skip past any extra white space */
  2596. if ( *pstart == '(' ) {
  2597. saw_open_paren = 1;
  2598. ++pstart;
  2599. }
  2600. pAllowedAttrs = slapi_ch_strdup ( pstart );
  2601. if ( saw_open_paren && (pend = strchr (pAllowedAttrs, ')')) != NULL ) {
  2602. *pend = '\0';
  2603. } else if ((pend = strchr (pAllowedAttrs, ' ' )) != NULL ) {
  2604. *pend = '\0';
  2605. } else {
  2606. pend = pAllowedAttrs + strlen(pAllowedAttrs); /* at end of string */
  2607. }
  2608. nextinput = pstart + ( pend - pAllowedAttrs );
  2609. AllowedAttrsArray = read_dollar_values (pAllowedAttrs);
  2610. slapi_ch_free((void**)&pAllowedAttrs);
  2611. } else {
  2612. AllowedAttrsArray = (char **) slapi_ch_malloc (1 * sizeof(char *)) ;
  2613. AllowedAttrsArray[0] = NULL;
  2614. }
  2615. if ( schema_ds4x_compat ) nextinput = input;
  2616. /* look for X-ORIGIN list */
  2617. oc_origins = parse_origin_list( nextinput, &num_origins,
  2618. schema_user_defined_origin );
  2619. /* set remaining flags */
  2620. if ( element_is_user_defined( oc_origins )) {
  2621. flags |= OC_FLAG_USER_OC;
  2622. } else if ( is_user_defined ) {
  2623. flags |= OC_FLAG_USER_OC;
  2624. /* add missing user defined origin string */
  2625. charray_add( &oc_origins, slapi_ch_strdup( schema_user_defined_origin[0] ));
  2626. ++num_origins;
  2627. } else {
  2628. flags |= OC_FLAG_STANDARD_OC;
  2629. }
  2630. /* generate OrigRequiredAttrsArray and OrigAllowedAttrsArray */
  2631. if (psup_oc) {
  2632. int found_it;
  2633. OrigRequiredAttrsArray = (char **) slapi_ch_malloc (1 * sizeof(char *)) ;
  2634. OrigRequiredAttrsArray[0] = NULL;
  2635. OrigAllowedAttrsArray = (char **) slapi_ch_malloc (1 * sizeof(char *)) ;
  2636. OrigAllowedAttrsArray[0] = NULL;
  2637. if (psup_oc->oc_required) {
  2638. for (i = 0; RequiredAttrsArray[i]; i++) {
  2639. for (j = 0, found_it = 0; psup_oc->oc_required[j]; j++) {
  2640. if (strcasecmp (psup_oc->oc_required[j], RequiredAttrsArray[i]) == 0) {
  2641. found_it = 1;
  2642. }
  2643. }
  2644. if (!found_it) {
  2645. charray_add (&OrigRequiredAttrsArray, slapi_ch_strdup ( RequiredAttrsArray[i] ) );
  2646. }
  2647. }
  2648. }
  2649. if (psup_oc->oc_allowed) {
  2650. for (i = 0; AllowedAttrsArray[i]; i++) {
  2651. for (j = 0, found_it=0; psup_oc->oc_allowed[j]; j++) {
  2652. if (strcasecmp (psup_oc->oc_allowed[j], AllowedAttrsArray[i]) == 0) {
  2653. found_it = 1;
  2654. }
  2655. }
  2656. if (!found_it) {
  2657. charray_add (&OrigAllowedAttrsArray, slapi_ch_strdup (AllowedAttrsArray[i]) );
  2658. }
  2659. }
  2660. }
  2661. }
  2662. else {
  2663. /* if no parent oc */
  2664. OrigRequiredAttrsArray = charray_dup ( RequiredAttrsArray );
  2665. OrigAllowedAttrsArray = charray_dup ( AllowedAttrsArray );
  2666. }
  2667. if (!(schema_flags & DSE_SCHEMA_NO_GLOCK)) {
  2668. oc_unlock(); /* we are done accessing superior oc (psup_oc) */
  2669. }
  2670. /* finally -- create new objclass structure */
  2671. pnew_oc = (struct objclass *) slapi_ch_malloc (1 * sizeof (struct objclass));
  2672. pnew_oc->oc_name = slapi_ch_strdup ( psbOcName->buffer );
  2673. pnew_oc->oc_superior = pOcSup;
  2674. pOcSup = NULL; /* don't free this later */
  2675. pnew_oc->oc_oid = pOcOid;
  2676. pOcOid = NULL; /* don't free this later */
  2677. pnew_oc->oc_desc = pOcDesc;
  2678. pOcDesc = NULL; /* don't free this later */
  2679. pnew_oc->oc_required = RequiredAttrsArray;
  2680. pnew_oc->oc_allowed = AllowedAttrsArray;
  2681. pnew_oc->oc_orig_required = OrigRequiredAttrsArray;
  2682. pnew_oc->oc_orig_allowed = OrigAllowedAttrsArray;
  2683. pnew_oc->oc_origin = cool_charray_dup( oc_origins );
  2684. pnew_oc->oc_next = NULL;
  2685. pnew_oc->oc_flags = flags;
  2686. pnew_oc->oc_kind = kind;
  2687. *oc = pnew_oc;
  2688. return read_oc_ldif_return( LDAP_SUCCESS, pOcOid, psbOcName, pOcSup,
  2689. oc_origins, num_origins, pOcDesc );
  2690. }
  2691. static void
  2692. oc_free( struct objclass **ocp )
  2693. {
  2694. struct objclass *oc;
  2695. if ( NULL != ocp && NULL != *ocp ) {
  2696. oc = *ocp;
  2697. slapi_ch_free( (void **)&oc->oc_name );
  2698. slapi_ch_free( (void **)&oc->oc_desc );
  2699. slapi_ch_free( (void **)&oc->oc_oid );
  2700. slapi_ch_free( (void **)&oc->oc_superior );
  2701. charray_free( oc->oc_required );
  2702. charray_free( oc->oc_allowed );
  2703. charray_free( oc->oc_orig_required );
  2704. charray_free( oc->oc_orig_allowed );
  2705. cool_charray_free( oc->oc_origin );
  2706. slapi_ch_free( (void **)&oc );
  2707. *ocp = NULL;
  2708. }
  2709. }
  2710. struct supargs{
  2711. char *sup, *oid;
  2712. unsigned long rc;
  2713. };
  2714. static int
  2715. at_sup_dependency_callback(struct asyntaxinfo *asi, void *arg)
  2716. {
  2717. struct supargs *aew = (struct supargs *)arg;
  2718. int rc=ATTR_SYNTAX_ENUM_NEXT;
  2719. if (!asi) {
  2720. LDAPDebug(LDAP_DEBUG_ANY, "Error: no attribute types in at_schema_attributes_callback\n",
  2721. 0, 0, 0);
  2722. }
  2723. else
  2724. {
  2725. if (strcasecmp (asi->asi_oid, aew->oid ) == 0) {
  2726. rc=ATTR_SYNTAX_ENUM_STOP;
  2727. } else {
  2728. if(asi->asi_name != NULL) {
  2729. if (strcasecmp (asi->asi_name, aew->sup ) == 0) {
  2730. aew->rc=0;
  2731. } else if (asi->asi_aliases) {
  2732. int i = 0;
  2733. /* Loop through aliases to see if any match */
  2734. for (i=0; asi->asi_aliases[i] != NULL; i++) {
  2735. if (strcasecmp (asi->asi_aliases[i], aew->sup ) == 0) {
  2736. aew->rc=0;
  2737. }
  2738. }
  2739. }
  2740. }
  2741. }
  2742. }
  2743. return rc;
  2744. }
  2745. /* walks down attribute types and makes sure that the superior value is found in an attribute type
  2746. preceeding in the hash table. I have concerns about collisions messing with the order here but this
  2747. may be the best we can do.
  2748. */
  2749. static int
  2750. slapi_check_at_sup_dependency(char *sup, char *oid)
  2751. {
  2752. struct supargs aew;
  2753. memset(&aew,0,sizeof(struct supargs));
  2754. aew.rc=LDAP_TYPE_OR_VALUE_EXISTS;
  2755. aew.sup=sup;
  2756. aew.oid=oid;
  2757. attr_syntax_enumerate_attrs(at_sup_dependency_callback, &aew, PR_FALSE);
  2758. return aew.rc;
  2759. }
  2760. /*
  2761. * if asipp is NULL, the attribute type is added to the global set of schema.
  2762. * if asipp is not NULL, the AT is not added but *asipp is set. When you are
  2763. * finished with *asipp, use attr_syntax_free() to dispose of it.
  2764. *
  2765. * schema_flags: Any or none of the following bits could be set
  2766. * DSE_SCHEMA_NO_CHECK -- schema won't be checked
  2767. * DSE_SCHEMA_NO_GLOCK -- locking of global resources is turned off;
  2768. * this saves time during initialization since
  2769. * the server operates in single threaded mode
  2770. * at that time or in reload_schemafile_lock.
  2771. * DSE_SCHEMA_LOCKED -- already locked with reload_schemafile_lock;
  2772. * no further lock needed
  2773. *
  2774. * if is_user_defined is true, force attribute type to be user defined.
  2775. *
  2776. * returns an LDAP error code (LDAP_SUCCESS if all goes well)
  2777. */
  2778. static int
  2779. read_at_ldif(const char *input, struct asyntaxinfo **asipp, char *errorbuf,
  2780. size_t errorbufsize, PRUint32 schema_flags, int is_user_defined,
  2781. int schema_ds4x_compat, int is_remote)
  2782. {
  2783. char *pStart, *pEnd;
  2784. char *pOid, *pSyntax, *pSuperior, *pMREquality, *pMROrdering, *pMRSubstring;
  2785. const char *nextinput;
  2786. struct sizedbuffer *psbAttrName= sizedbuffer_construct(BUFSIZ);
  2787. struct sizedbuffer *psbAttrDesc= sizedbuffer_construct(BUFSIZ);
  2788. int status = 0;
  2789. int syntaxlength;
  2790. char **attr_names = NULL;
  2791. char *first_attr_name = NULL;
  2792. char **attr_origins = NULL;
  2793. int num_names = 0;
  2794. int num_origins = 0;
  2795. unsigned long flags = SLAPI_ATTR_FLAG_OVERRIDE;
  2796. const char *ss = 0;
  2797. struct asyntaxinfo *tmpasip;
  2798. int invalid_syntax_error;
  2799. schema_strstr_fn_t keyword_strstr_fn;
  2800. /*
  2801. * From RFC 2252 section 4.2:
  2802. *
  2803. * AttributeTypeDescription = "(" whsp
  2804. * numericoid whsp ; AttributeType identifier
  2805. * [ "NAME" qdescrs ] ; name used in AttributeType
  2806. * [ "DESC" qdstring ] ; description
  2807. * [ "OBSOLETE" whsp ]
  2808. * [ "SUP" woid ] ; derived from this other
  2809. * ; AttributeType
  2810. * [ "EQUALITY" woid ; Matching Rule name
  2811. * [ "ORDERING" woid ; Matching Rule name
  2812. * [ "SUBSTR" woid ] ; Matching Rule name
  2813. * [ "SYNTAX" whsp noidlen whsp ] ; see section 4.3
  2814. * [ "SINGLE-VALUE" whsp ] ; default multi-valued
  2815. * [ "COLLECTIVE" whsp ] ; default not collective
  2816. * [ "NO-USER-MODIFICATION" whsp ]; default user modifiable
  2817. * [ "USAGE" whsp AttributeUsage ]; default userApplications
  2818. * whsp ")"
  2819. *
  2820. * AttributeUsage =
  2821. * "userApplications" /
  2822. * "directoryOperation" /
  2823. * "distributedOperation" / ; DSA-shared
  2824. * "dSAOperation" ; DSA-specific, value depends on server
  2825. *
  2826. * XXXmcs: Our parsing technique is poor. In (Netscape) DS 4.12 and earlier
  2827. * releases, parsing was mostly done by looking anywhere within the input
  2828. * string for various keywords such as "EQUALITY". But if, for example, a
  2829. * description contains the word "equality", the parser would take assume
  2830. * that the token following the word was a matching rule. Bad news.
  2831. *
  2832. * In iDS 5.0 and later, we parse in order left to right and advance a
  2833. * pointer as we consume the input string (the nextinput variable). We
  2834. * also use a case-insensitive search when looking for keywords such as
  2835. * DESC. This is still less than ideal.
  2836. *
  2837. * Someday soon we will need to write a real parser.
  2838. *
  2839. * Compatibility notes: if schema_ds4x_compat is set, we:
  2840. * 1. always parse from the beginning of the string
  2841. * 2. use a case-insensitive compare when looking for keywords, e.g., DESC
  2842. */
  2843. if ( schema_ds4x_compat ) {
  2844. keyword_strstr_fn = PL_strcasestr;
  2845. invalid_syntax_error = LDAP_OPERATIONS_ERROR;
  2846. } else {
  2847. keyword_strstr_fn = PL_strstr;
  2848. invalid_syntax_error = LDAP_INVALID_SYNTAX;
  2849. }
  2850. if (schema_flags & DSE_SCHEMA_NO_GLOCK)
  2851. flags |= SLAPI_ATTR_FLAG_NOLOCKING;
  2852. psbAttrName->buffer[0] = '\0';
  2853. psbAttrDesc->buffer[0] = '\0';
  2854. pOid = pSyntax = pSuperior = NULL;
  2855. pMREquality = pMROrdering = pMRSubstring = NULL;
  2856. syntaxlength = SLAPI_SYNTAXLENGTH_NONE;
  2857. nextinput = input;
  2858. /* get the OID */
  2859. pOid = get_tagged_oid( "(", &nextinput, keyword_strstr_fn );
  2860. if (NULL == pOid) {
  2861. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
  2862. input, "Missing or invalid OID" );
  2863. status = invalid_syntax_error;
  2864. goto done;
  2865. }
  2866. if ( schema_ds4x_compat || (strcasecmp(pOid, "NAME") == 0))
  2867. nextinput = input;
  2868. /* look for the NAME (single or list of names) */
  2869. if ( (pStart = (*keyword_strstr_fn) ( nextinput, "NAME ")) != NULL ) {
  2870. pStart += 5;
  2871. sizedbuffer_allocate(psbAttrName,strlen(pStart)+1);
  2872. strcpy ( psbAttrName->buffer, pStart);
  2873. if (*pStart == '(')
  2874. pEnd = strchr(psbAttrName->buffer, ')');
  2875. else
  2876. pEnd = strchr(psbAttrName->buffer+1, '\'');
  2877. if (pEnd)
  2878. *(pEnd+1) = 0;
  2879. nextinput = pStart + strlen(psbAttrName->buffer) + 1;
  2880. attr_names = parse_qdescrs(psbAttrName->buffer, &num_names);
  2881. if ( NULL != attr_names ) {
  2882. first_attr_name = attr_names[0];
  2883. } else { /* NAME followed by nothing violates syntax */
  2884. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
  2885. input, "Missing or invalid attribute name" );
  2886. status = invalid_syntax_error;
  2887. goto done;
  2888. }
  2889. }
  2890. if ( schema_ds4x_compat ) nextinput = input;
  2891. /*
  2892. * if the attribute ldif doesn't have an OID, we'll make the oid
  2893. * attrname-oid
  2894. */
  2895. if ( (strcasecmp ( pOid, "NAME" ) == 0) && (first_attr_name)) {
  2896. slapi_ch_free_string( &pOid );
  2897. pOid = slapi_ch_smprintf("%s-oid", first_attr_name );
  2898. }
  2899. /* look for the optional DESCription */
  2900. if ( (pStart = (*keyword_strstr_fn) ( nextinput, "DESC '")) != NULL ) {
  2901. pStart += 6;
  2902. sizedbuffer_allocate(psbAttrDesc,strlen(pStart));
  2903. strcpy ( psbAttrDesc->buffer, pStart);
  2904. if ( (pEnd = strchr (psbAttrDesc->buffer, '\'' )) != NULL ){
  2905. *pEnd ='\0';
  2906. }
  2907. nextinput = pStart + strlen(psbAttrDesc->buffer) + 1;
  2908. }
  2909. if ( schema_ds4x_compat ) nextinput = input;
  2910. /* look for the optional OBSOLETE marker */
  2911. flags |= get_flag_keyword( schema_obsolete_with_spaces,
  2912. SLAPI_ATTR_FLAG_OBSOLETE, &nextinput, keyword_strstr_fn );
  2913. if ( schema_ds4x_compat ) nextinput = input;
  2914. /* look for the optional SUPerior type */
  2915. pSuperior = get_tagged_oid( "SUP ", &nextinput, keyword_strstr_fn );
  2916. if ( schema_ds4x_compat ) nextinput = input;
  2917. /* look for the optional matching rules */
  2918. pMREquality = get_tagged_oid( "EQUALITY ", &nextinput, keyword_strstr_fn );
  2919. if ( schema_ds4x_compat ) nextinput = input;
  2920. pMROrdering = get_tagged_oid( "ORDERING ", &nextinput, keyword_strstr_fn );
  2921. if ( schema_ds4x_compat ) nextinput = input;
  2922. pMRSubstring = get_tagged_oid( "SUBSTR ", &nextinput, keyword_strstr_fn );
  2923. if ( schema_ds4x_compat ) nextinput = input;
  2924. /* look for the optional SYNTAX */
  2925. if ( NULL != ( pSyntax = get_tagged_oid( "SYNTAX ", &nextinput,
  2926. keyword_strstr_fn ))) {
  2927. /*
  2928. * Check for an optional {LEN}, which if present indicates a
  2929. * suggested maximum size for values of this attribute type.
  2930. *
  2931. * XXXmcs: we do not enforce length restrictions, but we do read
  2932. * and include them in the subschemasubentry.
  2933. */
  2934. if ( (pEnd = strchr ( pSyntax, '{')) != NULL /* balance } */ ) {
  2935. *pEnd = '\0';
  2936. syntaxlength = atoi( pEnd + 1 );
  2937. }
  2938. }
  2939. if ( schema_ds4x_compat ) nextinput = input;
  2940. /* look for the optional SINGLE-VALUE marker */
  2941. flags |= get_flag_keyword( " SINGLE-VALUE ",
  2942. SLAPI_ATTR_FLAG_SINGLE, &nextinput, keyword_strstr_fn );
  2943. if ( schema_ds4x_compat ) nextinput = input;
  2944. /* look for the optional COLLECTIVE marker */
  2945. flags |= get_flag_keyword( schema_collective_with_spaces,
  2946. SLAPI_ATTR_FLAG_COLLECTIVE, &nextinput, keyword_strstr_fn );
  2947. if ( schema_ds4x_compat ) nextinput = input;
  2948. /* look for the optional NO-USER-MODIFICATION marker */
  2949. flags |= get_flag_keyword( schema_nousermod_with_spaces,
  2950. SLAPI_ATTR_FLAG_NOUSERMOD, &nextinput, keyword_strstr_fn );
  2951. if ( schema_ds4x_compat ) nextinput = input;
  2952. /* look for the optional USAGE */
  2953. if (NULL != (ss = (*keyword_strstr_fn)(nextinput, " USAGE "))) {
  2954. ss += 7;
  2955. ss = skipWS(ss);
  2956. if (ss) {
  2957. if ( !PL_strncmp(ss, "directoryOperation",
  2958. strlen("directoryOperation"))) {
  2959. flags |= SLAPI_ATTR_FLAG_OPATTR;
  2960. }
  2961. if ( NULL == ( nextinput = strchr( ss, ' ' ))) {
  2962. nextinput = ss + strlen(ss);
  2963. }
  2964. }
  2965. }
  2966. if ( schema_ds4x_compat ) nextinput = input;
  2967. /* X-ORIGIN list */
  2968. attr_origins = parse_origin_list( nextinput, &num_origins,
  2969. schema_user_defined_origin );
  2970. /* Do some sanity checking to make sure everything was read correctly */
  2971. if (NULL == pOid) {
  2972. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
  2973. first_attr_name, "Missing OID" );
  2974. status = invalid_syntax_error;
  2975. }
  2976. if (!status && (!attr_names || !num_names)) {
  2977. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
  2978. first_attr_name,
  2979. "Missing name (OID is \"%s\")", pOid );
  2980. status = invalid_syntax_error;
  2981. }
  2982. if (!status && (NULL != pSuperior)) {
  2983. struct asyntaxinfo *asi_parent;
  2984. asi_parent = attr_syntax_get_by_name(pSuperior);
  2985. /* if we find no match then server won't start or add the attribute type */
  2986. if (asi_parent == NULL) {
  2987. LDAPDebug (LDAP_DEBUG_PARSE,
  2988. "Cannot find parent attribute type \"%s\"\n",pSuperior,
  2989. NULL,NULL);
  2990. schema_create_errormsg( errorbuf, errorbufsize,
  2991. schema_errprefix_at, first_attr_name,
  2992. "Missing parent attribute syntax OID");
  2993. status = invalid_syntax_error;
  2994. /* We only want to use the parent syntax if a SYNTAX
  2995. * wasn't explicitly specified for this attribute. */
  2996. } else if (NULL == pSyntax) {
  2997. char *pso = plugin_syntax2oid(asi_parent->asi_plugin);
  2998. if (pso) {
  2999. slapi_ch_free ((void **)&pSyntax);
  3000. pSyntax = slapi_ch_strdup(pso);
  3001. LDAPDebug (LDAP_DEBUG_TRACE,
  3002. "Inheriting syntax %s from parent type %s\n",
  3003. pSyntax, pSuperior,NULL);
  3004. } else {
  3005. schema_create_errormsg( errorbuf, errorbufsize,
  3006. schema_errprefix_at, first_attr_name,
  3007. "Missing parent attribute syntax OID");
  3008. status = invalid_syntax_error;
  3009. }
  3010. attr_syntax_return( asi_parent );
  3011. }
  3012. }
  3013. /*
  3014. if we are remote (via modify_schema_dse) then check sup dependencies. Locally
  3015. was done in if statement above
  3016. */
  3017. if(!status)
  3018. {
  3019. if(is_remote && (pSuperior != NULL))
  3020. {
  3021. status=slapi_check_at_sup_dependency(pSuperior, pOid);
  3022. }
  3023. if(LDAP_SUCCESS != status) {
  3024. schema_create_errormsg( errorbuf, errorbufsize,
  3025. schema_errprefix_at, first_attr_name,
  3026. "Missing parent attribute syntax OID");
  3027. status = LDAP_TYPE_OR_VALUE_EXISTS;
  3028. }
  3029. }
  3030. if (!status && (NULL == pSyntax)) {
  3031. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
  3032. first_attr_name, "Missing attribute syntax OID");
  3033. status = invalid_syntax_error;
  3034. }
  3035. if (!status && (plugin_syntax_find ( pSyntax ) == NULL) ) {
  3036. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
  3037. first_attr_name, "Unknown attribute syntax OID \"%s\"",
  3038. pSyntax );
  3039. status = invalid_syntax_error;
  3040. }
  3041. if (!status) {
  3042. struct objclass *poc;
  3043. /* check to make sure that the OID isn't being used by an objectclass */
  3044. if (!(schema_flags & DSE_SCHEMA_LOCKED))
  3045. oc_lock_read();
  3046. poc = oc_find_oid_nolock( pOid );
  3047. if ( poc != NULL) {
  3048. schema_create_errormsg( errorbuf, errorbufsize,
  3049. schema_errprefix_at, first_attr_name,
  3050. "The OID \"%s\" is also used by the object class \"%s\"",
  3051. pOid, poc->oc_name);
  3052. status = LDAP_TYPE_OR_VALUE_EXISTS;
  3053. }
  3054. if (!(schema_flags & DSE_SCHEMA_LOCKED))
  3055. oc_unlock();
  3056. }
  3057. if (!status && !element_is_user_defined( attr_origins )) {
  3058. if ( is_user_defined ) {
  3059. /* add missing user defined origin string */
  3060. charray_add( &attr_origins,
  3061. slapi_ch_strdup( schema_user_defined_origin[0] ));
  3062. ++num_origins;
  3063. } else {
  3064. flags |= SLAPI_ATTR_FLAG_STD_ATTR;
  3065. }
  3066. }
  3067. if (!(schema_flags & DSE_SCHEMA_NO_CHECK) && !status) {
  3068. int ii;
  3069. /* check to see if the attribute name is valid */
  3070. for (ii = 0; !status && (ii < num_names); ++ii) {
  3071. if ( schema_check_name(attr_names[ii], PR_TRUE, errorbuf,
  3072. errorbufsize) == 0 ) {
  3073. status = invalid_syntax_error;
  3074. }
  3075. else if (!(flags & SLAPI_ATTR_FLAG_OVERRIDE) &&
  3076. attr_syntax_exists(attr_names[ii])) {
  3077. schema_create_errormsg( errorbuf, errorbufsize,
  3078. schema_errprefix_at, attr_names[ii],
  3079. "Could not be added because it already exists" );
  3080. status = LDAP_TYPE_OR_VALUE_EXISTS;
  3081. }
  3082. }
  3083. }
  3084. if (!(schema_flags & DSE_SCHEMA_NO_CHECK) && !status) {
  3085. if ( schema_check_oid ( first_attr_name, pOid, PR_TRUE, errorbuf,
  3086. errorbufsize ) == 0 ) {
  3087. status = invalid_syntax_error;
  3088. }
  3089. }
  3090. if (!status) {
  3091. struct asyntaxinfo *tmpasi;
  3092. if (!(flags & SLAPI_ATTR_FLAG_OVERRIDE) &&
  3093. ( NULL != ( tmpasi = attr_syntax_get_by_oid(pOid)))) {
  3094. schema_create_errormsg( errorbuf, errorbufsize,
  3095. schema_errprefix_at, first_attr_name,
  3096. "Could not be added because the OID \"%s\" is already in use",
  3097. pOid);
  3098. status = LDAP_TYPE_OR_VALUE_EXISTS;
  3099. attr_syntax_return( tmpasi );
  3100. }
  3101. }
  3102. if (!status) {
  3103. status = attr_syntax_create( pOid, attr_names, num_names,
  3104. *psbAttrDesc->buffer == '\0' ? NULL : psbAttrDesc->buffer,
  3105. pSuperior,
  3106. pMREquality, pMROrdering, pMRSubstring, attr_origins,
  3107. pSyntax, syntaxlength, flags, &tmpasip );
  3108. }
  3109. if (!status) {
  3110. if ( NULL != asipp ) {
  3111. *asipp = tmpasip; /* just return it */
  3112. } else { /* add the new attribute to the global store */
  3113. status = attr_syntax_add( tmpasip );
  3114. if ( LDAP_SUCCESS != status ) {
  3115. if ( 0 != (flags & SLAPI_ATTR_FLAG_OVERRIDE) &&
  3116. LDAP_TYPE_OR_VALUE_EXISTS == status ) {
  3117. /*
  3118. * This can only occur if the name and OID don't match the
  3119. * attribute we are trying to override (all other cases of
  3120. * "type or value exists" were trapped above).
  3121. */
  3122. schema_create_errormsg( errorbuf, errorbufsize,
  3123. schema_errprefix_at, first_attr_name,
  3124. "Does not match the OID \"%s\". Another attribute"
  3125. " type is already using the name or OID.", pOid);
  3126. } else {
  3127. schema_create_errormsg( errorbuf, errorbufsize,
  3128. schema_errprefix_at, first_attr_name,
  3129. "Could not be added (OID is \"%s\")", pOid );
  3130. }
  3131. attr_syntax_free( tmpasip );
  3132. }
  3133. }
  3134. }
  3135. done:
  3136. /* free everything */
  3137. free_qdlist(attr_names, num_names);
  3138. free_qdlist(attr_origins, num_origins);
  3139. sizedbuffer_destroy(psbAttrName);
  3140. sizedbuffer_destroy(psbAttrDesc);
  3141. slapi_ch_free((void **)&pOid);
  3142. slapi_ch_free((void **)&pSuperior);
  3143. slapi_ch_free((void **)&pMREquality);
  3144. slapi_ch_free((void **)&pMROrdering);
  3145. slapi_ch_free((void **)&pMRSubstring);
  3146. slapi_ch_free((void **)&pSyntax);
  3147. return status;
  3148. }
  3149. /*
  3150. * schema_check_oc_attrs:
  3151. * Check to see if the required and allowed attributes are valid attributes
  3152. *
  3153. * arguments: poc : pointer to the objectclass to check
  3154. * errorbuf : buffer to write any error messages to
  3155. * stripOptions: 1 if you want to silently strip any options
  3156. * 0 if options should cause an error
  3157. *
  3158. * Returns:
  3159. *
  3160. * 0 if there's a unknown attribute, and errorbuf will contain an
  3161. * error message.
  3162. *
  3163. * 1 if everything is ok
  3164. *
  3165. * Note: no locking of poc is needed because poc is always a newly allocated
  3166. * objclass struct (this function is only called by add_oc_internal).
  3167. */
  3168. static int
  3169. schema_check_oc_attrs ( struct objclass *poc,
  3170. char *errorbuf, size_t errorbufsize,
  3171. int stripOptions )
  3172. {
  3173. int i;
  3174. if ( errorbuf == NULL || poc == NULL || poc->oc_name == NULL) {
  3175. /* error */
  3176. LDAPDebug (LDAP_DEBUG_PARSE,
  3177. "Null args passed to schema_check_oc_attrs\n",
  3178. NULL, NULL, NULL);
  3179. return -1;
  3180. }
  3181. /* remove any options like ;binary from the oc's attributes */
  3182. if ( strip_oc_options( poc ) && !stripOptions) {
  3183. /* there were options present, this oc should be rejected */
  3184. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
  3185. poc->oc_name, "Contains attribute options. "
  3186. "Attribute options, such as \";binary\" are not allowed in "
  3187. "object class definitions." );
  3188. return 0;
  3189. }
  3190. for ( i = 0; poc->oc_allowed && poc->oc_allowed[i]; i++ ) {
  3191. if ( attr_syntax_exists ( poc->oc_allowed[i] ) == 0 ) {
  3192. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
  3193. poc->oc_name, "Unknown allowed attribute type \"%s\"",
  3194. poc->oc_allowed[i]);
  3195. return 0;
  3196. }
  3197. }
  3198. for ( i = 0; poc->oc_required && poc->oc_required[i]; i++ ) {
  3199. if ( attr_syntax_exists ( poc->oc_required[i] ) == 0 ) {
  3200. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
  3201. poc->oc_name, "Unknown required attribute type \"%s\"",
  3202. poc->oc_required[i]);
  3203. return 0;
  3204. }
  3205. }
  3206. return 1;
  3207. }
  3208. /*
  3209. * schema_check_name:
  3210. * Check if the attribute or objectclass name is valid. Names can only contain
  3211. * characters, digits, and hyphens. In addition, names must begin with
  3212. * a character. If the nsslapd-attribute-name-exceptions attribute in cn=config
  3213. * is true, then we also allow underscores.
  3214. *
  3215. * XXX We're also supposed to allow semicolons, but we already use them to deal
  3216. * with attribute options XXX
  3217. *
  3218. * returns 1 if the attribute has a legal name
  3219. * 0 if not
  3220. *
  3221. * If the attribute name is invalid, an error message will be written to msg
  3222. */
  3223. static int
  3224. schema_check_name(char *name, PRBool isAttribute, char *errorbuf,
  3225. size_t errorbufsize )
  3226. {
  3227. int i;
  3228. /* allowed characters */
  3229. static char allowed[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-";
  3230. /* additional characters to allow if allow_exceptions is true */
  3231. static char allowedExceptions[] = "_";
  3232. int allow_exceptions = config_get_attrname_exceptions();
  3233. if ( name == NULL || errorbuf == NULL) {
  3234. /* this is bad */
  3235. return 0;
  3236. }
  3237. /* attribute names must begin with a letter */
  3238. if ( (isascii (name[0]) == 0) || (isalpha (name[0]) == 0)) {
  3239. if ( (strlen(name) + 80) < BUFSIZ ) {
  3240. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
  3241. name, "The name is invalid. Names must begin with a letter" );
  3242. }
  3243. else {
  3244. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
  3245. name, "The name is invalid, and probably too long. "
  3246. "Names must begin with a letter" );
  3247. }
  3248. return 0;
  3249. }
  3250. for (i = 1; name[i]; i++ ) {
  3251. if ( (NULL == strchr( allowed, name[i] )) &&
  3252. (!allow_exceptions ||
  3253. (NULL == strchr(allowedExceptions, name[i])) ) ) {
  3254. if ( (strlen(name) + 80) < BUFSIZ ) {
  3255. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
  3256. name, "The name contains the invalid character \"%c\"", name[i] );
  3257. }
  3258. else {
  3259. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
  3260. name, "The name contains the invalid character \"%c\". The name"
  3261. " is also probably too long.", name[i] );
  3262. }
  3263. return 0;
  3264. }
  3265. }
  3266. return 1;
  3267. }
  3268. /*
  3269. * schema_check_oid:
  3270. * Check if the oid is valid.
  3271. *
  3272. * returns 1 if the attribute has a legal oid
  3273. * 0 if not
  3274. *
  3275. * If the oid is invalid, an error message will be written to errorbuf
  3276. *
  3277. * Oids can either have the form <attr/oc name>-oid or
  3278. * start and end with a digit, and contain only digits and periods
  3279. */
  3280. static int
  3281. schema_check_oid( const char *name, const char *oid, PRBool isAttribute,
  3282. char *errorbuf, size_t errorbufsize ) {
  3283. int i = 0, length_oid = 0, rc = 0;
  3284. char *namePlusOid = NULL;
  3285. if ( name == NULL || oid == NULL) {
  3286. /* this is bad */
  3287. LDAPDebug (LDAP_DEBUG_ANY, "NULL passed to schema_check_oid\n",0,0,0);
  3288. return 0;
  3289. }
  3290. /* check to see if the OID is <name>-oid */
  3291. namePlusOid = slapi_ch_smprintf("%s-oid", name );
  3292. rc = strcasecmp( oid, namePlusOid );
  3293. slapi_ch_free( (void **) &namePlusOid );
  3294. if ( 0 == rc ) {
  3295. return 1;
  3296. }
  3297. /* If not, the OID must begin and end with a digit, and contain only
  3298. digits and dots */
  3299. /* check to see that it begins and ends with a digit */
  3300. length_oid = strlen(oid);
  3301. if ( !isdigit(oid[0]) ||
  3302. !isdigit(oid[length_oid-1]) ) {
  3303. schema_create_errormsg( errorbuf, errorbufsize,
  3304. isAttribute ? schema_errprefix_at : schema_errprefix_oc,
  3305. name,
  3306. "The OID \"%s\" must begin and end with a digit, or be \"%s-oid\"",
  3307. oid, name );
  3308. return 0;
  3309. }
  3310. /* check to see that it contains only digits and dots */
  3311. for ( i = 0; i < length_oid; i++ ) {
  3312. if ( !isdigit(oid[i]) && oid[i] != '.' ){
  3313. schema_create_errormsg( errorbuf, errorbufsize,
  3314. isAttribute ? schema_errprefix_at : schema_errprefix_oc,
  3315. name,
  3316. "The OID \"%s\" contains an invalid character: \"%c\"; the"
  3317. " OID must contain only digits and periods, or be \"%s-oid\"",
  3318. oid, oid[i], name );
  3319. return 0;
  3320. }
  3321. }
  3322. /* The oid is OK if we're here */
  3323. return 1;
  3324. }
  3325. /*
  3326. * Some utility functions for dealing with a dynamically
  3327. * allocated buffer.
  3328. */
  3329. static struct sizedbuffer *sizedbuffer_construct(size_t size)
  3330. {
  3331. struct sizedbuffer *p= (struct sizedbuffer *)slapi_ch_malloc(sizeof(struct sizedbuffer));
  3332. p->size= size;
  3333. if(size>0)
  3334. {
  3335. p->buffer= (char*)slapi_ch_malloc(size);
  3336. p->buffer[0]= '\0';
  3337. }
  3338. else
  3339. {
  3340. p->buffer= NULL;
  3341. }
  3342. return p;
  3343. }
  3344. static void sizedbuffer_destroy(struct sizedbuffer *p)
  3345. {
  3346. if(p!=NULL)
  3347. {
  3348. slapi_ch_free((void**)&p->buffer);
  3349. }
  3350. slapi_ch_free((void**)&p);
  3351. }
  3352. static void sizedbuffer_allocate(struct sizedbuffer *p, size_t sizeneeded)
  3353. {
  3354. if(p!=NULL)
  3355. {
  3356. if(sizeneeded>p->size)
  3357. {
  3358. if(p->buffer!=NULL)
  3359. {
  3360. slapi_ch_free((void**)&p->buffer);
  3361. }
  3362. p->buffer= (char*)slapi_ch_malloc(sizeneeded);
  3363. p->buffer[0]= '\0';
  3364. p->size= sizeneeded;
  3365. }
  3366. }
  3367. }
  3368. /*
  3369. * has_smart_referral: returns 1 if the entry contains a ref attribute,
  3370. * or a referral objectclass.
  3371. *
  3372. * Returns 0 If not.
  3373. */
  3374. static int
  3375. has_smart_referral( Slapi_Entry *e ) {
  3376. Slapi_Attr *aoc;
  3377. char ebuf[BUFSIZ];
  3378. /* Look for the ref attribute */
  3379. if ( (aoc = attrlist_find( e->e_attrs, "ref" )) != NULL ) {
  3380. LDAPDebug ( LDAP_DEBUG_ANY, "Entry \"%s\" contains a ref attrbute. Smart referrals are disabled in Directory Lite.\n", escape_string(slapi_entry_get_dn_const(e), ebuf),0,0 );
  3381. return 1;
  3382. }
  3383. /* Look for the referral objectclass */
  3384. if ( (aoc = attrlist_find( e->e_attrs, "objectclass" )) != NULL ) {
  3385. Slapi_Value target, *found;
  3386. slapi_value_init(&target);
  3387. slapi_value_set_string(&target,"referral");
  3388. found= slapi_valueset_find(aoc, &aoc->a_present_values, &target);
  3389. value_done(&target);
  3390. if(found!=NULL)
  3391. {
  3392. LDAPDebug ( LDAP_DEBUG_ANY, "Entry \"%s\" is a referral object class. Smart referrals are disabled in Directory Lite.\n", escape_string(slapi_entry_get_dn_const(e), ebuf),0,0 );
  3393. return 1;
  3394. }
  3395. }
  3396. /* No smart referral here */
  3397. return 0;
  3398. }
  3399. /*
  3400. * Check if the object class is extensible
  3401. */
  3402. static int isExtensibleObjectclass(const char *objectclass)
  3403. {
  3404. if ( strcasecmp( objectclass, "extensibleobject" ) == 0 ) {
  3405. return( 1 );
  3406. }
  3407. /* The Easter Egg is based on a special object class */
  3408. if ( strcasecmp( objectclass, EGG_OBJECT_CLASS ) == 0 ) {
  3409. return( 1 );
  3410. }
  3411. return 0;
  3412. }
  3413. /*
  3414. * strip_oc_options: strip any attribute options from the objectclass'
  3415. * attributes (remove things like ;binary from the attrs)
  3416. *
  3417. * argument: pointer to an objectclass, attributes will have their
  3418. * options removed in place
  3419. *
  3420. * returns: number of options removed
  3421. *
  3422. * Note: no locking of poc is needed because poc is always a newly allocated
  3423. * objclass struct (this function is only called by schema_check_oc_attrs,
  3424. * which is only called by add_oc_internal).
  3425. */
  3426. static int
  3427. strip_oc_options( struct objclass *poc ) {
  3428. int i, numRemoved = 0;
  3429. char *mod = NULL;
  3430. for ( i = 0; poc->oc_allowed && poc->oc_allowed[i]; i++ ) {
  3431. if ( (mod = stripOption( poc->oc_allowed[i] )) != NULL ){
  3432. LDAPDebug (LDAP_DEBUG_ANY,
  3433. "Removed option \"%s\" from allowed attribute type "
  3434. "\"%s\" in object class \"%s\".\n",
  3435. mod, poc->oc_allowed[i], poc->oc_name );
  3436. numRemoved++;
  3437. }
  3438. }
  3439. for ( i = 0; poc->oc_required && poc->oc_required[i]; i++ ) {
  3440. if ( (mod = stripOption( poc->oc_required[i] )) != NULL ){
  3441. LDAPDebug (LDAP_DEBUG_ANY,
  3442. "Removed option \"%s\" from required attribute type "
  3443. "\"%s\" in object class \"%s\".\n",
  3444. mod, poc->oc_required[i], poc->oc_name );
  3445. numRemoved++;
  3446. }
  3447. }
  3448. return numRemoved;
  3449. }
  3450. /*
  3451. * stripOption:
  3452. * removes options such as ";binary" from attribute names
  3453. *
  3454. * argument: pointer to an attribute name, such as "userCertificate;binary"
  3455. *
  3456. * returns: pointer to the option, such as "binary"
  3457. * NULL if there's no option
  3458. *
  3459. */
  3460. static char *
  3461. stripOption(char *attr) {
  3462. char *pSemiColon = strchr( attr, ';' );
  3463. if (pSemiColon) {
  3464. *pSemiColon = '\0';
  3465. }
  3466. return pSemiColon ? pSemiColon + 1 : NULL;
  3467. }
  3468. /*
  3469. * load_schema_dse: called by dse_read_file() when target is cn=schema
  3470. *
  3471. * Initialize attributes and objectclasses from the schema
  3472. *
  3473. * Note that this function removes all values for `attributetypes'
  3474. * and `objectclasses' attributes from the entry `e'.
  3475. *
  3476. * returntext is always at least SLAPI_DSE_RETURNTEXT_SIZE bytes in size.
  3477. */
  3478. int
  3479. load_schema_dse(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *ignored,
  3480. int *returncode, char *returntext, void *arg)
  3481. {
  3482. Slapi_Attr *attr = 0;
  3483. int primary_file = 0; /* this is the primary (writeable) schema file */
  3484. int schema_ds4x_compat = config_get_ds4_compatible_schema();
  3485. PRUint32 flags = *(PRUint32 *)arg;
  3486. flags |= DSE_SCHEMA_NO_GLOCK; /* don't lock global resources
  3487. during initialization */
  3488. *returncode = 0;
  3489. /*
  3490. * Note: there is no need to call schema_lock_write() here because this
  3491. * function is only called during server startup.
  3492. */
  3493. slapi_pblock_get( pb, SLAPI_DSE_IS_PRIMARY_FILE, &primary_file );
  3494. if (!slapi_entry_attr_find(e, "attributetypes", &attr) && attr)
  3495. {
  3496. /* enumerate the values in attr */
  3497. Slapi_Value *v = 0;
  3498. int index = 0;
  3499. for (index = slapi_attr_first_value(attr, &v);
  3500. v && (index != -1);
  3501. index = slapi_attr_next_value(attr, index, &v))
  3502. {
  3503. const char *s = slapi_value_get_string(v);
  3504. if (!s)
  3505. continue;
  3506. if (flags & DSE_SCHEMA_NO_LOAD)
  3507. {
  3508. struct asyntaxinfo *tmpasip = NULL;
  3509. if ((*returncode = read_at_ldif(s, &tmpasip, returntext,
  3510. SLAPI_DSE_RETURNTEXT_SIZE, flags,
  3511. primary_file /* force user defined? */,
  3512. schema_ds4x_compat, 0)) != 0)
  3513. break;
  3514. attr_syntax_free( tmpasip ); /* trash it */
  3515. }
  3516. else
  3517. {
  3518. if ((*returncode = read_at_ldif(s, NULL, returntext,
  3519. SLAPI_DSE_RETURNTEXT_SIZE, flags,
  3520. primary_file /* force user defined? */,
  3521. schema_ds4x_compat, 0)) != 0)
  3522. break;
  3523. }
  3524. }
  3525. slapi_entry_attr_delete(e, "attributetypes");
  3526. }
  3527. if (*returncode)
  3528. return SLAPI_DSE_CALLBACK_ERROR;
  3529. if (!slapi_entry_attr_find(e, "objectclasses", &attr) && attr)
  3530. {
  3531. /* enumerate the values in attr */
  3532. Slapi_Value *v = 0;
  3533. int index = 0;
  3534. for (index = slapi_attr_first_value(attr, &v);
  3535. v && (index != -1);
  3536. index = slapi_attr_next_value(attr, index, &v))
  3537. {
  3538. struct objclass *oc = 0;
  3539. const char *s = slapi_value_get_string(v);
  3540. if (!s)
  3541. continue;
  3542. if ( LDAP_SUCCESS != (*returncode = read_oc_ldif(s, &oc, returntext,
  3543. SLAPI_DSE_RETURNTEXT_SIZE, flags,
  3544. primary_file /* force user defined? */,
  3545. schema_ds4x_compat))) {
  3546. break;
  3547. }
  3548. if (flags & DSE_SCHEMA_NO_LOAD)
  3549. {
  3550. /* we don't load the objectclase; free it */
  3551. oc_free( &oc );
  3552. }
  3553. else
  3554. {
  3555. if ( LDAP_SUCCESS !=
  3556. (*returncode = add_oc_internal(oc, returntext,
  3557. SLAPI_DSE_RETURNTEXT_SIZE, schema_ds4x_compat,
  3558. flags))) {
  3559. oc_free( &oc );
  3560. break;
  3561. }
  3562. }
  3563. }
  3564. slapi_entry_attr_delete(e, "objectclasses");
  3565. }
  3566. /* Set the schema CSN */
  3567. if (!(flags & DSE_SCHEMA_NO_LOAD) &&
  3568. !slapi_entry_attr_find(e, "nsschemacsn", &attr) && attr)
  3569. {
  3570. Slapi_Value *v = NULL;
  3571. slapi_attr_first_value(attr, &v);
  3572. if (NULL != v) {
  3573. const char *s = slapi_value_get_string(v);
  3574. if (NULL != s) {
  3575. CSN *csn = csn_new_by_string(s);
  3576. g_set_global_schema_csn(csn);
  3577. }
  3578. }
  3579. }
  3580. return (*returncode == LDAP_SUCCESS) ? SLAPI_DSE_CALLBACK_OK
  3581. : SLAPI_DSE_CALLBACK_ERROR;
  3582. }
  3583. /*
  3584. * Try to initialize the schema from the LDIF file. Read
  3585. * the file and convert it to the avl tree of DSEs. If the
  3586. * file doesn't exist, we try to create it and put a minimal
  3587. * schema entry into it.
  3588. *
  3589. * Returns 1 for OK, 0 for Fail.
  3590. *
  3591. * schema_flags:
  3592. * DSE_SCHEMA_NO_LOAD -- schema won't get loaded
  3593. * DSE_SCHEMA_NO_CHECK -- schema won't be checked
  3594. * DSE_SCHEMA_NO_BACKEND -- don't add as backend
  3595. * DSE_SCHEMA_LOCKED -- already locked; no further lock needed
  3596. */
  3597. static int
  3598. init_schema_dse_ext(char *schemadir, Slapi_Backend *be,
  3599. struct dse **local_pschemadse, PRUint32 schema_flags)
  3600. {
  3601. int rc= 1; /* OK */
  3602. char *userschemafile = 0;
  3603. char *userschematmpfile = 0;
  3604. char **filelist = 0;
  3605. char *myschemadir = NULL;
  3606. Slapi_DN schema;
  3607. if (NULL == local_pschemadse)
  3608. {
  3609. return 0; /* cannot proceed; return failure */
  3610. }
  3611. slapi_sdn_init_dn_byref(&schema,"cn=schema");
  3612. /* get schemadir if not given */
  3613. if (NULL == schemadir)
  3614. {
  3615. myschemadir = config_get_schemadir();
  3616. if (NULL == myschemadir)
  3617. {
  3618. return 0; /* cannot proceed; return failure */
  3619. }
  3620. }
  3621. else
  3622. {
  3623. myschemadir = schemadir;
  3624. }
  3625. filelist = get_priority_filelist(myschemadir, ".*ldif$");
  3626. if (!filelist || !*filelist)
  3627. {
  3628. slapi_log_error(SLAPI_LOG_FATAL, "schema",
  3629. "No schema files were found in the directory %s\n", myschemadir);
  3630. free_filelist(filelist);
  3631. rc = 0;
  3632. }
  3633. else
  3634. {
  3635. /* figure out the last file in the list; it is the user schema */
  3636. int ii = 0;
  3637. while (filelist[ii]) ++ii;
  3638. userschemafile = filelist[ii-1];
  3639. userschematmpfile = slapi_ch_smprintf("%s.tmp", userschemafile);
  3640. }
  3641. if(rc)
  3642. {
  3643. *local_pschemadse = dse_new_with_filelist(userschemafile,
  3644. userschematmpfile, NULL, NULL, myschemadir, filelist);
  3645. }
  3646. PR_ASSERT(*local_pschemadse);
  3647. if ((rc = (*local_pschemadse != NULL)) != 0)
  3648. {
  3649. /* pass schema_flags as arguments */
  3650. dse_register_callback(*local_pschemadse,
  3651. DSE_OPERATION_READ, DSE_FLAG_PREOP, &schema,
  3652. LDAP_SCOPE_BASE, NULL,
  3653. load_schema_dse, (void *)&schema_flags);
  3654. }
  3655. slapi_ch_free_string(&userschematmpfile);
  3656. if (NULL == schemadir)
  3657. slapi_ch_free_string(&myschemadir); /* allocated in this function */
  3658. if(rc)
  3659. {
  3660. char errorbuf[SLAPI_DSE_RETURNTEXT_SIZE] = {0};
  3661. int dont_write = 1;
  3662. int merge = 1;
  3663. int dont_dup_check = 1;
  3664. Slapi_PBlock pb;
  3665. memset(&pb, 0, sizeof(pb));
  3666. /* don't write out the file when reading */
  3667. slapi_pblock_set(&pb, SLAPI_DSE_DONT_WRITE_WHEN_ADDING, (void*)&dont_write);
  3668. /* duplicate entries are allowed */
  3669. slapi_pblock_set(&pb, SLAPI_DSE_MERGE_WHEN_ADDING, (void*)&merge);
  3670. /* use the non duplicate checking str2entry */
  3671. slapi_pblock_set(&pb, SLAPI_DSE_DONT_CHECK_DUPS, (void*)&dont_dup_check);
  3672. /* borrow the task flag space */
  3673. slapi_pblock_set(&pb, SLAPI_SCHEMA_FLAGS, (void*)&schema_flags);
  3674. /* add the objectclass attribute so we can do some basic schema
  3675. checking during initialization; this will be overridden when
  3676. its "real" definition is read from the schema conf files */
  3677. if (schema_flags & DSE_SCHEMA_NO_LOAD)
  3678. {
  3679. struct asyntaxinfo *tmpasip = NULL;
  3680. rc = read_at_ldif("attributeTypes: ( 2.5.4.0 NAME 'objectClass' "
  3681. "DESC 'Standard schema for LDAP' SYNTAX "
  3682. "1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2252' )",
  3683. &tmpasip, errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
  3684. DSE_SCHEMA_NO_GLOCK|schema_flags, 0, 0, 0);
  3685. attr_syntax_free( tmpasip ); /* trash it */
  3686. }
  3687. else
  3688. {
  3689. rc = read_at_ldif("attributeTypes: ( 2.5.4.0 NAME 'objectClass' "
  3690. "DESC 'Standard schema for LDAP' SYNTAX "
  3691. "1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2252' )",
  3692. NULL, errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
  3693. DSE_SCHEMA_NO_GLOCK|schema_flags, 0, 0, 0);
  3694. }
  3695. if (rc)
  3696. {
  3697. slapi_log_error(SLAPI_LOG_FATAL, "schema", "Could not add"
  3698. " attribute type \"objectClass\" to the schema: %s\n",
  3699. errorbuf);
  3700. }
  3701. rc = dse_read_file(*local_pschemadse, &pb);
  3702. }
  3703. if (rc && !(schema_flags & DSE_SCHEMA_NO_BACKEND))
  3704. {
  3705. /* make sure the schema is normalized */
  3706. if (schema_flags & DSE_SCHEMA_LOCKED)
  3707. normalize_oc_nolock();
  3708. else
  3709. normalize_oc();
  3710. /* register callbacks */
  3711. dse_register_callback(*local_pschemadse, SLAPI_OPERATION_SEARCH,
  3712. DSE_FLAG_PREOP,&schema, LDAP_SCOPE_BASE,
  3713. NULL, read_schema_dse, NULL);
  3714. dse_register_callback(*local_pschemadse, SLAPI_OPERATION_MODIFY,
  3715. DSE_FLAG_PREOP,&schema, LDAP_SCOPE_BASE,
  3716. NULL, modify_schema_dse, NULL);
  3717. dse_register_callback(*local_pschemadse, SLAPI_OPERATION_DELETE,
  3718. DSE_FLAG_PREOP, &schema, LDAP_SCOPE_BASE,
  3719. NULL,dont_allow_that,NULL);
  3720. dse_register_callback(*local_pschemadse, DSE_OPERATION_WRITE,
  3721. DSE_FLAG_PREOP, &schema, LDAP_SCOPE_BASE,
  3722. NULL, refresh_user_defined_schema, NULL);
  3723. if (rc) {
  3724. if (NULL == be) { /* be is not given. select it */
  3725. be = slapi_be_select_by_instance_name( DSE_SCHEMA );
  3726. }
  3727. if (NULL == be) { /* first time */
  3728. /* add as a backend */
  3729. be = be_new_internal(*local_pschemadse, "DSE", DSE_SCHEMA);
  3730. be_addsuffix(be, &schema);
  3731. } else { /* schema file reload */
  3732. struct slapdplugin *backend_plugin = NULL;
  3733. be_replace_dse_internal(be, *local_pschemadse);
  3734. /* ldbm has some internal attributes to be added */
  3735. backend_plugin = plugin_get_by_name("ldbm database");
  3736. if (backend_plugin) {
  3737. if (backend_plugin->plg_add_schema) {
  3738. (backend_plugin->plg_add_schema)( NULL );
  3739. } else {
  3740. slapi_log_error( SLAPI_LOG_FATAL, "init_schema_dse",
  3741. "backend has not set internal schema\n" );
  3742. }
  3743. }
  3744. }
  3745. }
  3746. }
  3747. slapi_sdn_done(&schema);
  3748. return rc;
  3749. }
  3750. int
  3751. init_schema_dse(const char *configdir)
  3752. {
  3753. char *schemadir = config_get_schemadir();
  3754. int rc = 0;
  3755. if (NULL == schemadir)
  3756. {
  3757. schemadir = slapi_ch_smprintf("%s/%s", configdir, SCHEMA_SUBDIR_NAME);
  3758. }
  3759. rc = init_schema_dse_ext(schemadir, NULL, &pschemadse, 0);
  3760. slapi_ch_free_string(&schemadir);
  3761. return rc;
  3762. }
  3763. /*
  3764. * Look for `keyword' within `*inputp' and return the flag_value if found
  3765. * (zero if returned if not found).
  3766. *
  3767. * If the keyword is found, `*inputp' is set to point just beyond the end of
  3768. * the keyword. If the keyword is not found, `*inputp' is not changed.
  3769. *
  3770. * The `strstr_fn' function pointer is used to search for `keyword', e.g., it
  3771. * could be PL_strcasestr().
  3772. *
  3773. * The string passed in `keyword' MUST include a trailing space, e.g.,
  3774. *
  3775. * flag |= get_flag_keyword( " COLLECTIVE ", SLAPI_ATTR_FLAG_COLLECTIVE,
  3776. * &input, PL_strcasestr );
  3777. *
  3778. */
  3779. static int
  3780. get_flag_keyword( const char *keyword, int flag_value, const char **inputp,
  3781. schema_strstr_fn_t strstr_fn )
  3782. {
  3783. const char *kw;
  3784. PR_ASSERT( NULL != inputp );
  3785. PR_ASSERT( NULL != *inputp );
  3786. PR_ASSERT( ' ' == keyword[ strlen( keyword ) - 1 ] );
  3787. if ( NULL == strstr_fn ) {
  3788. strstr_fn = PL_strcasestr;
  3789. }
  3790. kw = (*strstr_fn)( *inputp, keyword );
  3791. if ( NULL == kw ) {
  3792. flag_value = 0; /* not found -- return no value */
  3793. } else {
  3794. *inputp = kw + strlen( keyword ) - 1; /* advance input */
  3795. }
  3796. return flag_value;
  3797. }
  3798. /*
  3799. * Look for `tag' within `*inputp' and return the OID string following `tag'.
  3800. * If the OID has single quotes around it they are removed (they are allowed
  3801. * for compatibility with DS 3.x and 4.x).
  3802. *
  3803. * If the tag is found, `*inputp' is set to point just beyond the end of
  3804. * the OID that was extracted and returned. If the tag is not found,
  3805. * `*inputp' is not changed.
  3806. *
  3807. * The `strstr_fn' function pointer is used to search for `tag', e.g., it
  3808. * could be PL_strcasestr().
  3809. *
  3810. * The string passed in `tag' SHOULD generally include a trailing space, e.g.,
  3811. *
  3812. * pSuperior = get_tagged_oid( "SUP ", &input, PL_strcasestr );
  3813. *
  3814. * The exception to this is when the tag contains '(' as a trailing character.
  3815. * This is used to process lists of oids, such as the following:
  3816. *
  3817. * SUP (inetOrgPerson $ testUser)
  3818. *
  3819. * A malloc'd string is returned if `tag; is found and NULL if not.
  3820. */
  3821. static char *
  3822. get_tagged_oid( const char *tag, const char **inputp,
  3823. schema_strstr_fn_t strstr_fn )
  3824. {
  3825. const char *startp, *endp;
  3826. char *oid;
  3827. PR_ASSERT( NULL != inputp );
  3828. PR_ASSERT( NULL != *inputp );
  3829. PR_ASSERT( NULL != tag );
  3830. PR_ASSERT( '\0' != tag[ 0 ] );
  3831. if('(' !=tag[0])
  3832. PR_ASSERT((' ' == tag[ strlen( tag ) - 1 ]) || ('(' == tag[ strlen( tag ) - 1 ]));
  3833. if ( NULL == strstr_fn ) {
  3834. strstr_fn = PL_strcasestr;
  3835. }
  3836. oid = NULL;
  3837. if ( NULL != ( startp = (*strstr_fn)( *inputp, tag ))) {
  3838. startp += strlen( tag );
  3839. /* skip past any extra white space */
  3840. if ( NULL == ( startp = skipWS( startp ))) {
  3841. return( NULL );
  3842. }
  3843. /* skip past the leading single quote, if present */
  3844. if ( *startp == '\'' ) {
  3845. ++startp;
  3846. /* skip past any extra white space */
  3847. startp = skipWS( startp );
  3848. }
  3849. /* locate the end of the OID */
  3850. if ((NULL != ( endp = strchr( startp, ' '))) ||
  3851. (NULL != (endp = strchr( startp, ')'))) ) {
  3852. if ( '\'' == *(endp-1) && endp > startp ) {
  3853. --endp; /* ignore trailing quote */
  3854. }
  3855. } else {
  3856. endp = startp + strlen( startp ); /* remainder of input */
  3857. }
  3858. oid = slapi_ch_malloc( endp - startp + 1 );
  3859. memcpy( oid, startp, endp - startp );
  3860. oid[ endp - startp ] = '\0';
  3861. *inputp = endp;
  3862. }
  3863. return( oid );
  3864. }
  3865. /*
  3866. * sprintf to `outp' the contents of `tag' followed by `oid' followed by a
  3867. * trailing space. If enquote is non-zero, single quotes are included
  3868. * around the `oid' string. If `suffix' is not NULL, it is output directly
  3869. * after the `oid' (before the trailing space).
  3870. * Note that `tag' should typically include a trailing space, e.g.,
  3871. *
  3872. * outp += put_tagged_oid( outp, "SUP ", "1.2.3.4", NULL, enquote_oids );
  3873. *
  3874. * Returns the number of bytes copied to `outp' or 0 if `oid' is NULL.
  3875. */
  3876. static int
  3877. put_tagged_oid( char *outp, const char *tag, const char *oid,
  3878. const char *suffix, int enquote )
  3879. {
  3880. int count = 0;
  3881. if ( NULL == suffix ) {
  3882. suffix = "";
  3883. }
  3884. if ( NULL != oid ) {
  3885. if ( enquote ) {
  3886. count = sprintf( outp, "%s'%s%s' ", tag, oid, suffix );
  3887. } else {
  3888. count = sprintf( outp, "%s%s%s ", tag, oid, suffix );
  3889. }
  3890. }
  3891. return( count );
  3892. }
  3893. /*
  3894. * Add to `buf' a string of the form:
  3895. *
  3896. * prefix SPACE ( oid1 $ oid2 ... ) SPACE
  3897. * OR
  3898. * prefix SPACE oid SPACE
  3899. *
  3900. * The part after <prefix> matches the `oids' definition
  3901. * from RFC 2252 section 4.1.
  3902. *
  3903. * If oids is NULL or an empty array, `buf' is not touched.
  3904. */
  3905. static void
  3906. strcat_oids( char *buf, char *prefix, char **oids, int schema_ds4x_compat )
  3907. {
  3908. char *p;
  3909. int i;
  3910. if ( NULL != oids && NULL != oids[0] ) {
  3911. p = buf + strlen(buf); /* skip past existing content */
  3912. if ( NULL == oids[1] && !schema_ds4x_compat ) {
  3913. sprintf( p, "%s %s ", prefix, oids[0] ); /* just one oid */
  3914. } else {
  3915. sprintf( p, "%s ( ", prefix ); /* oidlist */
  3916. for ( i = 0; oids[i] != NULL; ++i ) {
  3917. if ( i > 0 ) {
  3918. strcat( p, " $ " );
  3919. }
  3920. strcat( p, oids[i] );
  3921. }
  3922. strcat( p, " ) " );
  3923. }
  3924. }
  3925. }
  3926. /*
  3927. * Add to `buf' a string of the form:
  3928. *
  3929. * prefix SPACE ( 's1' 's2' ... ) SPACE
  3930. * OR
  3931. * prefix SPACE 's1' SPACE
  3932. *
  3933. * The part after <prefix> matches the qdescs definition
  3934. * from RFC 2252 section 4.1.
  3935. *
  3936. * A count of the number of bytes added to buf or needed is returned.
  3937. *
  3938. * If buf is NULL, no copying is done but the number of bytes needed
  3939. * is calculated and returned. This is useful if you need to allocate
  3940. * space before calling this function will a buffer.
  3941. *
  3942. * If qdlist is NULL or an empty array, `buf' is not touched and zero
  3943. * is returned.
  3944. */
  3945. static size_t
  3946. strcat_qdlist( char *buf, char *prefix, char **qdlist )
  3947. {
  3948. int i;
  3949. char *start, *p;
  3950. size_t len = 0;
  3951. if ( NULL != qdlist && NULL != qdlist[0] ) {
  3952. if ( NULL == buf ) { /* calculate length only */
  3953. len += strlen( prefix );
  3954. if ( NULL != qdlist[1] ) {
  3955. len += 4; /* surrounding spaces and '(' and ')' */
  3956. }
  3957. for ( i = 0; NULL != qdlist[i]; ++i ) {
  3958. len += 3; /* leading space and quote marks */
  3959. len += strlen(qdlist[i]);
  3960. }
  3961. ++len; /* trailing space */
  3962. } else {
  3963. p = start = buf + strlen(buf); /* skip past existing content */
  3964. if ( NULL == qdlist[1] ) { /* just one string */
  3965. p += sprintf( p, "%s '%s' ", prefix, qdlist[0] );
  3966. } else { /* a list of strings */
  3967. p += sprintf( p, "%s (", prefix );
  3968. for ( i = 0; qdlist[i] != NULL; ++i ) {
  3969. p += sprintf( p, " '%s'", qdlist[i] );
  3970. }
  3971. *p++ = ' ';
  3972. *p++ = ')';
  3973. *p++ = ' ';
  3974. *p = '\0';
  3975. }
  3976. len = p - start;
  3977. }
  3978. }
  3979. return( len );
  3980. }
  3981. /*
  3982. * Just like strlen() except that 0 is returned if `s' is NULL.
  3983. */
  3984. static size_t
  3985. strlen_null_ok(const char *s)
  3986. {
  3987. if ( NULL == s ) {
  3988. return( 0 );
  3989. }
  3990. return( strlen( s ));
  3991. }
  3992. /*
  3993. * Like strcpy() except a count of the number of bytes copied is returned.
  3994. */
  3995. static int
  3996. strcpy_count( char *dst, const char *src )
  3997. {
  3998. char *p;
  3999. p = dst;
  4000. while ( *src != '\0' ) {
  4001. *p++ = *src++;
  4002. }
  4003. *p = '\0';
  4004. return( p - dst );
  4005. }
  4006. /*
  4007. * Look for an X-ORIGIN list in `schema_value' and return a
  4008. * qdstrings array (or NULL if no list is present). *num_originsp is
  4009. * set to a count of the number of origin strings returned.
  4010. *
  4011. * If no X-ORIGIN list is found and `default_list' is non-NULL, a copy
  4012. * of default list is returned.
  4013. */
  4014. static char **
  4015. parse_origin_list( const char *schema_value, int *num_originsp,
  4016. char **default_list )
  4017. {
  4018. char *start, *end, *origin_tmp;
  4019. char **origins = NULL;
  4020. if (( start = PL_strstr ( schema_value, "X-ORIGIN ")) != NULL ) {
  4021. start += 9;
  4022. origin_tmp = slapi_ch_strdup( start );
  4023. if ( *start == '(' ) {
  4024. end = strchr( origin_tmp, ')' );
  4025. } else {
  4026. end = strchr( origin_tmp + 1, '\'' );
  4027. }
  4028. if (end) {
  4029. *(end+1) = 0;
  4030. }
  4031. origins = parse_qdstrings( origin_tmp, num_originsp );
  4032. slapi_ch_free( (void **)&origin_tmp );
  4033. } else {
  4034. origins = NULL;
  4035. *num_originsp = 0;
  4036. }
  4037. if ( NULL == origins && NULL != default_list ) {
  4038. int i;
  4039. for ( i = 0; default_list[i] != NULL; ++i ) {
  4040. ;
  4041. }
  4042. *num_originsp = i;
  4043. origins = (char **)slapi_ch_malloc( (i+1) * sizeof(char *));
  4044. for ( i = 0; default_list[i] != NULL; ++i ) {
  4045. origins[i] = slapi_ch_strdup( default_list[i] );
  4046. }
  4047. origins[i] = NULL;
  4048. }
  4049. if ( origins == NULL || origins[0] == NULL ) {
  4050. LDAPDebug( LDAP_DEBUG_ANY, "no origin (%s)\n", schema_value, 0, 0 );
  4051. }
  4052. return origins;
  4053. }
  4054. /*
  4055. * Determine based on origin whether a schema element is standard or
  4056. * user-defined. Algorithm: perform a case insensitive search for
  4057. * "user defined". If found, return 1 (user defined); if not, return 0.
  4058. */
  4059. static int
  4060. element_is_user_defined( char * const *origins )
  4061. {
  4062. int i;
  4063. if ( origins != NULL ) {
  4064. for ( i = 0; origins[i] != NULL; ++i ) {
  4065. if ( 0 == strcasecmp( schema_user_defined_origin[0], origins[i] )) {
  4066. return 1;
  4067. }
  4068. }
  4069. }
  4070. return 0;
  4071. }
  4072. /*
  4073. * Return PR_TRUE if the attribute type named 'type' is one of those that
  4074. * we handle directly in this file (in the scheme DSE callbacks).
  4075. * Other types are handled by the generic DSE code in dse.c.
  4076. */
  4077. /* subschema DSE attribute types we handle within the DSE callback */
  4078. static char *schema_interesting_attr_types[] = {
  4079. "dITStructureRules",
  4080. "nameForms",
  4081. "dITContentRules",
  4082. "objectClasses",
  4083. "attributeTypes",
  4084. "matchingRules",
  4085. "matchingRuleUse",
  4086. "ldapSyntaxes",
  4087. "nsschemacsn",
  4088. NULL
  4089. };
  4090. static PRBool
  4091. schema_type_is_interesting( const char *type )
  4092. {
  4093. int i;
  4094. for ( i = 0; schema_interesting_attr_types[i] != NULL; ++i ) {
  4095. if ( 0 == strcasecmp( type, schema_interesting_attr_types[i] )) {
  4096. return PR_TRUE;
  4097. }
  4098. }
  4099. return PR_FALSE;
  4100. }
  4101. static void
  4102. schema_create_errormsg(
  4103. char *errorbuf,
  4104. size_t errorbufsize,
  4105. const char *prefix,
  4106. const char *name,
  4107. const char *fmt,
  4108. ...
  4109. )
  4110. {
  4111. if ( NULL != errorbuf ) {
  4112. va_list ap;
  4113. int rc = 0;
  4114. va_start( ap, fmt );
  4115. if ( NULL != name ) {
  4116. rc = PR_snprintf( errorbuf, errorbufsize, prefix, name );
  4117. }
  4118. /* ok to cast here because rc is positive */
  4119. if ( (rc >= 0) && ((size_t)rc < errorbufsize) ) {
  4120. (void)PR_vsnprintf( errorbuf + rc, errorbufsize - rc, fmt, ap );
  4121. }
  4122. va_end( ap );
  4123. }
  4124. }
  4125. /*
  4126. * va_locate_oc_val finds an objectclass within the array of values in va.
  4127. * First oc_name is used, falling back to oc_oid. oc_oid can be NULL.
  4128. * oc_name and oc_oid should be official names (no trailing spaces). But
  4129. * trailing spaces within the va are ignored if appropriate.
  4130. *
  4131. * Returns >=0 if found (index into va) and -1 if not found.
  4132. */
  4133. static int
  4134. va_locate_oc_val( Slapi_Value **va, const char *oc_name, const char *oc_oid )
  4135. {
  4136. int i;
  4137. const char *strval;
  4138. if ( NULL == va || oc_name == NULL ) { /* nothing to look for */
  4139. return -1;
  4140. }
  4141. if ( !schema_ignore_trailing_spaces ) {
  4142. for ( i = 0; va[i] != NULL; i++ ) {
  4143. strval = slapi_value_get_string(va[i]);
  4144. if ( NULL != strval ) {
  4145. if ( 0 == strcasecmp(strval, oc_name)) {
  4146. return i;
  4147. }
  4148. if ( NULL != oc_oid
  4149. && 0 == strcasecmp( strval, oc_oid )) {
  4150. return i;
  4151. }
  4152. }
  4153. }
  4154. } else {
  4155. /*
  4156. * Ignore trailing spaces when comparing object class names.
  4157. */
  4158. size_t len;
  4159. const char *p;
  4160. for ( i = 0; va[i] != NULL; i++ ) {
  4161. strval = slapi_value_get_string(va[i]);
  4162. if ( NULL != strval ) {
  4163. for ( p = strval, len = 0; (*p != '\0') && (*p != ' ');
  4164. p++, len++ ) {
  4165. ; /* NULL */
  4166. }
  4167. if ( 0 == strncasecmp(oc_name, strval, len )
  4168. && ( len == strlen(oc_name))) {
  4169. return i;
  4170. }
  4171. if ( NULL != oc_oid
  4172. && ( 0 == strncasecmp( oc_oid, strval, len ))
  4173. && ( len == strlen(oc_oid))) {
  4174. return i;
  4175. }
  4176. }
  4177. }
  4178. }
  4179. return -1; /* not found */
  4180. }
  4181. /*
  4182. * va_expand_one_oc is used to add missing superclass values to the
  4183. * objectclass attribute when an entry is added or modified.
  4184. *
  4185. * missing values are always added to the end of the 'vap' array.
  4186. *
  4187. * Note: calls to this function MUST be bracketed by lock()/unlock(), i.e.,
  4188. *
  4189. * oc_lock_read();
  4190. * va_expand_one_oc( b, o );
  4191. * oc_unlock();
  4192. */
  4193. static void
  4194. va_expand_one_oc( const char *dn, Slapi_Value ***vap, const char *ocs )
  4195. {
  4196. struct objclass *this_oc, *sup_oc;
  4197. int p,i;
  4198. Slapi_Value **newva;
  4199. char ebuf[BUFSIZ];
  4200. this_oc = oc_find_nolock( ocs );
  4201. if ( this_oc == NULL ) {
  4202. return; /* skip unknown object classes */
  4203. }
  4204. if ( this_oc->oc_superior == NULL ) {
  4205. return; /* no superior */
  4206. }
  4207. sup_oc = oc_find_nolock( this_oc->oc_superior );
  4208. if ( sup_oc == NULL ) {
  4209. return; /* superior is unknown -- ignore */
  4210. }
  4211. p = va_locate_oc_val( *vap, sup_oc->oc_name, sup_oc->oc_oid );
  4212. if ( p != -1 ) {
  4213. return; /* value already present -- done! */
  4214. }
  4215. /* parent was not found. add to the end */
  4216. for ( i = 0; (*vap)[i] != NULL; i++ ) {
  4217. ;
  4218. }
  4219. /* prevent loops: stop if more than 1000 OC values are present */
  4220. if ( i > 1000 ) {
  4221. return;
  4222. }
  4223. newva = (Slapi_Value **)slapi_ch_realloc( (char *)*vap,
  4224. ( i + 2 )*sizeof(Slapi_Value **));
  4225. newva[i] = slapi_value_new_string(sup_oc->oc_name);
  4226. newva[i+1] = NULL;
  4227. *vap = newva;
  4228. LDAPDebug( LDAP_DEBUG_TRACE,
  4229. "Entry \"%s\": added missing objectClass value %s\n",
  4230. escape_string( dn, ebuf ), sup_oc->oc_name, 0 );
  4231. }
  4232. /*
  4233. * Expand the objectClass values in 'e' to take superior classes into account.
  4234. * All missing superior classes are added to the objectClass attribute, as
  4235. * is 'top' if it is missing.
  4236. */
  4237. void
  4238. slapi_schema_expand_objectclasses( Slapi_Entry *e )
  4239. {
  4240. Slapi_Attr *sa;
  4241. Slapi_Value **va;
  4242. const char *dn = slapi_entry_get_dn_const( e );
  4243. int i;
  4244. if ( 0 != slapi_entry_attr_find( e, SLAPI_ATTR_OBJECTCLASS, &sa )) {
  4245. return; /* no OC values -- nothing to do */
  4246. }
  4247. va = attr_get_present_values( sa );
  4248. if ( va == NULL || va[0] == NULL ) {
  4249. return; /* no OC values -- nothing to do */
  4250. }
  4251. oc_lock_read();
  4252. /*
  4253. * This loop relies on the fact that bv_expand_one_oc()
  4254. * always adds to the end
  4255. */
  4256. for ( i = 0; va[i] != NULL; ++i ) {
  4257. if ( NULL != slapi_value_get_string(va[i]) ) {
  4258. va_expand_one_oc( dn, &va, slapi_value_get_string(va[i]) );
  4259. }
  4260. }
  4261. /* top must always be present */
  4262. va_expand_one_oc( dn, &va, "top" );
  4263. /*
  4264. * Reset the present values in the set because we may have realloc'd it.
  4265. * Note that this is the counterpart to the attr_get_present_values()
  4266. * call we made above... nothing new has been allocated, but sa holds
  4267. * a pointer to the original (pre realloc) va.
  4268. */
  4269. sa->a_present_values.va = va;
  4270. oc_unlock();
  4271. }
  4272. void
  4273. schema_expand_objectclasses_nolock( Slapi_Entry *e )
  4274. {
  4275. Slapi_Attr *sa;
  4276. Slapi_Value **va;
  4277. const char *dn = slapi_entry_get_dn_const( e );
  4278. int i;
  4279. if ( 0 != slapi_entry_attr_find( e, SLAPI_ATTR_OBJECTCLASS, &sa )) {
  4280. return; /* no OC values -- nothing to do */
  4281. }
  4282. va = attr_get_present_values( sa );
  4283. if ( va == NULL || va[0] == NULL ) {
  4284. return; /* no OC values -- nothing to do */
  4285. }
  4286. /*
  4287. * This loop relies on the fact that bv_expand_one_oc()
  4288. * always adds to the end
  4289. */
  4290. for ( i = 0; va[i] != NULL; ++i ) {
  4291. if ( NULL != slapi_value_get_string(va[i]) ) {
  4292. va_expand_one_oc( dn, &va, slapi_value_get_string(va[i]) );
  4293. }
  4294. }
  4295. /* top must always be present */
  4296. va_expand_one_oc( dn, &va, "top" );
  4297. /*
  4298. * Reset the present values in the set because we may have realloc'd it.
  4299. * Note that this is the counterpart to the attr_get_present_values()
  4300. * call we made above... nothing new has been allocated, but sa holds
  4301. * a pointer to the original (pre realloc) va.
  4302. */
  4303. sa->a_present_values.va = va;
  4304. }
  4305. /* lock to protect both objectclass and schema_dse */
  4306. static void
  4307. reload_schemafile_lock()
  4308. {
  4309. oc_lock_write();
  4310. schema_dse_lock_write();
  4311. }
  4312. static void
  4313. reload_schemafile_unlock()
  4314. {
  4315. schema_dse_unlock();
  4316. oc_unlock();
  4317. }
  4318. /* API to validate the schema files */
  4319. int
  4320. slapi_validate_schema_files(char *schemadir)
  4321. {
  4322. struct dse *my_pschemadse = NULL;
  4323. int rc = init_schema_dse_ext(schemadir, NULL, &my_pschemadse,
  4324. DSE_SCHEMA_NO_LOAD | DSE_SCHEMA_NO_BACKEND);
  4325. if (rc) {
  4326. dse_destroy(my_pschemadse);
  4327. return LDAP_SUCCESS;
  4328. } else {
  4329. slapi_log_error( SLAPI_LOG_FATAL, "schema_reload",
  4330. "schema file validation failed\n" );
  4331. return LDAP_OBJECT_CLASS_VIOLATION;
  4332. }
  4333. }
  4334. /*
  4335. * API to reload the schema files.
  4336. * Rule: this function is called when slapi_validate_schema_files is passed.
  4337. * Schema checking is skipped in this function.
  4338. */
  4339. int
  4340. slapi_reload_schema_files(char *schemadir)
  4341. {
  4342. int rc = LDAP_SUCCESS;
  4343. struct dse *my_pschemadse = NULL;
  4344. /* get be to lock */
  4345. Slapi_Backend *be = slapi_be_select_by_instance_name( DSE_SCHEMA );
  4346. if (NULL == be)
  4347. {
  4348. slapi_log_error( SLAPI_LOG_FATAL, "schema_reload",
  4349. "schema file reload failed\n" );
  4350. return LDAP_LOCAL_ERROR;
  4351. }
  4352. slapi_be_Wlock(be); /* be lock must be outer of schemafile lock */
  4353. reload_schemafile_lock();
  4354. attr_syntax_delete_all();
  4355. oc_delete_all_nolock();
  4356. rc = init_schema_dse_ext(schemadir, be, &my_pschemadse,
  4357. DSE_SCHEMA_NO_CHECK | DSE_SCHEMA_LOCKED);
  4358. if (rc) {
  4359. dse_destroy(pschemadse);
  4360. pschemadse = my_pschemadse;
  4361. reload_schemafile_unlock();
  4362. slapi_be_Unlock(be);
  4363. return LDAP_SUCCESS;
  4364. } else {
  4365. reload_schemafile_unlock();
  4366. slapi_be_Unlock(be);
  4367. slapi_log_error( SLAPI_LOG_FATAL, "schema_reload",
  4368. "schema file reload failed\n" );
  4369. return LDAP_LOCAL_ERROR;
  4370. }
  4371. }
  4372. /*
  4373. * slapi_schema_list_objectclass_attributes:
  4374. * Return the list of attributes belonging to the objectclass
  4375. *
  4376. * The caller is responsible to free the returned list with charray_free.
  4377. * flags: one of them or both:
  4378. * SLAPI_OC_FLAG_REQUIRED
  4379. * SLAPI_OC_FLAG_ALLOWED
  4380. */
  4381. char **
  4382. slapi_schema_list_objectclass_attributes(const char *ocname_or_oid,
  4383. PRUint32 flags)
  4384. {
  4385. struct objclass *oc = NULL;
  4386. char **attrs = NULL;
  4387. PRUint32 mask = SLAPI_OC_FLAG_REQUIRED | SLAPI_OC_FLAG_ALLOWED;
  4388. if (!flags) {
  4389. return attrs;
  4390. }
  4391. oc_lock_read();
  4392. oc = oc_find_nolock(ocname_or_oid);
  4393. if (oc) {
  4394. switch (flags & mask) {
  4395. case SLAPI_OC_FLAG_REQUIRED:
  4396. attrs = charray_dup(oc->oc_required);
  4397. break;
  4398. case SLAPI_OC_FLAG_ALLOWED:
  4399. attrs = charray_dup(oc->oc_allowed);
  4400. break;
  4401. case SLAPI_OC_FLAG_REQUIRED|SLAPI_OC_FLAG_ALLOWED:
  4402. attrs = charray_dup(oc->oc_required);
  4403. charray_merge(&attrs, oc->oc_allowed, 1/*copy_strs*/);
  4404. break;
  4405. default:
  4406. slapi_log_error( SLAPI_LOG_FATAL, "list objectclass attributes",
  4407. "flag 0x%x not supported\n", flags );
  4408. break;
  4409. }
  4410. }
  4411. oc_unlock();
  4412. return attrs;
  4413. }
  4414. /*
  4415. * slapi_schema_get_superior_name:
  4416. * Return the name of the superior objectclass
  4417. *
  4418. * The caller is responsible to free the returned name
  4419. */
  4420. char *
  4421. slapi_schema_get_superior_name(const char *ocname_or_oid)
  4422. {
  4423. struct objclass *oc = NULL;
  4424. char *superior = NULL;
  4425. oc_lock_read();
  4426. oc = oc_find_nolock(ocname_or_oid);
  4427. if (oc) {
  4428. superior = slapi_ch_strdup(oc->oc_superior);
  4429. }
  4430. oc_unlock();
  4431. return superior;
  4432. }