schema.c 264 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803
  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. #if defined(USE_OPENLDAP)
  51. #include <ldap_schema.h> /* openldap schema parser */
  52. #endif
  53. typedef struct sizedbuffer
  54. {
  55. char *buffer;
  56. size_t size;
  57. } sizedbuffer;
  58. typedef char *(*schema_strstr_fn_t)( const char *big, const char *little);
  59. /*
  60. * The schema_oc_kind_strings array is indexed by oc_kind values, i.e.,
  61. * OC_KIND_STRUCTURAL (0), OC_KIND_AUXILIARY (1), or OC_KIND_ABSTRACT (2).
  62. * The leading and trailing spaces are intentional.
  63. */
  64. #define SCHEMA_OC_KIND_COUNT 3
  65. static char *schema_oc_kind_strings_with_spaces[] = {
  66. " ABSTRACT ",
  67. " STRUCTURAL ",
  68. " AUXILIARY ",
  69. };
  70. /* constant strings (used in a few places) */
  71. static const char *schema_obsolete_with_spaces = " OBSOLETE ";
  72. static const char *schema_collective_with_spaces = " COLLECTIVE ";
  73. static const char *schema_nousermod_with_spaces = " NO-USER-MODIFICATION ";
  74. /* user defined origin array */
  75. static char *schema_user_defined_origin[] = {
  76. "user defined",
  77. NULL
  78. };
  79. /* The policies for the replication of the schema are
  80. * - base policy
  81. * - extended policies
  82. * Those policies are enforced when the server is acting as a supplier and
  83. * when it is acting as a consumer
  84. *
  85. * Base policy:
  86. * Supplier: before pushing the schema, the supplier checks that each objectclass/attribute of
  87. * the consumer schema is a subset of the objectclass/attribute of the supplier schema
  88. * Consumer: before accepting a schema (from replication), the consumer checks that
  89. * each objectclass/attribute of the consumer schema is a subset of the objectclass/attribute
  90. * of the supplier schema
  91. * Extended policies:
  92. * They are stored in repl_schema_policy_t and specifies an "action" to be taken
  93. * for specific objectclass/attribute.
  94. * Supplier: extended policies are stored in entry "cn=supplierUpdatePolicy,cn=replSchema,cn=config"
  95. * and uploaded in static variable: supplier_policy
  96. * Before pushing the schema, for each objectclass/attribute defined in supplier_policy:
  97. * if its "action" is REPL_SCHEMA_UPDATE_ACCEPT_VALUE, it is not checked that the
  98. * attribute/objectclass of the consumer is a subset of the attribute/objectclass
  99. * of the supplier schema.
  100. *
  101. * if its "action" is REPL_SCHEMA_UPDATE_REJECT_VALUE and the consumer schema contains
  102. * attribute/objectclass, then schema is not pushed
  103. *
  104. * Consumer: extended policies are stored in entry "cn=consumerUpdatePolicy,cn=replSchema,cn=config"
  105. * and uploaded in static variable: consumer_policy
  106. * before accepting a schema (from replication), for each objectclass/attribute defined in
  107. * consumer_policy:
  108. * if its "action" is REPL_SCHEMA_UPDATE_ACCEPT_VALUE, it is not checked that the
  109. * attribute/objectclass of the consumer is a subset of the attribute/objectclass
  110. * of the supplier schema.
  111. *
  112. * if its "action" is REPL_SCHEMA_UPDATE_REJECT_VALUE and the consumer schema contains
  113. * attribute/objectclass, then schema is not accepted
  114. *
  115. */
  116. typedef struct schema_item {
  117. int action; /* REPL_SCHEMA_UPDATE_ACCEPT_VALUE or REPL_SCHEMA_UPDATE_REJECT_VALUE */
  118. char *name_or_oid;
  119. struct schema_item *next;
  120. } schema_item_t;
  121. typedef struct repl_schema_policy {
  122. schema_item_t *objectclasses;
  123. schema_item_t *attributes;
  124. } repl_schema_policy_t;
  125. struct schema_mods_indexes {
  126. int index;
  127. char *new_value;
  128. char *old_value;
  129. struct schema_mods_indexes *next;
  130. };
  131. /*
  132. * pschemadse is based on the general implementation in dse
  133. */
  134. static struct dse *pschemadse= NULL;
  135. static void oc_add_nolock(struct objclass *newoc);
  136. static int oc_delete_nolock (char *ocname);
  137. static int oc_replace_nolock(const char *ocname, struct objclass *newoc);
  138. static int oc_check_required(Slapi_PBlock *, Slapi_Entry *,struct objclass *);
  139. static int oc_check_allowed_sv(Slapi_PBlock *, Slapi_Entry *e, const char *type, struct objclass **oclist );
  140. static int schema_delete_objectclasses ( Slapi_Entry *entryBefore,
  141. LDAPMod *mod, char *errorbuf, size_t errorbufsize,
  142. int schema_ds4x_compat, int is_internal_operation);
  143. static int schema_delete_attributes ( Slapi_Entry *entryBefore,
  144. LDAPMod *mod, char *errorbuf, size_t errorbufsize, int is_internal_operation);
  145. static int schema_add_attribute ( Slapi_PBlock *pb, LDAPMod *mod,
  146. char *errorbuf, size_t errorbufsize, int schema_ds4x_compat );
  147. static int schema_add_objectclass ( Slapi_PBlock *pb, LDAPMod *mod,
  148. char *errorbuf, size_t errorbufsize, int schema_ds4x_compat );
  149. static int schema_replace_attributes ( Slapi_PBlock *pb, LDAPMod *mod,
  150. char *errorbuf, size_t errorbufsize );
  151. static int schema_replace_objectclasses ( Slapi_PBlock *pb, LDAPMod *mod,
  152. char *errorbuf, size_t errorbufsize );
  153. static int schema_check_name(char *name, PRBool isAttribute, char *errorbuf,
  154. size_t errorbufsize );
  155. static int schema_check_oid(const char *name, const char *oid,
  156. PRBool isAttribute, char *errorbuf, size_t errorbufsize);
  157. static int isExtensibleObjectclass(const char *objectclass);
  158. static int strip_oc_options ( struct objclass *poc );
  159. static char *stripOption (char *attr);
  160. static int schema_extension_cmp(schemaext *e1, schemaext *e2);
  161. static int put_tagged_oid( char *outp, const char *tag, const char *oid,
  162. const char *suffix, int enquote );
  163. static void strcat_oids( char *buf, char *prefix, char **oids,
  164. int schema_ds4x_compat );
  165. static size_t strcat_extensions( char *buf, schemaext *extension );
  166. static size_t strlen_null_ok(const char *s);
  167. static int strcpy_count( char *dst, const char *src );
  168. static int refresh_user_defined_schema(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg);
  169. static int schema_check_oc_attrs ( struct objclass *poc, char *errorbuf,
  170. size_t errorbufsize, int stripOptions );
  171. static struct objclass *oc_find_nolock( const char *ocname_or_oid, struct objclass *oc_private, PRBool use_private );
  172. static struct objclass *oc_find_oid_nolock( const char *ocoid );
  173. static void oc_free( struct objclass **ocp );
  174. static PRBool oc_equal( struct objclass *oc1, struct objclass *oc2 );
  175. static PRBool attr_syntax_equal( struct asyntaxinfo *asi1,
  176. struct asyntaxinfo *asi2 );
  177. static int schema_strcmp( const char *s1, const char *s2 );
  178. static int schema_strcmp_array( char **sa1, char **sa2,
  179. const char *ignorestr );
  180. static PRBool schema_type_is_interesting( const char *type );
  181. static void schema_create_errormsg( char *errorbuf, size_t errorbufsize,
  182. const char *prefix, const char *name, const char *fmt, ... )
  183. #ifdef __GNUC__
  184. __attribute__ ((format (printf, 5, 6)));
  185. #else
  186. ;
  187. #endif
  188. static PRBool check_replicated_schema(LDAPMod **mods, char *replica_role, char **attr_name);
  189. static void modify_schema_get_new_definitions(Slapi_PBlock *pb, LDAPMod **mods, struct schema_mods_indexes **at_list, struct schema_mods_indexes **oc_list);
  190. static void modify_schema_apply_new_definitions(char *attr_name, struct schema_mods_indexes *list);
  191. static void modify_schema_free_new_definitions(struct schema_mods_indexes *def_list);
  192. static int schema_oc_compare(struct objclass *oc_1, struct objclass *oc_2, const char *description);
  193. static int schema_at_compare(struct asyntaxinfo *at_1, struct asyntaxinfo *at_2, char *message, int debug_logging);
  194. static int schema_at_superset_check(struct asyntaxinfo *at_list1, struct asyntaxinfo *at_list2, char *message, int replica_role);
  195. static int schema_at_superset_check_syntax_oids(char *oid1, char *oid2);
  196. static int schema_at_superset_check_mr(struct asyntaxinfo *a1, struct asyntaxinfo *a2, char *info);
  197. static int parse_at_str(const char *input, struct asyntaxinfo **asipp, char *errorbuf, size_t errorbufsize,
  198. PRUint32 schema_flags, int is_user_defined, int schema_ds4x_compat, int is_remote);
  199. static int extension_is_user_defined( schemaext *extensions );
  200. static size_t strcat_qdlist( char *buf, char *prefix, char **qdlist );
  201. #if defined (USE_OPENLDAP)
  202. /*
  203. * openldap
  204. */
  205. static int parse_attr_str(const char *input, struct asyntaxinfo **asipp, char *errorbuf, size_t errorbufsize,
  206. PRUint32 schema_flags, int is_user_defined, int schema_ds4x_compat, int is_remote);
  207. static int parse_objclass_str(const char *input, struct objclass **oc, char *errorbuf, size_t errorbufsize,
  208. PRUint32 schema_flags, int is_user_defined, int schema_ds4x_compat, struct objclass* private_schema );
  209. #else
  210. /*
  211. * mozldap
  212. */
  213. static char **parse_qdescrs(const char *s, int *n);
  214. static char **parse_qdstrings(const char *s, int *n);
  215. static char **parse_qdlist(const char *s, int *n, int strip_options);
  216. static void free_qdlist(char **vals, int n);
  217. static int read_at_ldif(const char *input, struct asyntaxinfo **asipp,
  218. char *errorbuf, size_t errorbufsize, PRUint32 flags,
  219. int is_user_defined, int schema_ds4x_compat, int is_remote);
  220. static int read_oc_ldif ( const char *input, struct objclass **oc,
  221. char *errorbuf, size_t errorbufsize, PRUint32 flags, int is_user_defined,
  222. int schema_ds4x_compat );
  223. static int get_flag_keyword( const char *keyword, int flag_value,
  224. const char **inputp, schema_strstr_fn_t strstr_fn );
  225. static char *get_tagged_oid( const char *tag, const char **inputp,
  226. schema_strstr_fn_t strstr_fn );
  227. static char **read_dollar_values ( char *vals);
  228. static schemaext *parse_extensions( const char *schema_value, char **default_list );
  229. #endif
  230. /*
  231. * Some utility functions for dealing with a dynamic buffer
  232. */
  233. static struct sizedbuffer *sizedbuffer_construct(size_t size);
  234. static void sizedbuffer_destroy(struct sizedbuffer *p);
  235. static void sizedbuffer_allocate(struct sizedbuffer *p, size_t sizeneeded);
  236. /*
  237. * Constant strings that we pass to schema_create_errormsg().
  238. */
  239. static const char *schema_errprefix_oc = "object class %s: ";
  240. static const char *schema_errprefix_at = "attribute type %s: ";
  241. static const char *schema_errprefix_generic = "%s: ";
  242. /* Defined the policies for the replication of the schema */
  243. static repl_schema_policy_t supplier_policy = {0};
  244. static repl_schema_policy_t consumer_policy = {0};
  245. static Slapi_RWLock *schema_policy_lock = NULL;
  246. static int schema_check_policy(int replica_role, int schema_item, char *name, char *oid);
  247. static void schema_load_repl_policy(const char *dn, repl_schema_policy_t *replica);
  248. /*
  249. * A "cached" copy of the "ignore trailing spaces" config. setting.
  250. * This is set during initialization only (server restart required for
  251. * changes to take effect). We do things this way to avoid lock/unlock
  252. * mutex sequences inside performance critical code.
  253. */
  254. static int schema_ignore_trailing_spaces =
  255. SLAPD_DEFAULT_SCHEMA_IGNORE_TRAILING_SPACES;
  256. /* R/W lock used to serialize access to the schema DSE */
  257. static Slapi_RWLock *schema_dse_lock = NULL;
  258. /*
  259. * The schema_dse_mandatory_init_callonce structure is used by NSPR to ensure
  260. * that schema_dse_mandatory_init() is called at most once.
  261. */
  262. static PRCallOnceType schema_dse_mandatory_init_callonce = { 0, 0, 0 };
  263. static int parse_at_str(const char *input, struct asyntaxinfo **asipp, char *errorbuf, size_t errorbufsize,
  264. PRUint32 schema_flags, int is_user_defined, int schema_ds4x_compat, int is_remote)
  265. {
  266. #ifdef USE_OPENLDAP
  267. return parse_attr_str(input, asipp, errorbuf, errorbufsize, schema_flags, is_user_defined,schema_ds4x_compat,is_remote);
  268. #else
  269. return read_at_ldif(input, asipp, errorbuf, errorbufsize, schema_flags, is_user_defined,schema_ds4x_compat,is_remote);
  270. #endif
  271. }
  272. static int parse_oc_str(const char *input, struct objclass **oc, char *errorbuf,
  273. size_t errorbufsize, PRUint32 schema_flags, int is_user_defined,
  274. int schema_ds4x_compat, struct objclass* private_schema )
  275. {
  276. #ifdef USE_OPENLDAP
  277. return parse_objclass_str (input, oc, errorbuf, errorbufsize, schema_flags, is_user_defined, schema_ds4x_compat, private_schema );
  278. #else
  279. return read_oc_ldif (input, oc, errorbuf, errorbufsize, schema_flags, is_user_defined, schema_ds4x_compat );
  280. #endif
  281. }
  282. /* Essential initialization. Returns PRSuccess if successful */
  283. static PRStatus
  284. schema_dse_mandatory_init( void )
  285. {
  286. if ( NULL == ( schema_dse_lock = slapi_new_rwlock())) {
  287. slapi_log_error( SLAPI_LOG_FATAL, "schema_dse_mandatory_init",
  288. "slapi_new_rwlock() for schema DSE lock failed\n" );
  289. return PR_FAILURE;
  290. }
  291. schema_ignore_trailing_spaces = config_get_schema_ignore_trailing_spaces();
  292. return PR_SUCCESS;
  293. }
  294. void
  295. schema_destroy_dse_lock()
  296. {
  297. if(schema_dse_lock){
  298. slapi_destroy_rwlock(schema_dse_lock);
  299. schema_dse_lock = NULL;
  300. }
  301. }
  302. void
  303. slapi_schema_get_repl_entries(char **repl_schema_top, char ** repl_schema_supplier, char **repl_schema_consumer, char **default_supplier_policy, char **default_consumer_policy)
  304. {
  305. *repl_schema_top = ENTRY_REPL_SCHEMA_TOP;
  306. *repl_schema_supplier = ENTRY_REPL_SCHEMA_SUPPLIER;
  307. *repl_schema_consumer = ENTRY_REPL_SCHEMA_CONSUMER;
  308. *default_supplier_policy = DEFAULT_SUPPLIER_POLICY;
  309. *default_consumer_policy = DEFAULT_CONSUMER_POLICY;
  310. }
  311. /* It gets the attributes (see attrName)values in the entry, and add
  312. * the policies in the provided list
  313. *
  314. * Entry: Slapi_entry with DN being ENTRY_REPL_SCHEMA_SUPPLIER or ENTRY_REPL_SCHEMA_CONSUMER
  315. * attrName: name defining the policy object (objectclass/attribute) and the action
  316. * ATTR_SCHEMA_UPDATE_OBJECTCLASS_ACCEPT
  317. * ATTR_SCHEMA_UPDATE_OBJECTCLASS_REJECT
  318. * ATTR_SCHEMA_UPDATE_ATTRIBUTE_ACCEPT
  319. * ATTR_SCHEMA_UPDATE_ATTRIBUTE_REJECT
  320. * *list: is the list of schema_item_t containing the policies (it can be list of objectclasses or attributes)
  321. *
  322. */
  323. static
  324. void schema_policy_add_action(Slapi_Entry *entry, char *attrName, schema_item_t **list)
  325. {
  326. Slapi_Attr *attr = NULL;
  327. schema_item_t *schema_item;
  328. char *value;
  329. int action;
  330. /* Retrieve the expected action from the attribute name */
  331. if ((strcasecmp(attrName, ATTR_SCHEMA_UPDATE_OBJECTCLASS_ACCEPT) == 0) ||
  332. (strcasecmp(attrName, ATTR_SCHEMA_UPDATE_ATTRIBUTE_ACCEPT) == 0)) {
  333. action = REPL_SCHEMA_UPDATE_ACCEPT_VALUE;
  334. } else {
  335. action = REPL_SCHEMA_UPDATE_REJECT_VALUE;
  336. }
  337. /* Retrieve the given attribute from the entry */
  338. slapi_entry_attr_find(entry, attrName, &attr);
  339. if (attr != NULL) {
  340. Slapi_Value *sval = NULL;
  341. const struct berval *attrVal = NULL;
  342. int k = slapi_attr_first_value(attr, &sval);
  343. /* For each value adds the policy in the list */
  344. while (k != -1) {
  345. attrVal = slapi_value_get_berval(sval);
  346. schema_item = (schema_item_t *) slapi_ch_calloc(1, sizeof(schema_item_t));
  347. /* Get the schema name_or_oid */
  348. value = (char *) slapi_ch_malloc(attrVal->bv_len + 1);
  349. memcpy(value, attrVal->bv_val, attrVal->bv_len);
  350. value[attrVal->bv_len] = '\0';
  351. schema_item->name_or_oid = value;
  352. /* Set the action on that item */
  353. schema_item->action = action;
  354. /* Add it on the head of the list */
  355. schema_item->next = *list;
  356. *list = schema_item;
  357. /* Get the next name_or_oid */
  358. k = slapi_attr_next_value(attr, k, &sval);
  359. }
  360. }
  361. }
  362. /* Caller must hold schema_policy_lock in write */
  363. static void
  364. schema_load_repl_policy(const char *dn, repl_schema_policy_t *replica)
  365. {
  366. Slapi_DN sdn;
  367. Slapi_Entry *entry = NULL;
  368. schema_item_t *schema_item, *next;
  369. if (replica == NULL) {
  370. return;
  371. }
  372. /* Start to free the previous policy */
  373. /* first the objectclasses policies */
  374. for (schema_item = replica->objectclasses; schema_item; ) {
  375. slapi_ch_free((void **) &schema_item->name_or_oid);
  376. next = schema_item->next;
  377. slapi_ch_free((void **) &schema_item);
  378. schema_item = next;
  379. }
  380. replica->objectclasses = NULL;
  381. /* second the attributes policies */
  382. for (schema_item = replica->attributes; schema_item; ) {
  383. slapi_ch_free((void **) &schema_item->name_or_oid);
  384. next = schema_item->next;
  385. slapi_ch_free((void **) &schema_item);
  386. schema_item = next;
  387. }
  388. replica->attributes = NULL;
  389. /* Load the replication policy of the schema */
  390. slapi_sdn_init_dn_byref( &sdn, dn );
  391. if (slapi_search_internal_get_entry(&sdn, NULL, &entry, plugin_get_default_component_id()) == LDAP_SUCCESS) {
  392. /* fill the policies (accept/reject) regarding objectclass */
  393. schema_policy_add_action(entry, ATTR_SCHEMA_UPDATE_OBJECTCLASS_ACCEPT, &replica->objectclasses);
  394. schema_policy_add_action(entry, ATTR_SCHEMA_UPDATE_OBJECTCLASS_REJECT, &replica->objectclasses);
  395. /* fill the policies (accept/reject) regarding attribute */
  396. schema_policy_add_action(entry, ATTR_SCHEMA_UPDATE_ATTRIBUTE_ACCEPT, &replica->attributes);
  397. schema_policy_add_action(entry, ATTR_SCHEMA_UPDATE_ATTRIBUTE_REJECT, &replica->attributes);
  398. slapi_entry_free( entry );
  399. }
  400. slapi_sdn_done(&sdn);
  401. }
  402. /* It load the policies (if they are defined) regarding the replication of the schema
  403. * depending if the instance behaves as a consumer or a supplier
  404. * It returns 0 if success
  405. */
  406. int
  407. slapi_schema_load_repl_policies()
  408. {
  409. if (schema_policy_lock == NULL) {
  410. if (NULL == (schema_policy_lock = slapi_new_rwlock())) {
  411. slapi_log_error(SLAPI_LOG_FATAL, "slapi_schema_load_repl_policies",
  412. "slapi_new_rwlock() for schema replication policy lock failed\n");
  413. return -1;
  414. }
  415. }
  416. slapi_rwlock_wrlock( schema_policy_lock );
  417. schema_load_repl_policy((const char *) ENTRY_REPL_SCHEMA_SUPPLIER, &supplier_policy);
  418. schema_load_repl_policy((const char *) ENTRY_REPL_SCHEMA_CONSUMER, &consumer_policy);
  419. slapi_rwlock_unlock( schema_policy_lock );
  420. return 0;
  421. }
  422. /*
  423. * It checks if the name/oid of the provided schema item (objectclass/attribute)
  424. * is defined in the schema replication policy.
  425. * If the replica role is a supplier, it takes the policy from supplier_policy else
  426. * it takes it from the consumer_policy.
  427. * Then depending on the schema_item, it takes the objectclasses or attributes policies
  428. *
  429. * If it find the name/oid in the policies, it returns
  430. * REPL_SCHEMA_UPDATE_ACCEPT_VALUE: This schema item is accepted and can not prevent schema update
  431. * REPL_SCHEMA_UPDATE_REJECT_VALUE: This schema item is rejected and prevents the schema update
  432. * REPL_SCHEMA_UPDATE_UNKNOWN_VALUE: This schema item as no defined policy
  433. *
  434. * Caller must hold schema_policy_lock in read
  435. */
  436. static int
  437. schema_check_policy(int replica_role, int schema_item, char *name, char *oid)
  438. {
  439. repl_schema_policy_t *repl_policy;
  440. schema_item_t *policy;
  441. /* depending on the role, we take the supplier or the consumer policy */
  442. if (replica_role == REPL_SCHEMA_AS_SUPPLIER) {
  443. repl_policy = &supplier_policy;
  444. } else {
  445. repl_policy = &consumer_policy;
  446. }
  447. /* Now take the correct schema item policy */
  448. if (schema_item == REPL_SCHEMA_OBJECTCLASS) {
  449. policy = repl_policy->objectclasses;
  450. } else {
  451. policy = repl_policy->attributes;
  452. }
  453. /* Try to find the name/oid in the defined policies */
  454. while (policy) {
  455. if ((strcasecmp( name, policy->name_or_oid) == 0) || (strcasecmp( oid, policy->name_or_oid) == 0)) {
  456. return policy->action;
  457. }
  458. policy = policy->next;
  459. }
  460. return REPL_SCHEMA_UPDATE_UNKNOWN_VALUE;
  461. }
  462. static void
  463. schema_dse_lock_read( void )
  464. {
  465. if ( NULL != schema_dse_lock ||
  466. PR_SUCCESS == PR_CallOnce( &schema_dse_mandatory_init_callonce,
  467. schema_dse_mandatory_init )) {
  468. slapi_rwlock_rdlock( schema_dse_lock );
  469. }
  470. }
  471. static void
  472. schema_dse_lock_write( void )
  473. {
  474. if ( NULL != schema_dse_lock ||
  475. PR_SUCCESS == PR_CallOnce( &schema_dse_mandatory_init_callonce,
  476. schema_dse_mandatory_init )) {
  477. slapi_rwlock_wrlock( schema_dse_lock );
  478. }
  479. }
  480. static void
  481. schema_dse_unlock( void )
  482. {
  483. if ( schema_dse_lock != NULL ) {
  484. slapi_rwlock_unlock( schema_dse_lock );
  485. }
  486. }
  487. static int
  488. dont_allow_that(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg)
  489. {
  490. *returncode = LDAP_UNWILLING_TO_PERFORM;
  491. return SLAPI_DSE_CALLBACK_ERROR;
  492. }
  493. #if !defined(USE_OPENLDAP)
  494. static const char *
  495. skipWS(const char *s)
  496. {
  497. while (s && isascii(*s) && isspace(*s) )
  498. ++s;
  499. if ((isascii(*s)) == 0) {
  500. return NULL;
  501. }
  502. return s;
  503. }
  504. /*
  505. * like strchr() but strings within single quotes are skipped.
  506. */
  507. static char *
  508. strchr_skip_quoted_strings( char *s, int c )
  509. {
  510. int in_quote = 0;
  511. while ( *s != '\0' ) {
  512. if ( *s == '\'' ) {
  513. in_quote = 1 - in_quote; /* toggle */
  514. } else if ( !in_quote && *s == c ) {
  515. return s;
  516. }
  517. ++s;
  518. }
  519. return( NULL );
  520. }
  521. /**
  522. * parses a string containing a qdescrs or qdstrings (as described by
  523. * RFC 2252, section 4.1) into an array of strings; the second parameter
  524. * will hold the actual number of strings in the array. The returned array
  525. * is NULL terminated.
  526. *
  527. * This function can handle qdescrs or qdstrings because the only
  528. * difference between the two is that fewer characters are allowed in
  529. * a qdescr (our parsing code does not check anyway) and we want to
  530. * strip attribute options when parsing qdescrs (indicated by a non-zero
  531. * strip_options parameter).
  532. */
  533. static char **
  534. parse_qdlist(const char *s, int *n, int strip_options)
  535. {
  536. char **retval = 0;
  537. char *work = 0;
  538. char *start = 0, *end = 0;
  539. int num = 0;
  540. int in_quote = 0;
  541. if (n)
  542. *n = 0;
  543. if (!s || !*s || !n) {
  544. return retval;
  545. }
  546. /* make a working copy of the given string */
  547. work = slapi_ch_strdup(s);
  548. /* count the number of qdescr items in the string e.g. just count
  549. the number of spaces */
  550. /* for a single qdescr, the terminal character will be the final
  551. single quote; for a qdesclist, the terminal will be the close
  552. parenthesis */
  553. end = strrchr(work, '\'');
  554. if ((start = strchr_skip_quoted_strings(work, '(')) != NULL)
  555. end = strchr_skip_quoted_strings(work, ')');
  556. else
  557. start = strchr(work, '\'');
  558. if (!end) /* already nulled out */
  559. end = work + strlen(work);
  560. if (start) {
  561. num = 1;
  562. /* first pass: count number of items and zero out non useful tokens */
  563. for (; *start && (start != end); ++start) {
  564. if (*start == '\'' ) {
  565. in_quote = 1 - in_quote; /* toggle */
  566. *start = 0;
  567. } else if ( !in_quote && ((*start == ' ') || (*start == '(') ||
  568. (*start == ')'))) {
  569. if (*start == ' ') {
  570. num++;
  571. }
  572. *start = 0;
  573. }
  574. }
  575. *start = 0;
  576. /* allocate retval; num will be >= actual number of items */
  577. retval = (char**)slapi_ch_calloc(num+1, sizeof(char *));
  578. /* second pass: copy strings into the return value and set the
  579. actual number of items returned */
  580. start = work;
  581. while (start != end) {
  582. /* skip over nulls */
  583. while (!*start && (start != end))
  584. ++start;
  585. if (start == end)
  586. break;
  587. retval[*n] = slapi_ch_strdup(start);
  588. /*
  589. * A qdescr list may contain attribute options; we just strip
  590. * them here. In the future, we may want to support them or do
  591. * something really fancy with them
  592. */
  593. if ( strip_options ) {
  594. stripOption(retval[*n]);
  595. }
  596. (*n)++;
  597. start += strlen(start);
  598. }
  599. PR_ASSERT( *n <= num ); /* sanity check */
  600. retval[*n] = NULL;
  601. } else {
  602. /* syntax error - no start and/or end delimiters */
  603. }
  604. /* free the working string */
  605. slapi_ch_free((void **)&work);
  606. return retval;
  607. }
  608. /**
  609. * parses a string containing a qdescrs (as described by RFC 2252, section 4.1)
  610. * into an array of strings; the second parameter will hold the actual number
  611. * of strings in the array. The returned array is NULL terminated.
  612. */
  613. static char **
  614. parse_qdescrs(const char *s, int *n)
  615. {
  616. return parse_qdlist( s, n, 1 /* strip attribute options */ );
  617. }
  618. /*
  619. * Parses a string containing a qdstrings (see RFC 2252, section 4.1) into
  620. * an array of strings; the second parameter will hold the actual number
  621. * of strings in the array.
  622. */
  623. static char **
  624. parse_qdstrings(const char *s, int *n)
  625. {
  626. return parse_qdlist( s, n, 0 /* DO NOT strip attribute options */ );
  627. }
  628. static void
  629. free_qdlist(char **vals, int n)
  630. {
  631. int ii;
  632. for (ii = 0; ii < n; ++ii)
  633. slapi_ch_free((void **)&(vals[ii]));
  634. slapi_ch_free((void **)&vals);
  635. }
  636. #endif /* not openldap */
  637. /*
  638. * slapi_entry_schema_check - check that entry e conforms to the schema
  639. * required by its object class(es). returns 0 if so, non-zero otherwise.
  640. * [ the pblock is used to check if this is a replicated operation.
  641. * you may pass in NULL if this isn't part of an operation. ]
  642. * the pblock is also used to return a reason why schema checking failed.
  643. * it is also used to get schema flags
  644. * if replicated operations should be checked use slapi_entry_schema_check_ext
  645. */
  646. int
  647. slapi_entry_schema_check( Slapi_PBlock *pb, Slapi_Entry *e )
  648. {
  649. return (slapi_entry_schema_check_ext(pb, e, 0));
  650. }
  651. int
  652. slapi_entry_schema_check_ext( Slapi_PBlock *pb, Slapi_Entry *e, int repl_check )
  653. {
  654. struct objclass **oclist;
  655. struct objclass *oc;
  656. const char *ocname;
  657. Slapi_Attr *a, *aoc;
  658. Slapi_Value *v;
  659. int ret = 0;
  660. int schemacheck = config_get_schemacheck();
  661. int is_replicated_operation = 0;
  662. int is_extensible_object = 0;
  663. int i, oc_count = 0;
  664. int unknown_class = 0;
  665. char errtext[ BUFSIZ ];
  666. PRUint32 schema_flags = 0;
  667. /*
  668. * say the schema checked out ok if we're not checking schema at
  669. * all, or if this is a replication update.
  670. */
  671. if (pb != NULL) {
  672. slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &is_replicated_operation);
  673. slapi_pblock_get(pb, SLAPI_SCHEMA_FLAGS, &schema_flags);
  674. }
  675. if ( schemacheck == 0 || (is_replicated_operation && !repl_check)) {
  676. return( 0 );
  677. }
  678. /* find the object class attribute - could error out here */
  679. if ( (aoc = attrlist_find( e->e_attrs, "objectclass" )) == NULL ) {
  680. LDAPDebug( LDAP_DEBUG_ANY,
  681. "Entry \"%s\" required attribute \"objectclass\" missing\n",
  682. slapi_entry_get_dn_const(e), 0, 0 );
  683. if (pb) {
  684. PR_snprintf( errtext, sizeof( errtext ),
  685. "missing required attribute \"objectclass\"\n" );
  686. slapi_pblock_set( pb, SLAPI_PB_RESULT_TEXT, errtext );
  687. }
  688. return( 1 );
  689. }
  690. /*
  691. * Create an array of pointers to the objclass definitions.
  692. */
  693. i= slapi_attr_first_value(aoc,&v);
  694. while (i != -1) {
  695. oc_count++;
  696. i= slapi_attr_next_value(aoc,i,&v);
  697. }
  698. oclist = (struct objclass**)
  699. slapi_ch_malloc((oc_count+1)*sizeof(struct objclass*));
  700. /*
  701. * Need the read lock to create the oc array and while we use it.
  702. */
  703. if (!(schema_flags & DSE_SCHEMA_LOCKED))
  704. oc_lock_read();
  705. oc_count = 0;
  706. for (i= slapi_attr_first_value(aoc,&v); i != -1;
  707. i= slapi_attr_next_value(aoc,i,&v)) {
  708. ocname = slapi_value_get_string(v);
  709. if ( !ocname ) {
  710. LDAPDebug( LDAP_DEBUG_ANY,
  711. "Entry \"%s\" \"objectclass\" value missing\n",
  712. slapi_entry_get_dn_const(e), 0, 0 );
  713. if (pb) {
  714. PR_snprintf( errtext, sizeof( errtext ),
  715. "missing \"objectclass\" value\n" );
  716. slapi_pblock_set( pb, SLAPI_PB_RESULT_TEXT, errtext );
  717. }
  718. ret = 1;
  719. goto out;
  720. }
  721. if ( isExtensibleObjectclass( ocname )) {
  722. /*
  723. * if the entry is an extensibleObject, just check to see if
  724. * the required attributes for whatever other objectclasses the
  725. * entry might be are present. All other attributes are allowed
  726. */
  727. is_extensible_object = 1;
  728. continue;
  729. }
  730. if ((oc = oc_find_nolock( ocname, NULL, PR_FALSE )) != NULL ) {
  731. oclist[oc_count++] = oc;
  732. } else {
  733. /* we don't know about the oc; return an appropriate error message */
  734. char ebuf[ BUFSIZ ];
  735. size_t ocname_len = strlen( ocname );
  736. const char *extra_msg = "";
  737. if ( ocname_len > 0 && isspace( ocname[ ocname_len-1 ] )) {
  738. if ( ocname_len > 1 && isspace( ocname[ ocname_len-2 ] )) {
  739. extra_msg = " (remove the trailing spaces)";
  740. } else {
  741. extra_msg = " (remove the trailing space)";
  742. }
  743. }
  744. LDAPDebug( LDAP_DEBUG_ANY,
  745. "Entry \"%s\" has unknown object class \"%s\"%s\n",
  746. slapi_entry_get_dn_const(e),
  747. escape_string(ocname, ebuf), extra_msg );
  748. if (pb) {
  749. PR_snprintf( errtext, sizeof( errtext ),
  750. "unknown object class \"%s\"%s\n",
  751. escape_string(ocname, ebuf), extra_msg );
  752. slapi_pblock_set( pb, SLAPI_PB_RESULT_TEXT, errtext );
  753. }
  754. unknown_class = 1;
  755. }
  756. }
  757. oclist[oc_count] = NULL;
  758. if (unknown_class) {
  759. /* failure */
  760. ret = 1;
  761. goto out;
  762. }
  763. /*
  764. * go through all the checking so we can log everything
  765. * wrong with the entry. some day, we might want to return
  766. * this information to the client as an error message.
  767. */
  768. /*
  769. * check that the entry has required attrs for each oc
  770. */
  771. for (i = 0; oclist[i] != NULL; i++) {
  772. if ( oc_check_required( pb, e, oclist[i] ) != 0 ) {
  773. ret = 1;
  774. goto out;
  775. }
  776. }
  777. /*
  778. * check that each attr in the entry is allowed by some oc,
  779. * and that single-valued attrs only have one value
  780. */
  781. {
  782. Slapi_Attr *prevattr;
  783. i = slapi_entry_first_attr(e, &a);
  784. while (-1 != i && 0 == ret)
  785. {
  786. if (is_extensible_object == 0 &&
  787. unknown_class == 0 &&
  788. !slapi_attr_flag_is_set(a, SLAPI_ATTR_FLAG_OPATTR))
  789. {
  790. char *attrtype;
  791. slapi_attr_get_type(a, &attrtype);
  792. if (oc_check_allowed_sv(pb, e, attrtype, oclist) != 0)
  793. {
  794. ret = 1;
  795. }
  796. }
  797. if ( slapi_attr_flag_is_set( a, SLAPI_ATTR_FLAG_SINGLE ) ) {
  798. if (slapi_valueset_count(&a->a_present_values) > 1)
  799. {
  800. LDAPDebug( LDAP_DEBUG_ANY,
  801. "Entry \"%s\" single-valued attribute \"%s\" has multiple values\n",
  802. slapi_entry_get_dn_const(e),
  803. a->a_type, 0 );
  804. if (pb) {
  805. PR_snprintf( errtext, sizeof( errtext ),
  806. "single-valued attribute \"%s\" has multiple values\n",
  807. a->a_type );
  808. slapi_pblock_set( pb, SLAPI_PB_RESULT_TEXT, errtext );
  809. }
  810. ret = 1;
  811. }
  812. }
  813. prevattr = a;
  814. i = slapi_entry_next_attr(e, prevattr, &a);
  815. }
  816. }
  817. out:
  818. /* Done with the oc array so can release the lock */
  819. if (!(schema_flags & DSE_SCHEMA_LOCKED))
  820. oc_unlock();
  821. slapi_ch_free((void**)&oclist);
  822. return( ret );
  823. }
  824. /*
  825. * The caller must obtain a read lock first by calling oc_lock_read().
  826. */
  827. static int
  828. oc_check_required( Slapi_PBlock *pb, Slapi_Entry *e, struct objclass *oc )
  829. {
  830. int i;
  831. int rc = 0; /* success, by default */
  832. Slapi_Attr *a;
  833. if (oc == NULL || oc->oc_required == NULL || oc->oc_required[0] == NULL) {
  834. return 0; /* success, as none required */
  835. }
  836. /* for each required attribute */
  837. for ( i = 0; oc->oc_required[i] != NULL; i++ ) {
  838. /* see if it's in the entry */
  839. for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
  840. if ( slapi_attr_type_cmp( oc->oc_required[i], a->a_type,
  841. SLAPI_TYPE_CMP_SUBTYPE ) == 0 ) {
  842. break;
  843. }
  844. }
  845. /* not there => schema violation */
  846. if ( a == NULL ) {
  847. char errtext[ BUFSIZ ];
  848. LDAPDebug( LDAP_DEBUG_ANY,
  849. "Entry \"%s\" missing attribute \"%s\" required"
  850. " by object class \"%s\"\n",
  851. slapi_entry_get_dn_const(e),
  852. oc->oc_required[i], oc->oc_name);
  853. if (pb) {
  854. PR_snprintf( errtext, sizeof( errtext ),
  855. "missing attribute \"%s\" required"
  856. " by object class \"%s\"\n",
  857. oc->oc_required[i], oc->oc_name );
  858. slapi_pblock_set( pb, SLAPI_PB_RESULT_TEXT, errtext );
  859. }
  860. rc = 1; /* failure */
  861. }
  862. }
  863. return rc;
  864. }
  865. /*
  866. * The caller must obtain a read lock first by calling oc_lock_read().
  867. */
  868. static int
  869. oc_check_allowed_sv(Slapi_PBlock *pb, Slapi_Entry *e, const char *type, struct objclass **oclist )
  870. {
  871. struct objclass *oc;
  872. int i, j;
  873. int rc = 1; /* failure */
  874. /* always allow objectclass and entryid attributes */
  875. /* MFW XXX THESE SHORTCUTS SHOULD NOT BE NECESSARY BUT THEY MASK
  876. * MFW XXX OTHER BUGS IN THE SERVER.
  877. */
  878. if ( slapi_attr_type_cmp( type, "objectclass", SLAPI_TYPE_CMP_EXACT ) == 0 ) {
  879. return( 0 );
  880. } else if ( slapi_attr_type_cmp( type, "entryid", SLAPI_TYPE_CMP_EXACT ) == 0 ) {
  881. return( 0 );
  882. }
  883. /* check that the type appears as req or opt in at least one oc */
  884. for (i = 0; rc != 0 && oclist[i] != NULL; i++) {
  885. oc = oclist[i];
  886. /* does it require the type? */
  887. for ( j = 0; oc->oc_required && oc->oc_required[j] != NULL; j++ ) {
  888. if ( slapi_attr_type_cmp( oc->oc_required[j],
  889. type, SLAPI_TYPE_CMP_SUBTYPE ) == 0 ) {
  890. rc = 0;
  891. break;
  892. }
  893. }
  894. if ( 0 != rc ) {
  895. /* does it allow the type? */
  896. for ( j = 0; oc->oc_allowed && oc->oc_allowed[j] != NULL; j++ ) {
  897. if ( slapi_attr_type_cmp( oc->oc_allowed[j],
  898. type, SLAPI_TYPE_CMP_SUBTYPE ) == 0 ||
  899. strcmp( oc->oc_allowed[j],"*" ) == 0 ) {
  900. rc = 0;
  901. break;
  902. }
  903. }
  904. /* maybe the next oc allows it */
  905. }
  906. }
  907. if ( 0 != rc ) {
  908. char errtext[ BUFSIZ ];
  909. char ebuf[ BUFSIZ ];
  910. LDAPDebug( LDAP_DEBUG_ANY,
  911. "Entry \"%s\" -- attribute \"%s\" not allowed\n",
  912. slapi_entry_get_dn_const(e),
  913. escape_string( type, ebuf ),
  914. 0);
  915. if (pb) {
  916. PR_snprintf( errtext, sizeof( errtext ),
  917. "attribute \"%s\" not allowed\n",
  918. escape_string( type, ebuf ) );
  919. slapi_pblock_set( pb, SLAPI_PB_RESULT_TEXT, errtext );
  920. }
  921. }
  922. return rc;
  923. }
  924. /*
  925. * oc_find_name() will return a strdup'd string or NULL if the objectclass
  926. * could not be found.
  927. */
  928. char *
  929. oc_find_name( const char *name_or_oid )
  930. {
  931. struct objclass *oc;
  932. char *ocname = NULL;
  933. oc_lock_read();
  934. if ( NULL != ( oc = oc_find_nolock( name_or_oid, NULL, PR_FALSE ))) {
  935. ocname = slapi_ch_strdup( oc->oc_name );
  936. }
  937. oc_unlock();
  938. return ocname;
  939. }
  940. /*
  941. * oc_find_nolock will return a pointer to the objectclass which has the
  942. * same name OR oid.
  943. * NULL is returned if no match is found or `name_or_oid' is NULL.
  944. */
  945. static struct objclass *
  946. oc_find_nolock( const char *ocname_or_oid, struct objclass *oc_private, PRBool use_private)
  947. {
  948. struct objclass *oc;
  949. if ( NULL != ocname_or_oid ) {
  950. if ( !schema_ignore_trailing_spaces ) {
  951. if (use_private) {
  952. oc = oc_private;
  953. } else {
  954. oc = g_get_global_oc_nolock();
  955. }
  956. for ( ; oc != NULL; oc = oc->oc_next ) {
  957. if ( ( strcasecmp( oc->oc_name, ocname_or_oid ) == 0 )
  958. || ( oc->oc_oid &&
  959. strcasecmp( oc->oc_oid, ocname_or_oid ) == 0 )) {
  960. return( oc );
  961. }
  962. }
  963. } else {
  964. const char *p;
  965. size_t len;
  966. /*
  967. * Ignore trailing spaces when comparing object class names.
  968. */
  969. for ( p = ocname_or_oid, len = 0; (*p != '\0') && (*p != ' ');
  970. p++, len++ ) {
  971. ; /* NULL */
  972. }
  973. if (use_private) {
  974. oc = oc_private;
  975. } else {
  976. oc = g_get_global_oc_nolock();
  977. }
  978. for ( ; oc != NULL; oc = oc->oc_next ) {
  979. if ( ( (strncasecmp( oc->oc_name, ocname_or_oid, len ) == 0)
  980. && (len == strlen(oc->oc_name)) )
  981. ||
  982. ( oc->oc_oid &&
  983. ( strncasecmp( oc->oc_oid, ocname_or_oid, len ) == 0)
  984. && (len == strlen(oc->oc_oid)) ) ) {
  985. return( oc );
  986. }
  987. }
  988. }
  989. }
  990. return( NULL );
  991. }
  992. /*
  993. * oc_find_oid_nolock will return a pointer to the objectclass which has
  994. * the same oid.
  995. * NULL is returned if no match is found or `ocoid' is NULL.
  996. */
  997. static struct objclass *
  998. oc_find_oid_nolock( const char *ocoid )
  999. {
  1000. struct objclass *oc;
  1001. if ( NULL != ocoid ) {
  1002. for ( oc = g_get_global_oc_nolock(); oc != NULL; oc = oc->oc_next ) {
  1003. if ( ( oc->oc_oid &&
  1004. ( strcasecmp( oc->oc_oid, ocoid ) == 0)) ){
  1005. return( oc );
  1006. }
  1007. }
  1008. }
  1009. return( NULL );
  1010. }
  1011. /*
  1012. We need to keep the objectclasses in the same order as defined in the ldif files. If not
  1013. SUP dependencies will break. When the user redefines an existing objectclass this code
  1014. makes sure it is put back in the same order it was read to from the ldif file. It also
  1015. verifies that the entries oc_superior value preceeds it in the chain. If not it will not
  1016. allow the entry to be added. This makes sure that the ldif will be written back correctly.
  1017. */
  1018. static int
  1019. oc_replace_nolock(const char *ocname, struct objclass *newoc) {
  1020. struct objclass *oc, *pnext;
  1021. int rc = LDAP_SUCCESS;
  1022. PRBool saw_sup=PR_FALSE;
  1023. oc = g_get_global_oc_nolock();
  1024. if(newoc->oc_superior == NULL)
  1025. {
  1026. saw_sup=PR_TRUE;
  1027. }
  1028. /* don't check SUP dependency for first one because it always/should be top */
  1029. if (strcasecmp (oc->oc_name, ocname) == 0) {
  1030. newoc->oc_next=oc->oc_next;
  1031. g_set_global_oc_nolock ( newoc );
  1032. oc_free( &oc );
  1033. } else {
  1034. for (pnext = oc ; pnext != NULL;
  1035. oc = pnext, pnext = pnext->oc_next) {
  1036. if(pnext->oc_name == NULL) {
  1037. rc = LDAP_OPERATIONS_ERROR;
  1038. break;
  1039. }
  1040. if(newoc->oc_superior != NULL) {
  1041. if(strcasecmp( pnext->oc_name, newoc->oc_superior) == 0)
  1042. {
  1043. saw_sup=PR_TRUE;
  1044. }
  1045. }
  1046. if (strcasecmp ( pnext->oc_name, ocname ) == 0) {
  1047. if(saw_sup)
  1048. {
  1049. oc->oc_next=newoc;
  1050. newoc->oc_next=pnext->oc_next;
  1051. oc_free( &pnext );
  1052. break;
  1053. } else
  1054. {
  1055. rc = LDAP_TYPE_OR_VALUE_EXISTS;
  1056. break;
  1057. }
  1058. }
  1059. }
  1060. }
  1061. return rc;
  1062. }
  1063. static int
  1064. oc_delete_nolock (char *ocname)
  1065. {
  1066. struct objclass *oc, *pnext;
  1067. int rc = 0; /* failure */
  1068. oc = g_get_global_oc_nolock();
  1069. /* special case if we're removing the first oc */
  1070. if (strcasecmp (oc->oc_name, ocname) == 0) {
  1071. g_set_global_oc_nolock ( oc->oc_next );
  1072. oc_free( &oc );
  1073. rc = 1;
  1074. } else {
  1075. for (pnext = oc->oc_next ; pnext != NULL;
  1076. oc = pnext, pnext = pnext->oc_next) {
  1077. if (strcasecmp ( pnext->oc_name, ocname ) == 0) {
  1078. oc->oc_next = pnext->oc_next;
  1079. oc_free( &pnext );
  1080. rc = 1;
  1081. break;
  1082. }
  1083. }
  1084. }
  1085. return rc;
  1086. }
  1087. static void
  1088. oc_delete_all_nolock( void )
  1089. {
  1090. struct objclass *oc, *pnext;
  1091. oc = g_get_global_oc_nolock();
  1092. for (pnext = oc->oc_next; oc;
  1093. oc = pnext, pnext = oc?oc->oc_next:NULL) {
  1094. oc_free( &oc );
  1095. }
  1096. g_set_global_oc_nolock ( NULL );
  1097. }
  1098. /*
  1099. * Compare two objectclass definitions for equality. Return PR_TRUE if
  1100. * they are equivalent and PR_FALSE if not.
  1101. *
  1102. * The oc_required and oc_allowed arrays are ignored.
  1103. * The string "user defined" is ignored within the origins array.
  1104. * The following flags are ignored:
  1105. * OC_FLAG_STANDARD_OC
  1106. * OC_FLAG_USER_OC
  1107. * OC_FLAG_REDEFINED_OC
  1108. */
  1109. static PRBool
  1110. oc_equal( struct objclass *oc1, struct objclass *oc2 )
  1111. {
  1112. PRUint8 flagmask;
  1113. if ( schema_strcmp( oc1->oc_name, oc2->oc_name ) != 0
  1114. || schema_strcmp( oc1->oc_desc, oc2->oc_desc ) != 0
  1115. || schema_strcmp( oc1->oc_oid, oc2->oc_oid ) != 0
  1116. || schema_strcmp( oc1->oc_superior, oc2->oc_superior ) != 0 ) {
  1117. return PR_FALSE;
  1118. }
  1119. flagmask = ~(OC_FLAG_STANDARD_OC | OC_FLAG_USER_OC | OC_FLAG_REDEFINED_OC);
  1120. if ( oc1->oc_kind != oc2->oc_kind
  1121. || ( oc1->oc_flags & flagmask ) != ( oc2->oc_flags & flagmask )) {
  1122. return PR_FALSE;
  1123. }
  1124. if ( schema_strcmp_array( oc1->oc_orig_required, oc2->oc_orig_required,
  1125. NULL ) != 0
  1126. || schema_strcmp_array( oc1->oc_orig_allowed, oc2->oc_orig_allowed,
  1127. NULL ) != 0
  1128. || schema_extension_cmp( oc1->oc_extensions, oc2->oc_extensions ) != 0 ) {
  1129. return PR_FALSE;
  1130. }
  1131. return PR_TRUE;
  1132. }
  1133. #ifdef OC_DEBUG
  1134. static int
  1135. oc_print( struct objclass *oc )
  1136. {
  1137. int i;
  1138. printf( "object class %s\n", oc->oc_name );
  1139. if ( oc->oc_required != NULL ) {
  1140. printf( "\trequires %s", oc->oc_required[0] );
  1141. for ( i = 1; oc->oc_required[i] != NULL; i++ ) {
  1142. printf( ",%s", oc->oc_required[i] );
  1143. }
  1144. printf( "\n" );
  1145. }
  1146. if ( oc->oc_allowed != NULL ) {
  1147. printf( "\tallows %s", oc->oc_allowed[0] );
  1148. for ( i = 1; oc->oc_allowed[i] != NULL; i++ ) {
  1149. printf( ",%s", oc->oc_allowed[i] );
  1150. }
  1151. printf( "\n" );
  1152. }
  1153. return 0;
  1154. }
  1155. #endif
  1156. /*
  1157. * Compare the X-ORIGIN extension, other extensions can be ignored
  1158. */
  1159. static int
  1160. schema_extension_cmp(schemaext *e1, schemaext *e2)
  1161. {
  1162. schemaext *e1_head = e1;
  1163. schemaext *e2_head = e2;
  1164. int found = 0;
  1165. int e1_has_origin = 0;
  1166. int e2_has_origin = 0;
  1167. int i, ii;
  1168. if(e1 == NULL && e2 == NULL){
  1169. return 0; /* match */
  1170. } else if (e1 == NULL || e2 == NULL){
  1171. return -1;
  1172. }
  1173. while(e1){
  1174. if(strcmp(e1->term, "X-ORIGIN")){
  1175. e1 = e1->next;
  1176. continue;
  1177. }
  1178. e1_has_origin = 1;
  1179. while(e2){
  1180. if(strcmp(e1->term, e2->term) == 0)
  1181. {
  1182. e2_has_origin = 1;
  1183. if(e1->values == NULL && e2->values == NULL){
  1184. return 0;
  1185. } else if (e1->values == NULL || e2->values == NULL){
  1186. return -1;
  1187. }
  1188. for (i = 0; e1->values[i]; i++)
  1189. {
  1190. found = 0;
  1191. for(ii = 0; e2->values[ii]; ii++)
  1192. {
  1193. if(strcmp(e1->values[i], e2->values[ii]) == 0){
  1194. found = 1;
  1195. break;
  1196. }
  1197. }
  1198. if(!found){
  1199. return -1;
  1200. }
  1201. }
  1202. /* So far so good, move on to the next check */
  1203. goto next;
  1204. }
  1205. e2 = e2->next;
  1206. }
  1207. e2 = e2_head;
  1208. e1 = e1->next;
  1209. }
  1210. if(e1_has_origin != e2_has_origin){
  1211. return -1;
  1212. } else if (e1_has_origin == 0 && e2_has_origin == 0){
  1213. return 0;
  1214. }
  1215. next:
  1216. /*
  1217. * We know that e2 has the same extensions as e1, but does e1 have all the extensions as e2?
  1218. * Run the compare in reverse...
  1219. */
  1220. found = 0;
  1221. e1 = e1_head;
  1222. e2 = e2_head;
  1223. while(e2){
  1224. if(strcmp(e2->term, "X-ORIGIN")){
  1225. e2 = e2->next;
  1226. continue;
  1227. }
  1228. while(e1){
  1229. if(strcmp(e2->term, e1->term) == 0)
  1230. {
  1231. if(e2->values == NULL && e1->values == NULL){
  1232. return 0;
  1233. } else if (e1->values == NULL || e2->values == NULL){
  1234. return -1;
  1235. }
  1236. for (i = 0; e2->values[i]; i++)
  1237. {
  1238. found = 0;
  1239. for(ii = 0; e1->values[ii]; ii++)
  1240. {
  1241. if(strcmp(e2->values[i], e1->values[ii]) == 0){
  1242. found = 1;
  1243. break;
  1244. }
  1245. }
  1246. if(!found){
  1247. return -1;
  1248. }
  1249. }
  1250. return 0;
  1251. }
  1252. e1 = e1->next;
  1253. }
  1254. e1 = e1_head;
  1255. e2 = e2->next;
  1256. }
  1257. return 0;
  1258. }
  1259. /*
  1260. * Compare two attrsyntax definitions for equality. Return PR_TRUE if
  1261. * they are equivalent and PR_FALSE if not.
  1262. *
  1263. * The string "user defined" is ignored within the origins array.
  1264. * The following flags are ignored:
  1265. * SLAPI_ATTR_FLAG_STD_ATTR
  1266. * SLAPI_ATTR_FLAG_NOLOCKING
  1267. * SLAPI_ATTR_FLAG_OVERRIDE
  1268. */
  1269. static PRBool
  1270. attr_syntax_equal( struct asyntaxinfo *asi1, struct asyntaxinfo *asi2 )
  1271. {
  1272. unsigned long flagmask;
  1273. flagmask = ~( SLAPI_ATTR_FLAG_STD_ATTR | SLAPI_ATTR_FLAG_NOLOCKING
  1274. | SLAPI_ATTR_FLAG_OVERRIDE );
  1275. if ( schema_strcmp( asi1->asi_oid, asi2->asi_oid ) != 0
  1276. || schema_strcmp( asi1->asi_name, asi2->asi_name ) != 0
  1277. || schema_strcmp( asi1->asi_desc, asi2->asi_desc ) != 0
  1278. || schema_strcmp( asi1->asi_superior, asi2->asi_superior ) != 0
  1279. || schema_strcmp( asi1->asi_mr_equality, asi2->asi_mr_equality )
  1280. != 0
  1281. || schema_strcmp( asi1->asi_mr_ordering, asi2->asi_mr_ordering )
  1282. != 0
  1283. || schema_strcmp( asi1->asi_mr_substring,
  1284. asi2->asi_mr_substring ) != 0 ) {
  1285. return PR_FALSE;
  1286. }
  1287. if ( schema_strcmp_array( asi1->asi_aliases, asi2->asi_aliases, NULL ) != 0
  1288. || schema_extension_cmp (asi1->asi_extensions, asi2->asi_extensions) != 0
  1289. || asi1->asi_plugin != asi2->asi_plugin
  1290. || ( asi1->asi_flags & flagmask ) !=
  1291. ( asi2->asi_flags & flagmask )
  1292. || asi1->asi_syntaxlength != asi2->asi_syntaxlength ) {
  1293. return PR_FALSE;
  1294. }
  1295. return PR_TRUE;
  1296. }
  1297. /*
  1298. * Like strcmp(), but a NULL string pointer is treated as equivalent to
  1299. * another NULL one and NULL is treated as "less than" all non-NULL values.
  1300. */
  1301. static int
  1302. schema_strcmp( const char *s1, const char *s2 )
  1303. {
  1304. if ( s1 == NULL ) {
  1305. if ( s2 == NULL ) {
  1306. return 0; /* equal */
  1307. }
  1308. return -1; /* s1 < s2 */
  1309. }
  1310. if ( s2 == NULL ) {
  1311. return 1; /* s1 > s2 */
  1312. }
  1313. return strcmp( s1, s2 );
  1314. }
  1315. /*
  1316. * Invoke strcmp() on each string in an array. If one array has fewer elements
  1317. * than the other, it is treated as "less than" the other. Two NULL or
  1318. * empty arrays (or one NULL and one empty) are considered to be equivalent.
  1319. *
  1320. * If ignorestr is non-NULL, occurrences of that string are ignored.
  1321. */
  1322. static int
  1323. schema_strcmp_array( char **sa1, char **sa2, const char *ignorestr )
  1324. {
  1325. int i1, i2, rc;
  1326. if ( sa1 == NULL || *sa1 == NULL ) {
  1327. if ( sa2 == NULL || *sa2 == NULL ) {
  1328. return 0; /* equal */
  1329. }
  1330. return -1; /* sa1 < sa2 */
  1331. }
  1332. if ( sa2 == NULL || *sa2 == NULL ) {
  1333. return 1; /* sa1 > sa2 */
  1334. }
  1335. rc = 0;
  1336. i1 = i2 = 0;
  1337. while ( sa1[i1] != NULL && sa2[i2] != NULL ) {
  1338. if ( NULL != ignorestr ) {
  1339. if ( 0 == strcmp( sa1[i1], ignorestr )) {
  1340. ++i1;
  1341. continue;
  1342. }
  1343. if ( 0 == strcmp( sa2[i2], ignorestr )) {
  1344. ++i2;
  1345. continue;
  1346. }
  1347. }
  1348. rc = strcmp( sa1[i1], sa2[i2] );
  1349. ++i1;
  1350. ++i2;
  1351. }
  1352. if ( rc == 0 ) { /* all matched so far */
  1353. /* get rid of trailing ignored strings (if any) */
  1354. if ( NULL != ignorestr ) {
  1355. if ( sa1[i1] != NULL && 0 == strcmp( sa1[i1], ignorestr )) {
  1356. ++i1;
  1357. }
  1358. if ( sa2[i2] != NULL && 0 == strcmp( sa2[i2], ignorestr )) {
  1359. ++i2;
  1360. }
  1361. }
  1362. /* check for differing array lengths */
  1363. if ( sa2[i2] != NULL ) {
  1364. rc = -1; /* sa1 < sa2 -- fewer elements */
  1365. } else if ( sa1[i1] != NULL ) {
  1366. rc = 1; /* sa1 > sa2 -- more elements */
  1367. }
  1368. }
  1369. return rc;
  1370. }
  1371. struct attr_enum_wrapper {
  1372. Slapi_Attr **attrs;
  1373. int enquote_sup_oc;
  1374. struct sizedbuffer *psbAttrTypes;
  1375. int user_defined_only;
  1376. int schema_ds4x_compat;
  1377. };
  1378. static int
  1379. schema_attr_enum_callback(struct asyntaxinfo *asip, void *arg)
  1380. {
  1381. struct attr_enum_wrapper *aew = (struct attr_enum_wrapper *)arg;
  1382. int aliaslen = 0;
  1383. struct berval val;
  1384. struct berval *vals[2] = {0, 0};
  1385. const char *attr_desc, *syntaxoid;
  1386. char *outp, syntaxlengthbuf[ 128 ];
  1387. int i;
  1388. vals[0] = &val;
  1389. if (!asip) {
  1390. LDAPDebug(LDAP_DEBUG_ANY,
  1391. "Error: no attribute types in schema_attr_enum_callback\n",
  1392. 0, 0, 0);
  1393. return ATTR_SYNTAX_ENUM_NEXT;
  1394. }
  1395. if (aew->user_defined_only &&
  1396. (asip->asi_flags & SLAPI_ATTR_FLAG_STD_ATTR)) {
  1397. return ATTR_SYNTAX_ENUM_NEXT; /* not user defined */
  1398. }
  1399. if ( aew->schema_ds4x_compat ) {
  1400. attr_desc = ( asip->asi_flags & SLAPI_ATTR_FLAG_STD_ATTR)
  1401. ? ATTR_STANDARD_STRING : ATTR_USERDEF_STRING;
  1402. } else {
  1403. attr_desc = asip->asi_desc;
  1404. }
  1405. if ( asip->asi_aliases != NULL ) {
  1406. for ( i = 0; asip->asi_aliases[i] != NULL; ++i ) {
  1407. aliaslen += strlen( asip->asi_aliases[i] );
  1408. }
  1409. }
  1410. syntaxoid = asip->asi_plugin->plg_syntax_oid;
  1411. if ( !aew->schema_ds4x_compat &&
  1412. asip->asi_syntaxlength != SLAPI_SYNTAXLENGTH_NONE ) {
  1413. /* sprintf() is safe because syntaxlengthbuf is large enough */
  1414. sprintf( syntaxlengthbuf, "{%d}", asip->asi_syntaxlength );
  1415. } else {
  1416. *syntaxlengthbuf = '\0';
  1417. }
  1418. /*
  1419. * XXX: 256 is a magic number... it must be big enough to account for
  1420. * all of the fixed sized items we output.
  1421. */
  1422. sizedbuffer_allocate(aew->psbAttrTypes,256+strlen(asip->asi_oid)+
  1423. strlen(asip->asi_name) +
  1424. aliaslen + strlen_null_ok(attr_desc) +
  1425. strlen(syntaxoid) +
  1426. strlen_null_ok(asip->asi_superior) +
  1427. strlen_null_ok(asip->asi_mr_equality) +
  1428. strlen_null_ok(asip->asi_mr_ordering) +
  1429. strlen_null_ok(asip->asi_mr_substring) +
  1430. strcat_extensions( NULL, asip->asi_extensions ));
  1431. /*
  1432. * Overall strategy is to maintain a pointer to the next location in
  1433. * the output buffer so we can do simple strcpy's, sprintf's, etc.
  1434. * That pointer is `outp'. Each item that is output includes a trailing
  1435. * space, so there is no need to include a leading one in the next item.
  1436. */
  1437. outp = aew->psbAttrTypes->buffer;
  1438. outp += sprintf(outp, "( %s NAME ", asip->asi_oid);
  1439. if ( asip->asi_aliases == NULL || asip->asi_aliases[0] == NULL ) {
  1440. /* only one name */
  1441. outp += sprintf(outp, "'%s' ", asip->asi_name);
  1442. } else {
  1443. /* several names */
  1444. outp += sprintf(outp, "( '%s' ", asip->asi_name);
  1445. for ( i = 0; asip->asi_aliases[i] != NULL; ++i ) {
  1446. outp += sprintf(outp, "'%s' ", asip->asi_aliases[i]);
  1447. }
  1448. outp += strcpy_count(outp, ") ");
  1449. }
  1450. /* DESC is optional */
  1451. if (attr_desc && *attr_desc) {
  1452. outp += sprintf( outp, "DESC '%s'", attr_desc );
  1453. }
  1454. if ( !aew->schema_ds4x_compat &&
  1455. ( asip->asi_flags & SLAPI_ATTR_FLAG_OBSOLETE )) {
  1456. outp += strcpy_count( outp, schema_obsolete_with_spaces );
  1457. } else {
  1458. outp += strcpy_count( outp, " " );
  1459. }
  1460. if ( !aew->schema_ds4x_compat ) {
  1461. outp += put_tagged_oid( outp, "SUP ",
  1462. asip->asi_superior, NULL, aew->enquote_sup_oc );
  1463. outp += put_tagged_oid( outp, "EQUALITY ",
  1464. asip->asi_mr_equality, NULL, aew->enquote_sup_oc );
  1465. outp += put_tagged_oid( outp, "ORDERING ",
  1466. asip->asi_mr_ordering, NULL, aew->enquote_sup_oc );
  1467. outp += put_tagged_oid( outp, "SUBSTR ",
  1468. asip->asi_mr_substring, NULL, aew->enquote_sup_oc );
  1469. }
  1470. outp += put_tagged_oid( outp, "SYNTAX ", syntaxoid, syntaxlengthbuf,
  1471. aew->enquote_sup_oc );
  1472. if (asip->asi_flags & SLAPI_ATTR_FLAG_SINGLE) {
  1473. outp += strcpy_count(outp, "SINGLE-VALUE ");
  1474. }
  1475. if ( !aew->schema_ds4x_compat ) {
  1476. if (asip->asi_flags & SLAPI_ATTR_FLAG_COLLECTIVE ) {
  1477. outp += strcpy_count( outp, 1 + schema_collective_with_spaces );
  1478. }
  1479. if (asip->asi_flags & SLAPI_ATTR_FLAG_NOUSERMOD ) {
  1480. outp += strcpy_count( outp, 1 + schema_nousermod_with_spaces );
  1481. }
  1482. if (asip->asi_flags & SLAPI_ATTR_FLAG_DISTRIBUTED_OPERATION) {
  1483. outp += strcpy_count(outp, "USAGE distributedOperation ");
  1484. } else if (asip->asi_flags & SLAPI_ATTR_FLAG_DSA_OPERATION) {
  1485. outp += strcpy_count(outp, "USAGE dSAOperation ");
  1486. } else if (asip->asi_flags & SLAPI_ATTR_FLAG_OPATTR) {
  1487. outp += strcpy_count(outp, "USAGE directoryOperation ");
  1488. }
  1489. outp += strcat_extensions( outp, asip->asi_extensions );
  1490. }
  1491. outp += strcpy_count(outp, ")");
  1492. val.bv_val = aew->psbAttrTypes->buffer;
  1493. val.bv_len = outp - aew->psbAttrTypes->buffer;
  1494. attrlist_merge(aew->attrs, "attributetypes", vals);
  1495. return ATTR_SYNTAX_ENUM_NEXT;
  1496. }
  1497. struct syntax_enum_wrapper {
  1498. Slapi_Attr **attrs;
  1499. struct sizedbuffer *psbSyntaxDescription;
  1500. };
  1501. static int
  1502. schema_syntax_enum_callback(char **names, Slapi_PluginDesc *plugindesc,
  1503. void *arg)
  1504. {
  1505. struct syntax_enum_wrapper *sew = (struct syntax_enum_wrapper *)arg;
  1506. char *oid, *desc;
  1507. int i;
  1508. struct berval val;
  1509. struct berval *vals[2] = {0, 0};
  1510. vals[0] = &val;
  1511. oid = NULL;
  1512. if ( names != NULL ) {
  1513. for ( i = 0; names[i] != NULL; ++i ) {
  1514. if ( isdigit( names[i][0] )) {
  1515. oid = names[i];
  1516. break;
  1517. }
  1518. }
  1519. }
  1520. if ( oid == NULL ) { /* must have an OID */
  1521. LDAPDebug(LDAP_DEBUG_ANY, "Error: no OID found in"
  1522. " schema_syntax_enum_callback for syntax %s\n",
  1523. ( names == NULL ) ? "unknown" : names[0], 0, 0);
  1524. return 1;
  1525. }
  1526. desc = names[0]; /* by convention, the first name is the "official" one */
  1527. /*
  1528. * RFC 2252 section 4.3.3 Syntax Description says:
  1529. *
  1530. * The following BNF may be used to associate a short description with a
  1531. * syntax OBJECT IDENTIFIER. Implementors should note that future
  1532. * versions of this document may expand this definition to include
  1533. * additional terms. Terms whose identifier begins with "X-" are
  1534. * reserved for private experiments, and MUST be followed by a
  1535. * <qdstrings>.
  1536. *
  1537. * SyntaxDescription = "(" whsp
  1538. * numericoid whsp
  1539. * [ "DESC" qdstring ]
  1540. * whsp ")"
  1541. *
  1542. * And section 5.3.1 ldapSyntaxes says:
  1543. *
  1544. * Servers MAY use this attribute to list the syntaxes which are
  1545. * implemented. Each value corresponds to one syntax.
  1546. *
  1547. * ( 1.3.6.1.4.1.1466.101.120.16 NAME 'ldapSyntaxes'
  1548. * EQUALITY objectIdentifierFirstComponentMatch
  1549. * SYNTAX 1.3.6.1.4.1.1466.115.121.1.54 USAGE directoryOperation )
  1550. */
  1551. if ( desc == NULL ) {
  1552. /* allocate enough room for "( )" and '\0' at end */
  1553. sizedbuffer_allocate(sew->psbSyntaxDescription, strlen(oid) + 5);
  1554. sprintf(sew->psbSyntaxDescription->buffer, "( %s )", oid );
  1555. } else {
  1556. /* allocate enough room for "( ) DESC '' " and '\0' at end */
  1557. sizedbuffer_allocate(sew->psbSyntaxDescription,
  1558. strlen(oid) + strlen(desc) + 13);
  1559. sprintf(sew->psbSyntaxDescription->buffer, "( %s DESC '%s' )",
  1560. oid, desc );
  1561. }
  1562. val.bv_val = sew->psbSyntaxDescription->buffer;
  1563. val.bv_len = strlen(sew->psbSyntaxDescription->buffer);
  1564. attrlist_merge(sew->attrs, "ldapSyntaxes", vals);
  1565. return 1;
  1566. }
  1567. struct listargs{
  1568. char **attrs;
  1569. unsigned long flag;
  1570. };
  1571. static int
  1572. schema_list_attributes_callback(struct asyntaxinfo *asi, void *arg)
  1573. {
  1574. struct listargs *aew = (struct listargs *)arg;
  1575. if (!asi) {
  1576. LDAPDebug(LDAP_DEBUG_ANY, "Error: no attribute types in schema_list_attributes_callback\n",
  1577. 0, 0, 0);
  1578. return ATTR_SYNTAX_ENUM_NEXT;
  1579. }
  1580. if (aew->flag && (asi->asi_flags & aew->flag)) {
  1581. #if defined(USE_OLD_UNHASHED)
  1582. /* skip unhashed password */
  1583. if (!is_type_forbidden(asi->asi_name)) {
  1584. #endif
  1585. charray_add(&aew->attrs, slapi_ch_strdup(asi->asi_name));
  1586. if (NULL != asi->asi_aliases) {
  1587. int i;
  1588. for ( i = 0; asi->asi_aliases[i] != NULL; ++i ) {
  1589. charray_add(&aew->attrs,
  1590. slapi_ch_strdup(asi->asi_aliases[i]));
  1591. }
  1592. }
  1593. #if defined(USE_OLD_UNHASHED)
  1594. }
  1595. #endif
  1596. }
  1597. return ATTR_SYNTAX_ENUM_NEXT;
  1598. }
  1599. /* Return the list of attributes names matching attribute flags */
  1600. char **
  1601. slapi_schema_list_attribute_names(unsigned long flag)
  1602. {
  1603. struct listargs aew;
  1604. memset(&aew,0,sizeof(struct listargs));
  1605. aew.flag=flag;
  1606. attr_syntax_enumerate_attrs(schema_list_attributes_callback, &aew,
  1607. PR_FALSE);
  1608. return aew.attrs;
  1609. }
  1610. /*
  1611. * returntext is always at least SLAPI_DSE_RETURNTEXT_SIZE bytes in size.
  1612. */
  1613. int
  1614. read_schema_dse(
  1615. Slapi_PBlock *pb,
  1616. Slapi_Entry *pschema_info_e,
  1617. Slapi_Entry *entryAfter,
  1618. int *returncode,
  1619. char *returntext /* not used */,
  1620. void *arg /* not used */ )
  1621. {
  1622. struct berval val;
  1623. struct berval *vals[2];
  1624. struct objclass *oc;
  1625. struct matchingRuleList *mrl=NULL;
  1626. struct sizedbuffer *psbObjectClasses= sizedbuffer_construct(BUFSIZ);
  1627. struct sizedbuffer *psbAttrTypes= sizedbuffer_construct(BUFSIZ);
  1628. struct sizedbuffer *psbMatchingRule= sizedbuffer_construct(BUFSIZ);
  1629. struct sizedbuffer *psbSyntaxDescription = sizedbuffer_construct(BUFSIZ);
  1630. struct attr_enum_wrapper aew;
  1631. struct syntax_enum_wrapper sew;
  1632. const CSN *csn;
  1633. char *mr_desc, *mr_name, *oc_description;
  1634. char **allowed, **required;
  1635. PRUint32 schema_flags = 0;
  1636. int enquote_sup_oc = config_get_enquote_sup_oc();
  1637. int schema_ds4x_compat = config_get_ds4_compatible_schema();
  1638. int user_defined_only = 0;
  1639. int i;
  1640. vals[0] = &val;
  1641. vals[1] = NULL;
  1642. slapi_pblock_get(pb, SLAPI_SCHEMA_FLAGS, (void*)&schema_flags);
  1643. user_defined_only = (schema_flags & DSE_SCHEMA_USER_DEFINED_ONLY) ? 1 : 0;
  1644. attrlist_delete (&pschema_info_e->e_attrs, "objectclasses");
  1645. attrlist_delete (&pschema_info_e->e_attrs, "attributetypes");
  1646. attrlist_delete (&pschema_info_e->e_attrs, "matchingRules");
  1647. attrlist_delete (&pschema_info_e->e_attrs, "ldapSyntaxes");
  1648. /*
  1649. * attrlist_delete (&pschema_info_e->e_attrs, "matchingRuleUse");
  1650. */
  1651. schema_dse_lock_read();
  1652. oc_lock_read();
  1653. /* return the objectclasses */
  1654. for (oc = g_get_global_oc_nolock(); oc != NULL; oc = oc->oc_next)
  1655. {
  1656. size_t size= 0;
  1657. int need_extra_space = 1;
  1658. if (user_defined_only &&
  1659. !((oc->oc_flags & OC_FLAG_USER_OC) ||
  1660. (oc->oc_flags & OC_FLAG_REDEFINED_OC) ))
  1661. {
  1662. continue;
  1663. }
  1664. /*
  1665. * XXX: 256 is a magic number... it must be large enough to fit
  1666. * all of the fixed size items including description (DESC),
  1667. * kind (STRUCTURAL, AUXILIARY, or ABSTRACT), and the OBSOLETE flag.
  1668. */
  1669. if ( schema_ds4x_compat ) {
  1670. oc_description = (oc->oc_flags & OC_FLAG_STANDARD_OC) ?
  1671. OC_STANDARD_STRING : OC_USERDEF_STRING;
  1672. } else {
  1673. oc_description = oc->oc_desc;
  1674. }
  1675. size = 256+strlen_null_ok(oc->oc_oid) + strlen(oc->oc_name) +
  1676. strlen_null_ok(oc_description) + strcat_extensions( NULL, oc->oc_extensions );
  1677. required = schema_ds4x_compat ? oc->oc_required : oc->oc_orig_required;
  1678. if (required && required[0]) {
  1679. for (i = 0 ; required[i]; i++)
  1680. size+= 16 + strlen(required[i]);
  1681. }
  1682. allowed = schema_ds4x_compat ? oc->oc_allowed : oc->oc_orig_allowed;
  1683. if (allowed && allowed[0]) {
  1684. for (i = 0 ; allowed[i]; i++)
  1685. size+= 16 + strlen(allowed[i]);
  1686. }
  1687. sizedbuffer_allocate(psbObjectClasses,size);
  1688. /* put the OID and the NAME */
  1689. sprintf (psbObjectClasses->buffer, "( %s NAME '%s'", (oc->oc_oid) ? oc->oc_oid : "", oc->oc_name);
  1690. /* The DESC (description) is OPTIONAL */
  1691. if (oc_description) {
  1692. strcat(psbObjectClasses->buffer, " DESC '");
  1693. /*
  1694. * We want to list an empty description
  1695. * element if it was defined that way.
  1696. */
  1697. if (*oc_description) {
  1698. strcat(psbObjectClasses->buffer, oc_description);
  1699. }
  1700. strcat(psbObjectClasses->buffer, "'");
  1701. need_extra_space = 1;
  1702. }
  1703. /* put the OBSOLETE keyword */
  1704. if (!schema_ds4x_compat && (oc->oc_flags & OC_FLAG_OBSOLETE)) {
  1705. strcat(psbObjectClasses->buffer, schema_obsolete_with_spaces);
  1706. need_extra_space = 0;
  1707. }
  1708. /* put the SUP superior objectclass */
  1709. if (0 != strcasecmp(oc->oc_name, "top")) { /* top has no SUP */
  1710. /*
  1711. * Some AUXILIARY AND ABSTRACT objectclasses may not have a SUP either
  1712. * for compatability, every objectclass other than top must have a SUP
  1713. */
  1714. if (schema_ds4x_compat || (oc->oc_superior && *oc->oc_superior)) {
  1715. if (need_extra_space) {
  1716. strcat(psbObjectClasses->buffer, " ");
  1717. }
  1718. strcat(psbObjectClasses->buffer, "SUP ");
  1719. strcat(psbObjectClasses->buffer, (enquote_sup_oc ? "'" : ""));
  1720. strcat(psbObjectClasses->buffer, ((oc->oc_superior && *oc->oc_superior) ?
  1721. oc->oc_superior : "top"));
  1722. strcat(psbObjectClasses->buffer, (enquote_sup_oc ? "'" : ""));
  1723. need_extra_space = 1;
  1724. }
  1725. }
  1726. /* put the kind of objectclass */
  1727. if (schema_ds4x_compat) {
  1728. if (need_extra_space) {
  1729. strcat(psbObjectClasses->buffer, " ");
  1730. }
  1731. } else {
  1732. strcat(psbObjectClasses->buffer, schema_oc_kind_strings_with_spaces[oc->oc_kind]);
  1733. }
  1734. strcat_oids( psbObjectClasses->buffer, "MUST", required, schema_ds4x_compat );
  1735. strcat_oids( psbObjectClasses->buffer, "MAY", allowed, schema_ds4x_compat );
  1736. if ( !schema_ds4x_compat ) {
  1737. strcat_extensions( psbObjectClasses->buffer, oc->oc_extensions );
  1738. }
  1739. strcat( psbObjectClasses->buffer, ")");
  1740. val.bv_val = psbObjectClasses->buffer;
  1741. val.bv_len = strlen (psbObjectClasses->buffer);
  1742. attrlist_merge (&pschema_info_e->e_attrs, "objectclasses", vals);
  1743. }
  1744. oc_unlock();
  1745. /* now return the attrs */
  1746. aew.attrs = &pschema_info_e->e_attrs;
  1747. aew.enquote_sup_oc = enquote_sup_oc;
  1748. aew.psbAttrTypes = psbAttrTypes;
  1749. aew.user_defined_only = user_defined_only;
  1750. aew.schema_ds4x_compat = schema_ds4x_compat;
  1751. attr_syntax_enumerate_attrs(schema_attr_enum_callback, &aew, PR_FALSE);
  1752. /* return the set of matching rules we support */
  1753. for (mrl = g_get_global_mrl(); !user_defined_only && mrl != NULL; mrl = mrl->mrl_next) {
  1754. mr_name = mrl->mr_entry->mr_name ? mrl->mr_entry->mr_name : "";
  1755. mr_desc = mrl->mr_entry->mr_desc ? mrl->mr_entry->mr_desc : "";
  1756. sizedbuffer_allocate(psbMatchingRule,128 + strlen_null_ok(mrl->mr_entry->mr_oid) +
  1757. strlen(mr_name)+ strlen(mr_desc) + strlen_null_ok(mrl->mr_entry->mr_syntax));
  1758. if ( schema_ds4x_compat ) {
  1759. sprintf(psbMatchingRule->buffer,
  1760. "( %s NAME '%s' DESC '%s' SYNTAX %s%s%s )",
  1761. (mrl->mr_entry->mr_oid ? mrl->mr_entry->mr_oid : ""),
  1762. mr_name, mr_desc, enquote_sup_oc ? "'" : "",
  1763. mrl->mr_entry->mr_syntax ? mrl->mr_entry->mr_syntax : "" ,
  1764. enquote_sup_oc ? "'" : "");
  1765. } else if ( NULL != mrl->mr_entry->mr_oid &&
  1766. NULL != mrl->mr_entry->mr_syntax ){
  1767. char *p;
  1768. sprintf(psbMatchingRule->buffer, "( %s ", mrl->mr_entry->mr_oid );
  1769. p = psbMatchingRule->buffer + strlen(psbMatchingRule->buffer);
  1770. if ( *mr_name != '\0' ) {
  1771. sprintf(p, "NAME '%s' ", mr_name );
  1772. p += strlen(p);
  1773. }
  1774. if ( *mr_desc != '\0' ) {
  1775. sprintf(p, "DESC '%s' ", mr_desc );
  1776. p += strlen(p);
  1777. }
  1778. sprintf(p, "SYNTAX %s )", mrl->mr_entry->mr_syntax );
  1779. }
  1780. val.bv_val = psbMatchingRule->buffer;
  1781. val.bv_len = strlen (psbMatchingRule->buffer);
  1782. attrlist_merge (&pschema_info_e->e_attrs, "matchingRules", vals);
  1783. }
  1784. if ( !schema_ds4x_compat && !user_defined_only ) {
  1785. /* return the set of syntaxes we support */
  1786. sew.attrs = &pschema_info_e->e_attrs;
  1787. sew.psbSyntaxDescription = psbSyntaxDescription;
  1788. plugin_syntax_enumerate(schema_syntax_enum_callback, &sew);
  1789. }
  1790. csn = g_get_global_schema_csn();
  1791. if (NULL != csn) {
  1792. char csn_str[CSN_STRSIZE + 1];
  1793. csn_as_string(csn, PR_FALSE, csn_str);
  1794. slapi_entry_attr_delete(pschema_info_e, "nsschemacsn");
  1795. slapi_entry_add_string(pschema_info_e, "nsschemacsn", csn_str);
  1796. }
  1797. schema_dse_unlock();
  1798. sizedbuffer_destroy(psbObjectClasses);
  1799. sizedbuffer_destroy(psbAttrTypes);
  1800. sizedbuffer_destroy(psbMatchingRule);
  1801. sizedbuffer_destroy(psbSyntaxDescription);
  1802. *returncode= LDAP_SUCCESS;
  1803. return SLAPI_DSE_CALLBACK_OK;
  1804. }
  1805. /* helper for deleting mods (we do not want to be applied) from the mods array */
  1806. static void
  1807. mod_free(LDAPMod *mod)
  1808. {
  1809. ber_bvecfree(mod->mod_bvalues);
  1810. slapi_ch_free((void**)&(mod->mod_type));
  1811. slapi_ch_free((void**)&mod);
  1812. }
  1813. /*
  1814. * modify_schema_dse: called by do_modify() when target is cn=schema
  1815. *
  1816. * Add/Delete attributes and objectclasses from the schema
  1817. * Supported mod_ops are LDAP_MOD_DELETE and LDAP_MOD_ADD
  1818. *
  1819. * Note that the in-memory DSE Slapi_Entry object does NOT hold the
  1820. * attributeTypes and objectClasses attributes -- it only holds
  1821. * non-schema related attributes such as aci.
  1822. *
  1823. * returntext is always at least SLAPI_DSE_RETURNTEXT_SIZE bytes in size.
  1824. */
  1825. int
  1826. modify_schema_dse (Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg)
  1827. {
  1828. int i, rc= SLAPI_DSE_CALLBACK_OK; /* default is to apply changes to the DSE */
  1829. char *schema_dse_attr_name;
  1830. LDAPMod **mods = NULL;
  1831. int num_mods = 0; /* count the number of mods */
  1832. int schema_ds4x_compat = config_get_ds4_compatible_schema();
  1833. int schema_modify_enabled = config_get_schemamod();
  1834. int reapply_mods = 0;
  1835. int is_replicated_operation = 0;
  1836. int is_internal_operation = 0;
  1837. Slapi_Operation *operation = NULL;
  1838. if (!schema_modify_enabled) {
  1839. *returncode = LDAP_UNWILLING_TO_PERFORM;
  1840. schema_create_errormsg( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  1841. schema_errprefix_generic, "Generic",
  1842. "schema update is disabled" );
  1843. return (SLAPI_DSE_CALLBACK_ERROR);
  1844. }
  1845. slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
  1846. slapi_pblock_get( pb, SLAPI_IS_REPLICATED_OPERATION, &is_replicated_operation);
  1847. slapi_pblock_get( pb, SLAPI_OPERATION, &operation);
  1848. is_internal_operation = slapi_operation_is_flag_set(operation, SLAPI_OP_FLAG_INTERNAL);
  1849. /* In case we receive a schema from a supplier, check if we can accept it
  1850. * (it is a superset of our own schema).
  1851. * If it is not a superset, pick up what could extend our schema and return
  1852. */
  1853. if (is_replicated_operation) {
  1854. char *attr_name = NULL;
  1855. struct schema_mods_indexes *at_list = NULL;
  1856. struct schema_mods_indexes *oc_list = NULL;
  1857. if (!check_replicated_schema(mods, OC_CONSUMER, &attr_name)) {
  1858. /* we will refuse to apply this schema
  1859. * Try to capture in it what would extends our own schema
  1860. */
  1861. modify_schema_get_new_definitions(pb, mods, &at_list, &oc_list);
  1862. if (at_list) {
  1863. modify_schema_apply_new_definitions("attributetypes", at_list);
  1864. }
  1865. if (oc_list) {
  1866. modify_schema_apply_new_definitions("objectclasses", oc_list);
  1867. }
  1868. /* No need to hold the lock for these list that are local */
  1869. modify_schema_free_new_definitions(at_list);
  1870. modify_schema_free_new_definitions(oc_list);
  1871. /* now return, we will not apply that schema */
  1872. schema_create_errormsg( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  1873. schema_errprefix_generic, attr_name,
  1874. "Replace is not possible, local consumer schema is a superset of the supplier" );
  1875. slapi_log_error(SLAPI_LOG_FATAL, "schema",
  1876. "[C] Local %s must not be overwritten (set replication log for additional info)\n",
  1877. attr_name);
  1878. *returncode = LDAP_UNWILLING_TO_PERFORM;
  1879. return (SLAPI_DSE_CALLBACK_ERROR);
  1880. }
  1881. }
  1882. schema_dse_lock_write();
  1883. /*
  1884. * Process each modification. Stop as soon as we hit an error.
  1885. *
  1886. * XXXmcs: known bugs: we don't operate on a copy of the schema, so it
  1887. * is possible for some schema changes to be made but not all of them.
  1888. * True for DS 4.x as well, although it tried to keep going even after
  1889. * an error was detected (which was very wrong).
  1890. */
  1891. for (i = 0; rc == SLAPI_DSE_CALLBACK_OK && mods && mods[i]; i++) {
  1892. schema_dse_attr_name = (char *) mods[i]->mod_type;
  1893. num_mods++; /* incr the number of mods */
  1894. /*
  1895. * skip attribute types that we do not recognize (the DSE code will
  1896. * handle them).
  1897. */
  1898. if ( !schema_type_is_interesting( schema_dse_attr_name )) {
  1899. continue;
  1900. }
  1901. /*
  1902. * Delete an objectclass or attribute
  1903. */
  1904. if (SLAPI_IS_MOD_DELETE(mods[i]->mod_op)) {
  1905. if (strcasecmp (mods[i]->mod_type, "objectclasses") == 0) {
  1906. *returncode = schema_delete_objectclasses (entryBefore, mods[i],
  1907. returntext, SLAPI_DSE_RETURNTEXT_SIZE, schema_ds4x_compat, is_internal_operation);
  1908. }
  1909. else if (strcasecmp (mods[i]->mod_type, "attributetypes") == 0) {
  1910. *returncode = schema_delete_attributes (entryBefore, mods[i],
  1911. returntext, SLAPI_DSE_RETURNTEXT_SIZE, is_internal_operation);
  1912. }
  1913. else {
  1914. *returncode= LDAP_NO_SUCH_ATTRIBUTE;
  1915. schema_create_errormsg( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  1916. schema_errprefix_generic, mods[i]->mod_type,
  1917. "Only object classes and attribute types may be deleted" );
  1918. }
  1919. if ( LDAP_SUCCESS != *returncode ) {
  1920. rc= SLAPI_DSE_CALLBACK_ERROR;
  1921. } else {
  1922. reapply_mods = 1;
  1923. }
  1924. }
  1925. /*
  1926. * Replace an objectclass,attribute, or schema CSN
  1927. */
  1928. else if (SLAPI_IS_MOD_REPLACE(mods[i]->mod_op)) {
  1929. int replace_allowed = 0;
  1930. slapdFrontendConfig_t *slapdFrontendConfig;
  1931. slapdFrontendConfig = getFrontendConfig();
  1932. CFG_LOCK_READ( slapdFrontendConfig );
  1933. if ( 0 == strcasecmp( slapdFrontendConfig->schemareplace,
  1934. CONFIG_SCHEMAREPLACE_STR_ON )) {
  1935. replace_allowed = 1;
  1936. } else if ( 0 == strcasecmp( slapdFrontendConfig->schemareplace,
  1937. CONFIG_SCHEMAREPLACE_STR_REPLICATION_ONLY )) {
  1938. replace_allowed = is_replicated_operation;
  1939. }
  1940. CFG_UNLOCK_READ( slapdFrontendConfig );
  1941. if ( !replace_allowed ) {
  1942. *returncode= LDAP_UNWILLING_TO_PERFORM;
  1943. schema_create_errormsg( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  1944. schema_errprefix_generic, mods[i]->mod_type,
  1945. "Replace is not allowed on the subschema subentry" );
  1946. slapi_log_error(SLAPI_LOG_REPL, "schema", "modify_schema_dse: Replace is not allowed on the subschema subentry\n");
  1947. rc = SLAPI_DSE_CALLBACK_ERROR;
  1948. } else {
  1949. if (strcasecmp (mods[i]->mod_type, "attributetypes") == 0) {
  1950. /*
  1951. * Replace all attributetypes
  1952. * It has already been checked that if it was a replicated schema
  1953. * it is a superset of the current schema. That is fine to apply the mods
  1954. */
  1955. *returncode = schema_replace_attributes( pb, mods[i], returntext,
  1956. SLAPI_DSE_RETURNTEXT_SIZE );
  1957. } else if (strcasecmp (mods[i]->mod_type, "objectclasses") == 0) {
  1958. /*
  1959. * Replace all objectclasses
  1960. * It has already been checked that if it was a replicated schema
  1961. * it is a superset of the current schema. That is fine to apply the mods
  1962. */
  1963. *returncode = schema_replace_objectclasses(pb, mods[i],
  1964. returntext, SLAPI_DSE_RETURNTEXT_SIZE);
  1965. } else if (strcasecmp (mods[i]->mod_type, "nsschemacsn") == 0) {
  1966. if (is_replicated_operation) {
  1967. /* Update the schema CSN */
  1968. if (mods[i]->mod_bvalues && mods[i]->mod_bvalues[0] &&
  1969. mods[i]->mod_bvalues[0]->bv_val &&
  1970. mods[i]->mod_bvalues[0]->bv_len > 0) {
  1971. char new_csn_string[CSN_STRSIZE + 1];
  1972. CSN *new_schema_csn;
  1973. memcpy(new_csn_string, mods[i]->mod_bvalues[0]->bv_val,
  1974. mods[i]->mod_bvalues[0]->bv_len);
  1975. new_csn_string[mods[i]->mod_bvalues[0]->bv_len] = '\0';
  1976. new_schema_csn = csn_new_by_string(new_csn_string);
  1977. if (NULL != new_schema_csn) {
  1978. g_set_global_schema_csn(new_schema_csn); /* csn is consumed */
  1979. }
  1980. }
  1981. }
  1982. } else {
  1983. *returncode= LDAP_UNWILLING_TO_PERFORM; /* XXXmcs: best error? */
  1984. schema_create_errormsg( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  1985. schema_errprefix_generic, mods[i]->mod_type,
  1986. "Only object classes and attribute types may be replaced" );
  1987. }
  1988. }
  1989. if ( LDAP_SUCCESS != *returncode ) {
  1990. rc= SLAPI_DSE_CALLBACK_ERROR;
  1991. } else {
  1992. reapply_mods = 1; /* we have at least some modifications we need to reapply */
  1993. }
  1994. }
  1995. /*
  1996. * Add an objectclass or attribute
  1997. */
  1998. else if (SLAPI_IS_MOD_ADD(mods[i]->mod_op)) {
  1999. if (strcasecmp (mods[i]->mod_type, "attributetypes") == 0) {
  2000. /*
  2001. * Add a new attribute
  2002. */
  2003. *returncode = schema_add_attribute ( pb, mods[i], returntext,
  2004. SLAPI_DSE_RETURNTEXT_SIZE, schema_ds4x_compat );
  2005. }
  2006. else if (strcasecmp (mods[i]->mod_type, "objectclasses") == 0) {
  2007. /*
  2008. * Add a new objectclass
  2009. */
  2010. *returncode = schema_add_objectclass ( pb, mods[i], returntext,
  2011. SLAPI_DSE_RETURNTEXT_SIZE, schema_ds4x_compat);
  2012. }
  2013. else {
  2014. if ( schema_ds4x_compat ) {
  2015. *returncode= LDAP_NO_SUCH_ATTRIBUTE;
  2016. } else {
  2017. *returncode= LDAP_UNWILLING_TO_PERFORM; /* XXXmcs: best error? */
  2018. }
  2019. schema_create_errormsg( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  2020. schema_errprefix_generic, mods[i]->mod_type,
  2021. "Only object classes and attribute types may be added" );
  2022. }
  2023. if ( LDAP_SUCCESS != *returncode ) {
  2024. rc= SLAPI_DSE_CALLBACK_ERROR;
  2025. } else {
  2026. reapply_mods = 1; /* we have at least some modifications we need to reapply */
  2027. }
  2028. }
  2029. /*
  2030. ** No value was specified to modify, the user probably tried
  2031. ** to delete all attributetypes or all objectclasses, which
  2032. ** isn't allowed
  2033. */
  2034. if (!mods[i]->mod_vals.modv_strvals)
  2035. {
  2036. if ( schema_ds4x_compat ) {
  2037. *returncode= LDAP_INVALID_SYNTAX;
  2038. } else {
  2039. *returncode= LDAP_UNWILLING_TO_PERFORM; /* XXXmcs: best error? */
  2040. }
  2041. schema_create_errormsg( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  2042. schema_errprefix_generic, mods[i]->mod_type,
  2043. "No target attribute type or object class specified" );
  2044. rc= SLAPI_DSE_CALLBACK_ERROR;
  2045. }
  2046. }
  2047. if(rc==SLAPI_DSE_CALLBACK_OK && reapply_mods)
  2048. {
  2049. CSN *new_schema_csn;
  2050. int newindex = 0; /* mods array index */
  2051. /* tell the "unholy" dse_modify code to reapply the mods and use
  2052. that result instead of the initial result; we must remove the attributes
  2053. we manage in this code from the mods
  2054. */
  2055. slapi_pblock_set(pb, SLAPI_DSE_REAPPLY_MODS, (void *)&reapply_mods);
  2056. /* because we are reapplying the mods, we want the entryAfter to
  2057. look just like the entryBefore, except that "our" attributes
  2058. will have been removed
  2059. */
  2060. /* delete the mods from the mods array */
  2061. for (i = 0; i < num_mods ; i++) {
  2062. const char *attrname = mods[i]->mod_type;
  2063. /* delete this attr from the entry */
  2064. slapi_entry_attr_delete(entryAfter, attrname);
  2065. if ( schema_type_is_interesting( attrname )) {
  2066. mod_free(mods[i]);
  2067. mods[i] = NULL;
  2068. } else {
  2069. /* add the original value of the attr back to the entry after */
  2070. Slapi_Attr *origattr = NULL;
  2071. Slapi_ValueSet *origvalues = NULL;
  2072. slapi_entry_attr_find(entryBefore, attrname, &origattr);
  2073. if (NULL != origattr) {
  2074. slapi_attr_get_valueset(origattr, &origvalues);
  2075. if (NULL != origvalues) {
  2076. slapi_entry_add_valueset(entryAfter, attrname, origvalues);
  2077. slapi_valueset_free(origvalues);
  2078. }
  2079. }
  2080. mods[newindex++] = mods[i];
  2081. }
  2082. }
  2083. mods[newindex] = NULL;
  2084. /*
  2085. * Since we successfully updated the schema, we need to generate
  2086. * a new schema CSN for non-replicated operations.
  2087. */
  2088. /* XXXmcs: I wonder if we should update the schema CSN even when no
  2089. * attribute types or OCs were changed? That way, an administrator
  2090. * could force schema replication to occur by submitting a modify
  2091. * operation that did not really do anything, such as:
  2092. *
  2093. * dn:cn=schema
  2094. * changetype:modify
  2095. * replace:cn
  2096. * cn:schema
  2097. */
  2098. if (!is_replicated_operation)
  2099. {
  2100. new_schema_csn = csn_new();
  2101. if (NULL != new_schema_csn) {
  2102. char csn_str[CSN_STRSIZE + 1];
  2103. csn_set_replicaid(new_schema_csn, 0);
  2104. csn_set_time(new_schema_csn, current_time());
  2105. g_set_global_schema_csn(new_schema_csn);
  2106. slapi_entry_attr_delete(entryBefore, "nsschemacsn");
  2107. csn_as_string(new_schema_csn, PR_FALSE, csn_str);
  2108. slapi_entry_add_string(entryBefore, "nsschemacsn", csn_str);
  2109. }
  2110. }
  2111. }
  2112. schema_dse_unlock();
  2113. return rc;
  2114. }
  2115. CSN *
  2116. dup_global_schema_csn()
  2117. {
  2118. CSN *schema_csn;
  2119. schema_dse_lock_read();
  2120. schema_csn = csn_dup ( g_get_global_schema_csn() );
  2121. schema_dse_unlock();
  2122. return schema_csn;
  2123. }
  2124. /*
  2125. * Remove all attribute types and objectclasses from the entry and
  2126. * then add back the user defined ones based on the contents of the
  2127. * schema hash tables.
  2128. *
  2129. * Returns SLAPI_DSE_CALLBACK_OK is all goes well.
  2130. *
  2131. * returntext is always at least SLAPI_DSE_RETURNTEXT_SIZE bytes in size.
  2132. */
  2133. static int
  2134. refresh_user_defined_schema( Slapi_PBlock *pb, Slapi_Entry *pschema_info_e, Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg /* not used */ )
  2135. {
  2136. int rc;
  2137. Slapi_PBlock *mypbptr = pb;
  2138. Slapi_PBlock mypb;
  2139. const CSN *schema_csn;
  2140. PRUint32 schema_flags = DSE_SCHEMA_USER_DEFINED_ONLY;
  2141. pblock_init(&mypb);
  2142. slapi_entry_attr_delete( pschema_info_e, "objectclasses");
  2143. slapi_entry_attr_delete( pschema_info_e, "attributetypes");
  2144. /* for write callbacks, no pb is supplied, so use our own */
  2145. if (!mypbptr) {
  2146. mypbptr = &mypb;
  2147. }
  2148. slapi_pblock_set(mypbptr, SLAPI_SCHEMA_FLAGS, &schema_flags);
  2149. rc = read_schema_dse(mypbptr, pschema_info_e, NULL, returncode, returntext, NULL);
  2150. schema_csn = g_get_global_schema_csn();
  2151. if (NULL != schema_csn) {
  2152. char csn_str[CSN_STRSIZE + 1];
  2153. slapi_entry_attr_delete(pschema_info_e, "nsschemacsn");
  2154. csn_as_string(schema_csn, PR_FALSE, csn_str);
  2155. slapi_entry_add_string(pschema_info_e, "nsschemacsn", csn_str);
  2156. }
  2157. pblock_done(&mypb);
  2158. return rc;
  2159. }
  2160. /* oc_add_nolock
  2161. * Add the objectClass newoc to the global list of objectclasses
  2162. */
  2163. static void
  2164. oc_add_nolock(struct objclass *newoc)
  2165. {
  2166. struct objclass *poc;
  2167. poc = g_get_global_oc_nolock();
  2168. if ( NULL == poc ) {
  2169. g_set_global_oc_nolock(newoc);
  2170. } else {
  2171. for ( ; (poc != NULL) && (poc->oc_next != NULL); poc = poc->oc_next) {
  2172. ;
  2173. }
  2174. poc->oc_next = newoc;
  2175. newoc->oc_next = NULL;
  2176. }
  2177. }
  2178. /*
  2179. * Delete one or more objectClasses from our internal data structure.
  2180. *
  2181. * Return an LDAP error code (LDAP_SUCCESS if all goes well).
  2182. * If an error occurs, explanatory text is copied into 'errorbuf'.
  2183. *
  2184. * This function should not send an LDAP result; that is the caller's
  2185. * responsibility.
  2186. */
  2187. static int
  2188. schema_delete_objectclasses( Slapi_Entry *entryBefore, LDAPMod *mod,
  2189. char *errorbuf, size_t errorbufsize, int schema_ds4x_compat, int is_internal_operation)
  2190. {
  2191. int i;
  2192. int rc = LDAP_SUCCESS; /* optimistic */
  2193. struct objclass *poc, *poc2, *delete_oc = NULL;
  2194. if ( NULL == mod->mod_bvalues ) {
  2195. if (is_internal_operation) {
  2196. slapi_log_error(SLAPI_LOG_REPL, "schema", "schema_delete_objectclasses: Remove all objectclass in Internal op\n");
  2197. } else {
  2198. schema_create_errormsg(errorbuf, errorbufsize, schema_errprefix_oc,
  2199. NULL, "Cannot remove all schema object classes");
  2200. return LDAP_UNWILLING_TO_PERFORM;
  2201. }
  2202. }
  2203. for (i = 0; mod->mod_bvalues && mod->mod_bvalues[i]; i++) {
  2204. if ( LDAP_SUCCESS != ( rc = parse_oc_str (
  2205. (const char *)mod->mod_bvalues[i]->bv_val, &delete_oc,
  2206. errorbuf, errorbufsize, 0, 0, schema_ds4x_compat, NULL))) {
  2207. return rc;
  2208. }
  2209. oc_lock_write();
  2210. if ((poc = oc_find_nolock(delete_oc->oc_name, NULL, PR_FALSE)) != NULL) {
  2211. /* check to see if any objectclasses inherit from this oc */
  2212. for (poc2 = g_get_global_oc_nolock(); poc2 != NULL; poc2 = poc2->oc_next) {
  2213. if (poc2->oc_superior &&
  2214. (strcasecmp (poc2->oc_superior, delete_oc->oc_name) == 0)) {
  2215. if (is_internal_operation) {
  2216. slapi_log_error(SLAPI_LOG_REPL, "schema", "schema_delete_objectclasses: Should not delete object class (%s) which has child object classes"
  2217. ". But accept it because it is internal operation\n",
  2218. delete_oc->oc_name);
  2219. } else {
  2220. schema_create_errormsg(errorbuf, errorbufsize, schema_errprefix_oc,
  2221. delete_oc->oc_name, "Cannot delete an object class"
  2222. " which has child object classes");
  2223. slapi_log_error(SLAPI_LOG_REPL, "schema", "schema_delete_objectclasses: Cannot delete an object class (%s) which has child object classes\n",
  2224. delete_oc->oc_name);
  2225. rc = LDAP_UNWILLING_TO_PERFORM;
  2226. goto unlock_and_return;
  2227. }
  2228. }
  2229. }
  2230. if ( (poc->oc_flags & OC_FLAG_STANDARD_OC) == 0) {
  2231. oc_delete_nolock (poc->oc_name);
  2232. }
  2233. else {
  2234. if (is_internal_operation) {
  2235. slapi_log_error(SLAPI_LOG_REPL, "schema", "schema_delete_objectclasses: Should not delete a standard object class (%s)"
  2236. ". But accept it because it is internal operation\n",
  2237. delete_oc->oc_name);
  2238. oc_delete_nolock (poc->oc_name);
  2239. } else {
  2240. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
  2241. delete_oc->oc_name, "Cannot delete a standard object class" );
  2242. slapi_log_error(SLAPI_LOG_REPL, "schema", "schema_delete_objectclasses: Cannot delete a standard object class (%s)\n",
  2243. delete_oc->oc_name);
  2244. rc = LDAP_UNWILLING_TO_PERFORM;
  2245. goto unlock_and_return;
  2246. }
  2247. }
  2248. }
  2249. else {
  2250. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
  2251. delete_oc->oc_name, "Is unknown. Cannot delete." );
  2252. rc = schema_ds4x_compat ? LDAP_NO_SUCH_OBJECT : LDAP_NO_SUCH_ATTRIBUTE;
  2253. goto unlock_and_return;
  2254. }
  2255. oc_free( &delete_oc );
  2256. oc_unlock();
  2257. }
  2258. return rc;
  2259. unlock_and_return:
  2260. oc_free( &delete_oc );
  2261. oc_unlock();
  2262. return rc;
  2263. }
  2264. static int
  2265. schema_return(int rc,struct sizedbuffer * psb1,struct sizedbuffer *psb2,struct sizedbuffer *psb3,struct sizedbuffer *psb4)
  2266. {
  2267. sizedbuffer_destroy(psb1);
  2268. sizedbuffer_destroy(psb2);
  2269. sizedbuffer_destroy(psb3);
  2270. sizedbuffer_destroy(psb4);
  2271. return rc;
  2272. }
  2273. /*
  2274. * Delete one or more attributeTypes from our internal data structure.
  2275. *
  2276. * Return an LDAP error code (LDAP_SUCCESS if all goes well).
  2277. * If an error occurs, explanatory text is copied into 'errorbuf'.
  2278. *
  2279. * This function should not send an LDAP result; that is the caller's
  2280. * responsibility.
  2281. */
  2282. static int
  2283. schema_delete_attributes ( Slapi_Entry *entryBefore, LDAPMod *mod,
  2284. char *errorbuf, size_t errorbufsize, int is_internal_operation)
  2285. {
  2286. char *attr_ldif, *oc_list_type = "";
  2287. asyntaxinfo *a;
  2288. struct objclass *oc = NULL;
  2289. int i, k, attr_in_use_by_an_oc = 0;
  2290. struct sizedbuffer *psbAttrName= sizedbuffer_construct(BUFSIZ);
  2291. struct sizedbuffer *psbAttrOid= sizedbuffer_construct(BUFSIZ);
  2292. struct sizedbuffer *psbAttrSyntax= sizedbuffer_construct(BUFSIZ);
  2293. if (NULL == mod->mod_bvalues) {
  2294. if (is_internal_operation) {
  2295. slapi_log_error(SLAPI_LOG_REPL, "schema", "schema_delete_attributes: Remove all attributetypes in Internal op\n");
  2296. } else {
  2297. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
  2298. NULL, "Cannot remove all schema attribute types" );
  2299. return schema_return(LDAP_UNWILLING_TO_PERFORM,psbAttrOid,psbAttrName,
  2300. psbAttrSyntax,NULL);
  2301. }
  2302. }
  2303. for (i = 0; mod->mod_bvalues && mod->mod_bvalues[i]; i++) {
  2304. attr_ldif =(char *) mod->mod_bvalues[i]->bv_val;
  2305. /* normalize the attr ldif */
  2306. for ( k = 0; attr_ldif[k]; k++) {
  2307. if (attr_ldif[k] == '\'' ||
  2308. attr_ldif[k] == '(' ||
  2309. attr_ldif[k] == ')' ) {
  2310. attr_ldif[k] = ' ';
  2311. }
  2312. attr_ldif[k] = tolower (attr_ldif[k]);
  2313. }
  2314. sizedbuffer_allocate(psbAttrName,strlen(attr_ldif));
  2315. sizedbuffer_allocate(psbAttrOid,strlen(attr_ldif));
  2316. sizedbuffer_allocate(psbAttrSyntax,strlen(attr_ldif));
  2317. sscanf (attr_ldif, "%s name %s syntax %s",
  2318. psbAttrOid->buffer, psbAttrName->buffer, psbAttrSyntax->buffer);
  2319. if ((a = attr_syntax_get_by_name ( psbAttrName->buffer, 0 )) != NULL ) {
  2320. /* only modify attrs which were user defined */
  2321. if (a->asi_flags & SLAPI_ATTR_FLAG_STD_ATTR) {
  2322. if (is_internal_operation) {
  2323. slapi_log_error(SLAPI_LOG_REPL, "schema", "schema_delete_attributes: Should not delete a standard attribute type (%s)"
  2324. ". But accept it because it is internal operation\n",
  2325. psbAttrName->buffer);
  2326. } else {
  2327. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
  2328. psbAttrName->buffer,
  2329. "Cannot delete a standard attribute type");
  2330. slapi_log_error(SLAPI_LOG_REPL, "schema", "schema_delete_attributes: Cannot delete a standard attribute type (%s)\n",
  2331. psbAttrName->buffer);
  2332. attr_syntax_return(a);
  2333. return schema_return(LDAP_UNWILLING_TO_PERFORM, psbAttrOid, psbAttrName,
  2334. psbAttrSyntax, NULL);
  2335. }
  2336. }
  2337. /* Do not allow deletion if referenced by an object class. */
  2338. oc_lock_read();
  2339. attr_in_use_by_an_oc = 0;
  2340. for ( oc = g_get_global_oc_nolock(); oc != NULL; oc = oc->oc_next ) {
  2341. if (NULL != oc->oc_required) {
  2342. for ( k = 0; oc->oc_required[k] != NULL; k++ ) {
  2343. if ( 0 == slapi_attr_type_cmp( oc->oc_required[k], a->asi_name,
  2344. SLAPI_TYPE_CMP_EXACT )) {
  2345. oc_list_type = "MUST";
  2346. attr_in_use_by_an_oc = 1;
  2347. break;
  2348. }
  2349. }
  2350. }
  2351. if (!attr_in_use_by_an_oc && NULL != oc->oc_allowed) {
  2352. for ( k = 0; oc->oc_allowed[k] != NULL; k++ ) {
  2353. if ( 0 == slapi_attr_type_cmp( oc->oc_allowed[k], a->asi_name,
  2354. SLAPI_TYPE_CMP_EXACT )) {
  2355. oc_list_type = "MAY";
  2356. attr_in_use_by_an_oc = 1;
  2357. break;
  2358. }
  2359. }
  2360. }
  2361. if (attr_in_use_by_an_oc) {
  2362. if (is_internal_operation) {
  2363. slapi_log_error(SLAPI_LOG_REPL, "schema", "schema_delete_attributes: Should not delete an attribute (%s) used in oc (%s)"
  2364. ". But accept it because it is internal operation\n",
  2365. oc_list_type, oc->oc_name);
  2366. } else {
  2367. schema_create_errormsg(errorbuf, errorbufsize, schema_errprefix_at,
  2368. psbAttrName->buffer, "Is included in the %s list for object class %s. Cannot delete.",
  2369. oc_list_type, oc->oc_name);
  2370. slapi_log_error(SLAPI_LOG_REPL, "schema", "schema_delete_attributes: Could delete an attribute (%s) used in oc (%s)"
  2371. ". But accept it because it is internal operation\n",
  2372. oc_list_type, oc->oc_name);
  2373. break;
  2374. }
  2375. }
  2376. }
  2377. oc_unlock();
  2378. if (attr_in_use_by_an_oc) {
  2379. if (is_internal_operation) {
  2380. slapi_log_error(SLAPI_LOG_REPL, "schema", "schema_delete_attributes: Should not delete an attribute used in oc"
  2381. ". But accept it because it is internal operation\n");
  2382. } else {
  2383. attr_syntax_return(a);
  2384. return schema_return(LDAP_UNWILLING_TO_PERFORM, psbAttrOid, psbAttrName,
  2385. psbAttrSyntax, NULL);
  2386. }
  2387. }
  2388. /* Delete it. */
  2389. attr_syntax_delete( a, 0 );
  2390. attr_syntax_return( a );
  2391. }
  2392. else {
  2393. /* unknown attribute */
  2394. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
  2395. psbAttrName->buffer, "Is unknown. Cannot delete." );
  2396. return schema_return(LDAP_NO_SUCH_ATTRIBUTE,psbAttrOid,psbAttrName,
  2397. psbAttrSyntax,NULL);
  2398. }
  2399. }
  2400. return schema_return(LDAP_SUCCESS,psbAttrOid,psbAttrName,psbAttrSyntax,
  2401. NULL);
  2402. }
  2403. static int
  2404. schema_add_attribute ( Slapi_PBlock *pb, LDAPMod *mod, char *errorbuf,
  2405. size_t errorbufsize, int schema_ds4x_compat )
  2406. {
  2407. int i;
  2408. char *attr_ldif;
  2409. /* LPXXX: Eventually, we should not allocate the buffers in parse_at_str
  2410. * for each attribute, but use the same buffer for all.
  2411. * This is not done yet, so it's useless to allocate buffers for nothing.
  2412. */
  2413. /* struct sizedbuffer *psbAttrName= sizedbuffer_construct(BUFSIZ); */
  2414. /* struct sizedbuffer *psbAttrOid= sizedbuffer_construct(BUFSIZ); */
  2415. /* struct sizedbuffer *psbAttrDesc= sizedbuffer_construct(BUFSIZ); */
  2416. /* struct sizedbuffer *psbAttrSyntax= sizedbuffer_construct(BUFSIZ); */
  2417. int status = 0;
  2418. for (i = 0; LDAP_SUCCESS == status && mod->mod_bvalues[i]; i++) {
  2419. PRUint32 nolock = 0; /* lock global resources during normal operation */
  2420. attr_ldif = (char *) mod->mod_bvalues[i]->bv_val;
  2421. status = parse_at_str(attr_ldif, NULL, errorbuf, errorbufsize,
  2422. nolock, 1 /* user defined */, schema_ds4x_compat, 1);
  2423. if ( LDAP_SUCCESS != status ) {
  2424. break; /* stop on first error */
  2425. }
  2426. }
  2427. /* free everything */
  2428. /* sizedbuffer_destroy(psbAttrOid); */
  2429. /* sizedbuffer_destroy(psbAttrName); */
  2430. /* sizedbuffer_destroy(psbAttrDesc); */
  2431. /* sizedbuffer_destroy(psbAttrSyntax); */
  2432. return status;
  2433. }
  2434. /*
  2435. * Returns an LDAP error code (LDAP_SUCCESS if all goes well)
  2436. */
  2437. static int
  2438. add_oc_internal(struct objclass *pnew_oc, char *errorbuf, size_t errorbufsize,
  2439. int schema_ds4x_compat, PRUint32 flags )
  2440. {
  2441. struct objclass *oldoc_by_name, *oldoc_by_oid, *psup_oc = NULL;
  2442. int redefined_oc = 0, rc=0;
  2443. asyntaxinfo *pasyntaxinfo = 0;
  2444. if (!(flags & DSE_SCHEMA_LOCKED))
  2445. oc_lock_write();
  2446. oldoc_by_name = oc_find_nolock (pnew_oc->oc_name, NULL, PR_FALSE);
  2447. oldoc_by_oid = oc_find_nolock (pnew_oc->oc_oid, NULL, PR_FALSE);
  2448. /* Check to see if the objectclass name and the objectclass oid are already
  2449. * in use by an existing objectclass. If an existing objectclass is already
  2450. * using the name or oid, the name and the oid should map to the same objectclass.
  2451. * Otherwise, return an error.
  2452. */
  2453. if ( oldoc_by_name != oldoc_by_oid ) {
  2454. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
  2455. pnew_oc->oc_name, "The name does not match the OID \"%s\". "
  2456. "Another object class is already using the name or OID.",
  2457. pnew_oc->oc_oid);
  2458. rc = LDAP_TYPE_OR_VALUE_EXISTS;
  2459. }
  2460. /*
  2461. * Set a flag so we know if we are updating an existing OC definition.
  2462. */
  2463. if ( !rc ) {
  2464. if ( NULL != oldoc_by_name ) {
  2465. redefined_oc = 1;
  2466. } else {
  2467. /*
  2468. * If we are not updating an existing OC, check that the new
  2469. * oid is not already in use.
  2470. */
  2471. if ( NULL != oldoc_by_oid ) {
  2472. schema_create_errormsg( errorbuf, errorbufsize,
  2473. schema_errprefix_oc, pnew_oc->oc_name,
  2474. "The OID \"%s\" is already used by the object class \"%s\"",
  2475. pnew_oc->oc_oid, oldoc_by_oid->oc_name);
  2476. rc = LDAP_TYPE_OR_VALUE_EXISTS;
  2477. }
  2478. }
  2479. }
  2480. /* check to see if the superior oc exists
  2481. * This is not enforced for internal op (when learning new schema
  2482. * definitions from a replication session)
  2483. */
  2484. if (!rc && pnew_oc->oc_superior &&
  2485. ((psup_oc = oc_find_nolock (pnew_oc->oc_superior, NULL, PR_FALSE)) == NULL)) {
  2486. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
  2487. pnew_oc->oc_name, "Superior object class \"%s\" does not exist",
  2488. pnew_oc->oc_superior);
  2489. rc = LDAP_TYPE_OR_VALUE_EXISTS;
  2490. }
  2491. /* inherit the attributes from the superior oc */
  2492. if (!rc && psup_oc ) {
  2493. if ( psup_oc->oc_required ) {
  2494. charray_merge( &pnew_oc->oc_required, psup_oc->oc_required, 1 );
  2495. }
  2496. if ( psup_oc->oc_allowed ) {
  2497. charray_merge ( &pnew_oc->oc_allowed, psup_oc->oc_allowed, 1 );
  2498. }
  2499. }
  2500. /* check to see if the oid is already in use by an attribute */
  2501. if (!rc && (pasyntaxinfo = attr_syntax_get_by_oid(pnew_oc->oc_oid, flags))) {
  2502. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
  2503. pnew_oc->oc_name,
  2504. "The OID \"%s\" is also used by the attribute type \"%s\"",
  2505. pnew_oc->oc_oid, pasyntaxinfo->asi_name);
  2506. rc = LDAP_TYPE_OR_VALUE_EXISTS;
  2507. attr_syntax_return( pasyntaxinfo );
  2508. }
  2509. /* check to see if the objectclass name is valid */
  2510. if (!rc && !(flags & DSE_SCHEMA_NO_CHECK) &&
  2511. schema_check_name ( pnew_oc->oc_name, PR_FALSE, errorbuf, errorbufsize )
  2512. == 0 ) {
  2513. rc = schema_ds4x_compat ? LDAP_OPERATIONS_ERROR : LDAP_INVALID_SYNTAX;
  2514. }
  2515. /* check to see if the oid is valid */
  2516. if (!rc && !(flags & DSE_SCHEMA_NO_CHECK))
  2517. {
  2518. struct sizedbuffer *psbOcOid, *psbOcName;
  2519. psbOcName = sizedbuffer_construct(strlen(pnew_oc->oc_name) + 1);
  2520. psbOcOid = sizedbuffer_construct(strlen(pnew_oc->oc_oid) + 1);
  2521. strcpy(psbOcName->buffer, pnew_oc->oc_name);
  2522. strcpy(psbOcOid->buffer, pnew_oc->oc_oid);
  2523. if (!schema_check_oid ( psbOcName->buffer, psbOcOid->buffer, PR_FALSE,
  2524. errorbuf, errorbufsize))
  2525. rc = schema_ds4x_compat ? LDAP_OPERATIONS_ERROR : LDAP_INVALID_SYNTAX;
  2526. sizedbuffer_destroy(psbOcName);
  2527. sizedbuffer_destroy(psbOcOid);
  2528. }
  2529. /* check to see if the oc's attributes are valid
  2530. * This is not checked if this is an internal operation (learning schema
  2531. * definitions from a replication session)
  2532. */
  2533. if (!rc && !(flags & DSE_SCHEMA_NO_CHECK) &&
  2534. schema_check_oc_attrs ( pnew_oc, errorbuf, errorbufsize,
  2535. 0 /* don't strip options */ ) == 0 ) {
  2536. rc = schema_ds4x_compat ? LDAP_OPERATIONS_ERROR : LDAP_INVALID_SYNTAX;
  2537. }
  2538. /* insert new objectclass exactly where the old one one in the linked list*/
  2539. if ( !rc && redefined_oc ) {
  2540. pnew_oc->oc_flags |= OC_FLAG_REDEFINED_OC;
  2541. rc=oc_replace_nolock( pnew_oc->oc_name, pnew_oc);
  2542. }
  2543. if (!rc && !redefined_oc ) {
  2544. oc_add_nolock(pnew_oc);
  2545. }
  2546. if (!rc && redefined_oc ) {
  2547. oc_update_inheritance_nolock( pnew_oc );
  2548. }
  2549. if (!(flags & DSE_SCHEMA_LOCKED))
  2550. oc_unlock();
  2551. return rc;
  2552. }
  2553. /*
  2554. * Process a replace modify suboperation for attributetypes.
  2555. *
  2556. * XXXmcs: At present, readonly (bundled) schema definitions can't be
  2557. * removed. If that is attempted, we just keep them without generating
  2558. * an error.
  2559. *
  2560. * Our algorithm is:
  2561. *
  2562. * Clear the "keep" flags on the all existing attr. definitions.
  2563. *
  2564. * For each replacement value:
  2565. * If the value exactly matches an existing schema definition,
  2566. * set that definition's keep flag.
  2567. *
  2568. * Else if the OID in the replacement value matches an existing
  2569. * definition, delete the old definition and add the new one. Set
  2570. * the keep flag on the newly added definition.
  2571. *
  2572. * Else add the new definition. Set the keep flag on the newly
  2573. * added definition.
  2574. *
  2575. * For each definition that is not flagged keep, delete.
  2576. *
  2577. * Clear all remaining "keep" flags.
  2578. *
  2579. * Note that replace was not supported at all before iDS 5.0.
  2580. */
  2581. static int
  2582. schema_replace_attributes ( Slapi_PBlock *pb, LDAPMod *mod, char *errorbuf,
  2583. size_t errorbufsize )
  2584. {
  2585. int i, rc = LDAP_SUCCESS;
  2586. struct asyntaxinfo *newasip, *oldasip;
  2587. PRUint32 schema_flags = 0;
  2588. if ( NULL == mod->mod_bvalues ) {
  2589. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
  2590. NULL, "Cannot remove all schema attribute types" );
  2591. return LDAP_UNWILLING_TO_PERFORM;
  2592. }
  2593. slapi_pblock_get(pb, SLAPI_SCHEMA_FLAGS, &schema_flags);
  2594. if (!(schema_flags & (DSE_SCHEMA_NO_LOAD|DSE_SCHEMA_NO_CHECK))) {
  2595. /* clear all of the "keep" flags unless it's from schema-reload */
  2596. attr_syntax_all_clear_flag( SLAPI_ATTR_FLAG_KEEP );
  2597. }
  2598. for ( i = 0; mod->mod_bvalues[i] != NULL; ++i ) {
  2599. if ( LDAP_SUCCESS != ( rc = parse_at_str( mod->mod_bvalues[i]->bv_val,
  2600. &newasip, errorbuf, errorbufsize, 0, 1, 0, 0 ))) {
  2601. goto clean_up_and_return;
  2602. }
  2603. /*
  2604. * Check for a match with an existing type and
  2605. * handle the various cases.
  2606. */
  2607. if ( NULL == ( oldasip =
  2608. attr_syntax_get_by_oid( newasip->asi_oid, 0 ))) {
  2609. /* new attribute type */
  2610. LDAPDebug( LDAP_DEBUG_TRACE, "schema_replace_attributes:"
  2611. " new type %s (OID %s)\n",
  2612. newasip->asi_name, newasip->asi_oid, 0 );
  2613. } else {
  2614. /* the name matches -- check the rest */
  2615. if ( attr_syntax_equal( newasip, oldasip )) {
  2616. /* unchanged attribute type -- just mark it as one to keep */
  2617. oldasip->asi_flags |= SLAPI_ATTR_FLAG_KEEP;
  2618. attr_syntax_free( newasip );
  2619. newasip = NULL;
  2620. } else {
  2621. /* modified attribute type */
  2622. LDAPDebug( LDAP_DEBUG_TRACE, "schema_replace_attributes:"
  2623. " replacing type %s (OID %s)\n",
  2624. newasip->asi_name, newasip->asi_oid, 0 );
  2625. /* flag for deletion */
  2626. attr_syntax_delete( oldasip, 0 );
  2627. }
  2628. attr_syntax_return( oldasip );
  2629. }
  2630. if ( NULL != newasip ) { /* add new or replacement definition */
  2631. rc = attr_syntax_add( newasip, 0 );
  2632. if ( LDAP_SUCCESS != rc ) {
  2633. schema_create_errormsg( errorbuf, errorbufsize,
  2634. schema_errprefix_at, newasip->asi_name,
  2635. "Could not be added (OID is \"%s\")",
  2636. newasip->asi_oid );
  2637. attr_syntax_free( newasip );
  2638. goto clean_up_and_return;
  2639. }
  2640. newasip->asi_flags |= SLAPI_ATTR_FLAG_KEEP;
  2641. }
  2642. }
  2643. /*
  2644. * Delete all of the definitions that are not marked "keep" or "standard".
  2645. *
  2646. * XXXmcs: we should consider reporting an error if any read only types
  2647. * remain....
  2648. */
  2649. attr_syntax_delete_all_not_flagged( SLAPI_ATTR_FLAG_KEEP |
  2650. SLAPI_ATTR_FLAG_STD_ATTR );
  2651. clean_up_and_return:
  2652. if (!(schema_flags & (DSE_SCHEMA_NO_LOAD|DSE_SCHEMA_NO_CHECK))) {
  2653. /* clear all of the "keep" flags unless it's from schema-reload */
  2654. attr_syntax_all_clear_flag( SLAPI_ATTR_FLAG_KEEP );
  2655. }
  2656. return rc;
  2657. }
  2658. static int
  2659. schema_add_objectclass ( Slapi_PBlock *pb, LDAPMod *mod, char *errorbuf,
  2660. size_t errorbufsize, int schema_ds4x_compat )
  2661. {
  2662. struct objclass *pnew_oc = NULL;
  2663. char *newoc_ldif;
  2664. int j, rc=0;
  2665. for (j = 0; mod->mod_bvalues[j]; j++) {
  2666. newoc_ldif = (char *) mod->mod_bvalues[j]->bv_val;
  2667. if ( LDAP_SUCCESS != (rc = parse_oc_str ( newoc_ldif, &pnew_oc,
  2668. errorbuf, errorbufsize, 0, 1 /* user defined */,
  2669. schema_ds4x_compat, NULL))) {
  2670. oc_free( &pnew_oc );
  2671. return rc;
  2672. }
  2673. if ( LDAP_SUCCESS != (rc = add_oc_internal(pnew_oc, errorbuf,
  2674. errorbufsize, schema_ds4x_compat, 0/* no restriction */))) {
  2675. oc_free( &pnew_oc );
  2676. return rc;
  2677. }
  2678. normalize_oc();
  2679. }
  2680. return LDAP_SUCCESS;
  2681. }
  2682. /*
  2683. * Process a replace modify suboperation for objectclasses.
  2684. *
  2685. * XXXmcs: At present, readonly (bundled) schema definitions can't be
  2686. * removed. If that is attempted, we just keep them without generating
  2687. * an error.
  2688. *
  2689. * Our algorithm is:
  2690. *
  2691. * Lock the global objectclass linked list.
  2692. *
  2693. * Create a new empty (temporary) linked list, initially empty.
  2694. *
  2695. * For each replacement value:
  2696. * If the value exactly matches an existing schema definition,
  2697. * move the existing definition from the current global list to the
  2698. * temporary list
  2699. *
  2700. * Else if the OID in the replacement value matches an existing
  2701. * definition, delete the old definition from the current global
  2702. * list and add the new one to the temporary list.
  2703. *
  2704. * Else add the new definition to the temporary list.
  2705. *
  2706. * Delete all definitions that remain on the current global list.
  2707. *
  2708. * Make the temporary list the current global list.
  2709. *
  2710. * Note that since the objectclass definitions are stored in a linked list,
  2711. * this algorithm is O(N * M) where N is the number of existing objectclass
  2712. * definitions and M is the number of replacement definitions.
  2713. * XXXmcs: Yuck. We should use a hash table for the OC definitions.
  2714. *
  2715. * Note that replace was not supported at all by DS versions prior to 5.0
  2716. */
  2717. static int
  2718. schema_replace_objectclasses ( Slapi_PBlock *pb, LDAPMod *mod, char *errorbuf,
  2719. size_t errorbufsize )
  2720. {
  2721. struct objclass *newocp, *curlisthead, *prevocp, *tmpocp;
  2722. struct objclass *newlisthead = NULL, *newlistend = NULL;
  2723. int i, rc = LDAP_SUCCESS;
  2724. if ( NULL == mod->mod_bvalues ) {
  2725. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
  2726. NULL, "Cannot remove all schema object classes" );
  2727. return LDAP_UNWILLING_TO_PERFORM;
  2728. }
  2729. oc_lock_write();
  2730. curlisthead = g_get_global_oc_nolock();
  2731. for ( i = 0; mod->mod_bvalues[i] != NULL; ++i ) {
  2732. struct objclass *addocp = NULL;
  2733. if ( LDAP_SUCCESS != ( rc = parse_oc_str( mod->mod_bvalues[i]->bv_val,
  2734. &newocp, errorbuf, errorbufsize, DSE_SCHEMA_NO_GLOCK,
  2735. 1 /* user defined */, 0 /* no DS 4.x compat issues */ , NULL))) {
  2736. rc = LDAP_INVALID_SYNTAX;
  2737. goto clean_up_and_return;
  2738. }
  2739. prevocp = NULL;
  2740. for ( tmpocp = curlisthead; tmpocp != NULL; tmpocp = tmpocp->oc_next ) {
  2741. if ( 0 == strcasecmp( tmpocp->oc_oid, newocp->oc_oid ) ) {
  2742. /* the names match -- remove from the current list */
  2743. if ( tmpocp == curlisthead ) {
  2744. curlisthead = tmpocp->oc_next;
  2745. /* The global oc list is scanned in parse_oc_str above,
  2746. if there are multiple objectclasses to be updated.
  2747. Needs to maintain the list dynamically. */
  2748. g_set_global_oc_nolock( curlisthead );
  2749. } else {
  2750. if (prevocp) prevocp->oc_next = tmpocp->oc_next;
  2751. }
  2752. tmpocp->oc_next = NULL;
  2753. /* check for a full match */
  2754. if ( oc_equal( tmpocp, newocp )) {
  2755. /* no changes: keep existing definition and discard new */
  2756. oc_free( &newocp );
  2757. addocp = tmpocp;
  2758. } else {
  2759. /* some differences: discard old and keep the new one */
  2760. oc_free( &tmpocp );
  2761. LDAPDebug( LDAP_DEBUG_TRACE, "schema_replace_objectclasses:"
  2762. " replacing object class %s (OID %s)\n",
  2763. newocp->oc_name, newocp->oc_oid, 0 );
  2764. addocp = newocp;
  2765. }
  2766. break; /* we found it -- exit the loop */
  2767. }
  2768. prevocp = tmpocp;
  2769. }
  2770. if ( NULL == addocp ) {
  2771. LDAPDebug( LDAP_DEBUG_TRACE, "schema_replace_objectclasses:"
  2772. " new object class %s (OID %s)\n",
  2773. newocp->oc_name, newocp->oc_oid, 0 );
  2774. addocp = newocp;
  2775. }
  2776. /* add the objectclass to the end of the new list */
  2777. if ( NULL != addocp ) {
  2778. if ( NULL == newlisthead ) {
  2779. newlisthead = addocp;
  2780. } else {
  2781. newlistend->oc_next = addocp;
  2782. }
  2783. newlistend = addocp;
  2784. }
  2785. }
  2786. clean_up_and_return:
  2787. if ( LDAP_SUCCESS == rc ) {
  2788. /*
  2789. * Delete all remaining OCs that are on the old list AND are not
  2790. * "standard" classes.
  2791. */
  2792. struct objclass *nextocp;
  2793. prevocp = NULL;
  2794. for ( tmpocp = curlisthead; tmpocp != NULL; tmpocp = nextocp ) {
  2795. if ( 0 == ( tmpocp->oc_flags & OC_FLAG_STANDARD_OC )) {
  2796. /* not a standard definition -- remove it */
  2797. if ( tmpocp == curlisthead ) {
  2798. curlisthead = tmpocp->oc_next;
  2799. } else {
  2800. if (prevocp) {
  2801. prevocp->oc_next = tmpocp->oc_next;
  2802. }
  2803. }
  2804. nextocp = tmpocp->oc_next;
  2805. oc_free( &tmpocp );
  2806. } else {
  2807. /*
  2808. * XXXmcs: we could generate an error, but for now we do not.
  2809. */
  2810. nextocp = tmpocp->oc_next;
  2811. prevocp = tmpocp;
  2812. #if 0
  2813. schema_create_errormsg( errorbuf, errorbufsize,
  2814. schema_errprefix_oc, tmpocp->oc_name,
  2815. "Cannot delete a standard object class" );
  2816. rc = LDAP_UNWILLING_TO_PERFORM;
  2817. break;
  2818. #endif
  2819. }
  2820. }
  2821. }
  2822. /*
  2823. * Combine the two lists by adding the new list to the end of the old
  2824. * one.
  2825. */
  2826. if ( NULL != curlisthead ) {
  2827. for ( tmpocp = curlisthead; tmpocp->oc_next != NULL;
  2828. tmpocp = tmpocp->oc_next ) {
  2829. ;/*NULL*/
  2830. }
  2831. tmpocp->oc_next = newlisthead;
  2832. newlisthead = curlisthead;
  2833. }
  2834. /*
  2835. * Install the new list as the global one, replacing the old one.
  2836. */
  2837. g_set_global_oc_nolock( newlisthead );
  2838. oc_unlock();
  2839. return rc;
  2840. }
  2841. schemaext *
  2842. schema_copy_extensions(schemaext *extensions)
  2843. {
  2844. schemaext *ext = NULL, *head = NULL;
  2845. while(extensions){
  2846. schemaext *newext = (schemaext *)slapi_ch_calloc(1, sizeof(schemaext));
  2847. newext->term = slapi_ch_strdup(extensions->term);
  2848. newext->values = charray_dup(extensions->values);
  2849. newext->value_count = extensions->value_count;
  2850. if(ext == NULL){
  2851. ext = newext;
  2852. head = newext;
  2853. } else {
  2854. ext->next = newext;
  2855. ext = newext;
  2856. }
  2857. extensions = extensions->next;
  2858. }
  2859. return head;
  2860. }
  2861. void
  2862. schema_free_extensions(schemaext *extensions)
  2863. {
  2864. if(extensions){
  2865. schemaext *prev;
  2866. while(extensions){
  2867. slapi_ch_free_string(&extensions->term);
  2868. charray_free(extensions->values);
  2869. prev = extensions;
  2870. extensions = extensions->next;
  2871. slapi_ch_free( (void **)&prev);
  2872. }
  2873. }
  2874. }
  2875. static void
  2876. oc_free( struct objclass **ocp )
  2877. {
  2878. struct objclass *oc;
  2879. if ( NULL != ocp && NULL != *ocp ) {
  2880. oc = *ocp;
  2881. slapi_ch_free( (void **)&oc->oc_name );
  2882. slapi_ch_free( (void **)&oc->oc_desc );
  2883. slapi_ch_free( (void **)&oc->oc_oid );
  2884. slapi_ch_free( (void **)&oc->oc_superior );
  2885. charray_free( oc->oc_required );
  2886. charray_free( oc->oc_allowed );
  2887. charray_free( oc->oc_orig_required );
  2888. charray_free( oc->oc_orig_allowed );
  2889. schema_free_extensions( oc->oc_extensions );
  2890. slapi_ch_free( (void **)&oc );
  2891. *ocp = NULL;
  2892. }
  2893. }
  2894. #if !defined (USE_OPENLDAP)
  2895. /*
  2896. * read_oc_ldif_return
  2897. * Free all the memory that read_oc_ldif() allocated, and return the retVal
  2898. *
  2899. * It's nice to do all the freeing in one spot, as read_oc_ldif() returns sideways
  2900. */
  2901. static int
  2902. read_oc_ldif_return( int retVal,
  2903. char *oid,
  2904. struct sizedbuffer *name,
  2905. char *sup,
  2906. char *desc )
  2907. {
  2908. slapi_ch_free((void **)&oid);
  2909. sizedbuffer_destroy( name );
  2910. slapi_ch_free((void **)&sup);
  2911. slapi_ch_free((void **)&desc);
  2912. return retVal;
  2913. }
  2914. /*
  2915. * read_oc_ldif
  2916. * Read the value of the objectclasses attribute in cn=schema, convert it
  2917. * into an objectclass struct.
  2918. *
  2919. * Arguments:
  2920. *
  2921. * input : value of objectclasses attribute to read
  2922. * oc : pointer write the objectclass to
  2923. * errorbuf : buffer to write any errors to
  2924. * is_user_defined : if non-zero, force objectclass to be user defined
  2925. * schema_flags : Any or none of the following bits could be set
  2926. * DSE_SCHEMA_NO_CHECK -- schema won't be checked
  2927. * DSE_SCHEMA_NO_GLOCK -- don't lock global resources
  2928. * DSE_SCHEMA_LOCKED -- already locked with
  2929. * reload_schemafile_lock;
  2930. * no further lock needed
  2931. * schema_ds4x_compat: if non-zero, act like Netscape DS 4.x
  2932. *
  2933. * Returns: an LDAP error code
  2934. *
  2935. * LDAP_SUCCESS if the objectclass was sucessfully read, the new
  2936. * objectclass will be written to oc
  2937. *
  2938. * All others: there was an error, an error message will
  2939. * be written to errorbuf
  2940. */
  2941. static int
  2942. read_oc_ldif ( const char *input, struct objclass **oc, char *errorbuf,
  2943. size_t errorbufsize, PRUint32 schema_flags, int is_user_defined,
  2944. int schema_ds4x_compat )
  2945. {
  2946. int i, j;
  2947. const char *pstart, *nextinput;
  2948. struct objclass *pnew_oc, *psup_oc;
  2949. char **RequiredAttrsArray, **AllowedAttrsArray;
  2950. char **OrigRequiredAttrsArray, **OrigAllowedAttrsArray;
  2951. char *pend, *pOcOid, *pOcSup, *pOcDesc;
  2952. struct sizedbuffer *psbOcName= sizedbuffer_construct(BUFSIZ);
  2953. PRUint8 kind, flags;
  2954. int invalid_syntax_error;
  2955. schema_strstr_fn_t keyword_strstr_fn;
  2956. schemaext *extensions = NULL;
  2957. /*
  2958. * From RFC 2252 section 4.4:
  2959. *
  2960. * ObjectClassDescription = "(" whsp
  2961. * numericoid whsp ; ObjectClass identifier
  2962. * [ "NAME" qdescrs ]
  2963. * [ "DESC" qdstring ]
  2964. * [ "OBSOLETE" whsp ]
  2965. * [ "SUP" oids ] ; Superior ObjectClasses
  2966. * [ ( "ABSTRACT" / "STRUCTURAL" / "AUXILIARY" ) whsp ]
  2967. * ; default structural
  2968. * [ "MUST" oids ] ; AttributeTypes
  2969. * [ "MAY" oids ] ; AttributeTypes
  2970. * whsp ")"
  2971. *
  2972. * XXXmcs: Our parsing technique is poor. In (Netscape) DS 4.12 and earlier
  2973. * releases, parsing was mostly done by looking anywhere within the input
  2974. * string for various keywords such as "MUST". But if, for example, a
  2975. * description contains the word "must", the parser would take assume that
  2976. * the tokens following the word were attribute types or OIDs. Bad news.
  2977. *
  2978. * In iDS 5.0 and later, we parse in order left to right and advance a
  2979. * pointer as we consume the input string (the nextinput variable). We
  2980. * also use a case-insensitive search when looking for keywords such as
  2981. * DESC. But the parser will still be fooled by sequences like:
  2982. *
  2983. * ( 1.2.3.4 NAME 'testOC' MUST ( DESC cn ) )
  2984. *
  2985. * Someday soon we will need to write a real parser.
  2986. *
  2987. * Compatibility notes: if schema_ds4x_compat is set, we:
  2988. * 1. always parse from the beginning of the string
  2989. * 2. use a case-insensitive compare when looking for keywords, e.g., MUST
  2990. */
  2991. if ( schema_ds4x_compat ) {
  2992. keyword_strstr_fn = PL_strcasestr;
  2993. invalid_syntax_error = LDAP_OPERATIONS_ERROR;
  2994. } else {
  2995. keyword_strstr_fn = PL_strstr;
  2996. invalid_syntax_error = LDAP_INVALID_SYNTAX;
  2997. }
  2998. flags = 0;
  2999. pOcOid = pOcSup = pOcDesc = NULL;
  3000. if ( NULL == input || '\0' == input[0] ) {
  3001. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc, NULL,
  3002. "One or more values are required for the objectClasses attribute" );
  3003. LDAPDebug ( LDAP_DEBUG_ANY, "NULL args passed to read_oc_ldif\n",0,0,0);
  3004. return read_oc_ldif_return( LDAP_OPERATIONS_ERROR, pOcOid, psbOcName,
  3005. pOcSup, pOcDesc );
  3006. }
  3007. nextinput = input;
  3008. /* look for the OID */
  3009. if ( NULL == ( pOcOid = get_tagged_oid( "(", &nextinput,
  3010. keyword_strstr_fn ))) {
  3011. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
  3012. input, "Value is malformed. It must include a \"(\"");
  3013. return read_oc_ldif_return( invalid_syntax_error, pOcOid, psbOcName,
  3014. pOcSup, pOcDesc );
  3015. }
  3016. if ( schema_ds4x_compat || ( strcasecmp(pOcOid, "NAME") == 0))
  3017. nextinput = input;
  3018. /* look for the NAME */
  3019. if ( (pstart = (*keyword_strstr_fn)(nextinput, "NAME '")) != NULL ) {
  3020. pstart += 6;
  3021. sizedbuffer_allocate(psbOcName,strlen(pstart)+1);
  3022. if ( sscanf ( pstart, "%s", psbOcName->buffer ) > 0 ) {
  3023. /* strip the trailing single quote */
  3024. if ( psbOcName->buffer[strlen(psbOcName->buffer)-1] == '\'' ) {
  3025. psbOcName->buffer[strlen(psbOcName->buffer)-1] = '\0';
  3026. nextinput = pstart + strlen(psbOcName->buffer) + 1;
  3027. } else {
  3028. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
  3029. input, "Value is malformed. It must include a single quote around"
  3030. " the name" );
  3031. return read_oc_ldif_return( invalid_syntax_error, pOcOid, psbOcName,
  3032. pOcSup, pOcDesc );
  3033. }
  3034. }
  3035. } else {
  3036. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
  3037. input, "Value is malformed. It must include a \"NAME '\"");
  3038. return read_oc_ldif_return( invalid_syntax_error, pOcOid, psbOcName,
  3039. pOcSup, pOcDesc );
  3040. }
  3041. /*
  3042. ** if the objectclass ldif doesn't have an OID, we'll make the oid
  3043. ** ocname-oid
  3044. */
  3045. if ( strcasecmp ( pOcOid, "NAME" ) == 0 ) {
  3046. slapi_ch_free_string( &pOcOid );
  3047. pOcOid = slapi_ch_smprintf("%s-oid", psbOcName->buffer );
  3048. }
  3049. if ( schema_ds4x_compat ) nextinput = input;
  3050. /* look for an optional DESCription */
  3051. if ( (pstart = (*keyword_strstr_fn) ( nextinput, " DESC '")) != NULL ) {
  3052. pstart += 7;
  3053. if (( pend = strchr( pstart, '\'' )) == NULL ) {
  3054. pend = (char *)(pstart + strlen(pstart));
  3055. }
  3056. pOcDesc = slapi_ch_malloc( pend - pstart + 1 );
  3057. memcpy( pOcDesc, pstart, pend - pstart );
  3058. pOcDesc[ pend - pstart ] = '\0';
  3059. nextinput = pend + 1;
  3060. }
  3061. if ( schema_ds4x_compat ) nextinput = input;
  3062. /* look for the optional OBSOLETE marker */
  3063. flags |= get_flag_keyword( schema_obsolete_with_spaces,
  3064. OC_FLAG_OBSOLETE, &nextinput, keyword_strstr_fn );
  3065. if (!(schema_flags & DSE_SCHEMA_NO_GLOCK)) {
  3066. oc_lock_read(); /* needed because we access the superior oc */
  3067. }
  3068. if ( schema_ds4x_compat ) nextinput = input;
  3069. /*
  3070. * Look for the superior objectclass. We first look for a parenthesized
  3071. * list and if not found we look for a simple OID.
  3072. *
  3073. * XXXmcs: Since we do not yet support multiple superior objectclasses, we
  3074. * just grab the first OID in a parenthesized list.
  3075. */
  3076. if ( NULL == ( pOcSup = get_tagged_oid( " SUP (", &nextinput,
  3077. keyword_strstr_fn ))) {
  3078. pOcSup = get_tagged_oid( " SUP ", &nextinput, keyword_strstr_fn );
  3079. }
  3080. psup_oc = oc_find_nolock ( pOcSup, NULL, PR_FALSE);
  3081. if ( schema_ds4x_compat ) nextinput = input;
  3082. /* look for the optional kind (ABSTRACT, STRUCTURAL, AUXILIARY) */
  3083. for ( i = 0; i < SCHEMA_OC_KIND_COUNT; ++i ) {
  3084. if ( NULL != ( pstart = (*keyword_strstr_fn)( nextinput,
  3085. schema_oc_kind_strings_with_spaces[i] ))) {
  3086. kind = i;
  3087. nextinput = pstart + strlen( schema_oc_kind_strings_with_spaces[i] ) - 1;
  3088. break;
  3089. }
  3090. }
  3091. if ( i >= SCHEMA_OC_KIND_COUNT ) { /* not found */
  3092. if ( NULL != psup_oc && OC_KIND_ABSTRACT != psup_oc->oc_kind ) {
  3093. /* inherit kind from superior class if not ABSTRACT */
  3094. kind = psup_oc->oc_kind;
  3095. } else {
  3096. /* according to RFC 2252, the default is structural */
  3097. kind = OC_KIND_STRUCTURAL;
  3098. }
  3099. }
  3100. if ( schema_ds4x_compat ) nextinput = input;
  3101. /* look for required attributes (MUST) */
  3102. if ( (pstart = (*keyword_strstr_fn) (nextinput, " MUST ")) != NULL ) {
  3103. char *pRequiredAttrs;
  3104. int saw_open_paren = 0;
  3105. pstart += 6;
  3106. pstart = skipWS( pstart ); /* skip past any extra white space */
  3107. if ( *pstart == '(' ) {
  3108. saw_open_paren = 1;
  3109. ++pstart;
  3110. }
  3111. pRequiredAttrs = slapi_ch_strdup ( pstart );
  3112. if ( saw_open_paren && (pend = strchr (pRequiredAttrs, ')')) != NULL ) {
  3113. *pend = '\0';
  3114. } else if ((pend = strchr (pRequiredAttrs, ' ' )) != NULL ) {
  3115. *pend = '\0';
  3116. } else {
  3117. pend = pRequiredAttrs + strlen(pRequiredAttrs); /* at end of string */
  3118. }
  3119. nextinput = pstart + ( pend - pRequiredAttrs );
  3120. RequiredAttrsArray = read_dollar_values (pRequiredAttrs);
  3121. slapi_ch_free((void**)&pRequiredAttrs);
  3122. } else {
  3123. RequiredAttrsArray = (char **) slapi_ch_malloc (1 * sizeof(char *)) ;
  3124. RequiredAttrsArray[0] = NULL;
  3125. }
  3126. if ( schema_ds4x_compat ) nextinput = input;
  3127. /* look for allowed attributes (MAY) */
  3128. if ( (pstart = (*keyword_strstr_fn) (nextinput, " MAY ")) != NULL ) {
  3129. char *pAllowedAttrs;
  3130. int saw_open_paren = 0;
  3131. pstart += 5;
  3132. pstart = skipWS( pstart ); /* skip past any extra white space */
  3133. if ( *pstart == '(' ) {
  3134. saw_open_paren = 1;
  3135. ++pstart;
  3136. }
  3137. pAllowedAttrs = slapi_ch_strdup ( pstart );
  3138. if ( saw_open_paren && (pend = strchr (pAllowedAttrs, ')')) != NULL ) {
  3139. *pend = '\0';
  3140. } else if ((pend = strchr (pAllowedAttrs, ' ' )) != NULL ) {
  3141. *pend = '\0';
  3142. } else {
  3143. pend = pAllowedAttrs + strlen(pAllowedAttrs); /* at end of string */
  3144. }
  3145. nextinput = pstart + ( pend - pAllowedAttrs );
  3146. AllowedAttrsArray = read_dollar_values (pAllowedAttrs);
  3147. slapi_ch_free((void**)&pAllowedAttrs);
  3148. } else {
  3149. AllowedAttrsArray = (char **) slapi_ch_malloc (1 * sizeof(char *)) ;
  3150. AllowedAttrsArray[0] = NULL;
  3151. }
  3152. if ( schema_ds4x_compat ) nextinput = input;
  3153. /* look for X-ORIGIN list */
  3154. if (is_user_defined) {
  3155. /* add X-ORIGIN 'user defined' */
  3156. extensions = parse_extensions( nextinput, schema_user_defined_origin );
  3157. flags |= OC_FLAG_USER_OC;
  3158. } else {
  3159. /* add nothing */
  3160. extensions = parse_extensions( nextinput, NULL );
  3161. flags |= OC_FLAG_STANDARD_OC;
  3162. }
  3163. /* generate OrigRequiredAttrsArray and OrigAllowedAttrsArray */
  3164. if (psup_oc) {
  3165. int found_it;
  3166. OrigRequiredAttrsArray = (char **) slapi_ch_malloc (1 * sizeof(char *)) ;
  3167. OrigRequiredAttrsArray[0] = NULL;
  3168. OrigAllowedAttrsArray = (char **) slapi_ch_malloc (1 * sizeof(char *)) ;
  3169. OrigAllowedAttrsArray[0] = NULL;
  3170. if (psup_oc->oc_required) {
  3171. for (i = 0; RequiredAttrsArray[i]; i++) {
  3172. for (j = 0, found_it = 0; psup_oc->oc_required[j]; j++) {
  3173. if (strcasecmp (psup_oc->oc_required[j], RequiredAttrsArray[i]) == 0) {
  3174. found_it = 1;
  3175. }
  3176. }
  3177. if (!found_it) {
  3178. charray_add (&OrigRequiredAttrsArray, slapi_ch_strdup ( RequiredAttrsArray[i] ) );
  3179. }
  3180. }
  3181. }
  3182. if (psup_oc->oc_allowed) {
  3183. for (i = 0; AllowedAttrsArray[i]; i++) {
  3184. for (j = 0, found_it=0; psup_oc->oc_allowed[j]; j++) {
  3185. if (strcasecmp (psup_oc->oc_allowed[j], AllowedAttrsArray[i]) == 0) {
  3186. found_it = 1;
  3187. }
  3188. }
  3189. if (!found_it) {
  3190. charray_add (&OrigAllowedAttrsArray, slapi_ch_strdup (AllowedAttrsArray[i]) );
  3191. }
  3192. }
  3193. }
  3194. }
  3195. else {
  3196. /* if no parent oc */
  3197. OrigRequiredAttrsArray = charray_dup ( RequiredAttrsArray );
  3198. OrigAllowedAttrsArray = charray_dup ( AllowedAttrsArray );
  3199. }
  3200. if (!(schema_flags & DSE_SCHEMA_NO_GLOCK)) {
  3201. oc_unlock(); /* we are done accessing superior oc (psup_oc) */
  3202. }
  3203. /* finally -- create new objclass structure */
  3204. pnew_oc = (struct objclass *) slapi_ch_malloc (1 * sizeof (struct objclass));
  3205. pnew_oc->oc_name = slapi_ch_strdup ( psbOcName->buffer );
  3206. pnew_oc->oc_superior = pOcSup;
  3207. pOcSup = NULL; /* don't free this later */
  3208. pnew_oc->oc_oid = pOcOid;
  3209. pOcOid = NULL; /* don't free this later */
  3210. pnew_oc->oc_desc = pOcDesc;
  3211. pOcDesc = NULL; /* don't free this later */
  3212. pnew_oc->oc_required = RequiredAttrsArray;
  3213. pnew_oc->oc_allowed = AllowedAttrsArray;
  3214. pnew_oc->oc_orig_required = OrigRequiredAttrsArray;
  3215. pnew_oc->oc_orig_allowed = OrigAllowedAttrsArray;
  3216. pnew_oc->oc_extensions = extensions;
  3217. pnew_oc->oc_next = NULL;
  3218. pnew_oc->oc_flags = flags;
  3219. pnew_oc->oc_kind = kind;
  3220. *oc = pnew_oc;
  3221. return read_oc_ldif_return( LDAP_SUCCESS, pOcOid, psbOcName, pOcSup, pOcDesc );
  3222. }
  3223. static char **read_dollar_values ( char *vals) {
  3224. int i,k;
  3225. char **retVal;
  3226. static const char *charsToRemove = " ()";
  3227. /* get rid of all the parens and spaces */
  3228. for ( i = 0, k = 0; vals[i]; i++) {
  3229. if (!strchr(charsToRemove, vals[i])) {
  3230. vals[k++] = vals[i];
  3231. }
  3232. }
  3233. vals[k] = '\0';
  3234. retVal = slapi_str2charray (vals, "$");
  3235. return retVal;
  3236. }
  3237. /*
  3238. * if asipp is NULL, the attribute type is added to the global set of schema.
  3239. * if asipp is not NULL, the AT is not added but *asipp is set. When you are
  3240. * finished with *asipp, use attr_syntax_free() to dispose of it.
  3241. *
  3242. * schema_flags: Any or none of the following bits could be set
  3243. * DSE_SCHEMA_NO_CHECK -- schema won't be checked
  3244. * DSE_SCHEMA_NO_GLOCK -- locking of global resources is turned off;
  3245. * this saves time during initialization since
  3246. * the server operates in single threaded mode
  3247. * at that time or in reload_schemafile_lock.
  3248. * DSE_SCHEMA_LOCKED -- already locked with reload_schemafile_lock;
  3249. * no further lock needed
  3250. *
  3251. * if is_user_defined is true, force attribute type to be user defined.
  3252. *
  3253. * returns an LDAP error code (LDAP_SUCCESS if all goes well)
  3254. */
  3255. static int
  3256. read_at_ldif(const char *input, struct asyntaxinfo **asipp, char *errorbuf,
  3257. size_t errorbufsize, PRUint32 schema_flags, int is_user_defined,
  3258. int schema_ds4x_compat, int is_remote)
  3259. {
  3260. char *pStart, *pEnd;
  3261. char *pOid, *pSyntax, *pSuperior, *pMREquality, *pMROrdering, *pMRSubstring;
  3262. const char *nextinput;
  3263. struct sizedbuffer *psbAttrName= sizedbuffer_construct(BUFSIZ);
  3264. struct sizedbuffer *psbAttrDesc= sizedbuffer_construct(BUFSIZ);
  3265. int status = 0;
  3266. int syntaxlength;
  3267. char **attr_names = NULL;
  3268. char *first_attr_name = NULL;
  3269. int num_names = 0;
  3270. unsigned long flags = SLAPI_ATTR_FLAG_OVERRIDE;
  3271. const char *ss = 0;
  3272. struct asyntaxinfo *tmpasip;
  3273. int invalid_syntax_error;
  3274. schema_strstr_fn_t keyword_strstr_fn;
  3275. schemaext *extensions = NULL;
  3276. /*
  3277. * From RFC 2252 section 4.2:
  3278. *
  3279. * AttributeTypeDescription = "(" whsp
  3280. * numericoid whsp ; AttributeType identifier
  3281. * [ "NAME" qdescrs ] ; name used in AttributeType
  3282. * [ "DESC" qdstring ] ; description
  3283. * [ "OBSOLETE" whsp ]
  3284. * [ "SUP" woid ] ; derived from this other
  3285. * ; AttributeType
  3286. * [ "EQUALITY" woid ; Matching Rule name
  3287. * [ "ORDERING" woid ; Matching Rule name
  3288. * [ "SUBSTR" woid ] ; Matching Rule name
  3289. * [ "SYNTAX" whsp noidlen whsp ] ; see section 4.3
  3290. * [ "SINGLE-VALUE" whsp ] ; default multi-valued
  3291. * [ "COLLECTIVE" whsp ] ; default not collective
  3292. * [ "NO-USER-MODIFICATION" whsp ]; default user modifiable
  3293. * [ "USAGE" whsp AttributeUsage ]; default userApplications
  3294. * whsp ")"
  3295. *
  3296. * AttributeUsage =
  3297. * "userApplications" /
  3298. * "directoryOperation" /
  3299. * "distributedOperation" / ; DSA-shared
  3300. * "dSAOperation" ; DSA-specific, value depends on server
  3301. *
  3302. * XXXmcs: Our parsing technique is poor. In (Netscape) DS 4.12 and earlier
  3303. * releases, parsing was mostly done by looking anywhere within the input
  3304. * string for various keywords such as "EQUALITY". But if, for example, a
  3305. * description contains the word "equality", the parser would take assume
  3306. * that the token following the word was a matching rule. Bad news.
  3307. *
  3308. * In iDS 5.0 and later, we parse in order left to right and advance a
  3309. * pointer as we consume the input string (the nextinput variable). We
  3310. * also use a case-insensitive search when looking for keywords such as
  3311. * DESC. This is still less than ideal.
  3312. *
  3313. * Someday soon we will need to write a real parser.
  3314. *
  3315. * Compatibility notes: if schema_ds4x_compat is set, we:
  3316. * 1. always parse from the beginning of the string
  3317. * 2. use a case-insensitive compare when looking for keywords, e.g., DESC
  3318. */
  3319. if ( schema_ds4x_compat ) {
  3320. keyword_strstr_fn = PL_strcasestr;
  3321. invalid_syntax_error = LDAP_OPERATIONS_ERROR;
  3322. } else {
  3323. keyword_strstr_fn = PL_strstr;
  3324. invalid_syntax_error = LDAP_INVALID_SYNTAX;
  3325. }
  3326. if (schema_flags & DSE_SCHEMA_NO_GLOCK)
  3327. flags |= SLAPI_ATTR_FLAG_NOLOCKING;
  3328. psbAttrName->buffer[0] = '\0';
  3329. psbAttrDesc->buffer[0] = '\0';
  3330. pOid = pSyntax = pSuperior = NULL;
  3331. pMREquality = pMROrdering = pMRSubstring = NULL;
  3332. syntaxlength = SLAPI_SYNTAXLENGTH_NONE;
  3333. nextinput = input;
  3334. /* get the OID */
  3335. pOid = get_tagged_oid( "(", &nextinput, keyword_strstr_fn );
  3336. if (NULL == pOid) {
  3337. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
  3338. input, "Missing or invalid OID" );
  3339. status = invalid_syntax_error;
  3340. goto done;
  3341. }
  3342. if ( schema_ds4x_compat || (strcasecmp(pOid, "NAME") == 0))
  3343. nextinput = input;
  3344. /* look for the NAME (single or list of names) */
  3345. if ( (pStart = (*keyword_strstr_fn) ( nextinput, "NAME ")) != NULL ) {
  3346. pStart += 5;
  3347. sizedbuffer_allocate(psbAttrName,strlen(pStart)+1);
  3348. strcpy ( psbAttrName->buffer, pStart);
  3349. if (*pStart == '(')
  3350. pEnd = strchr(psbAttrName->buffer, ')');
  3351. else
  3352. pEnd = strchr(psbAttrName->buffer+1, '\'');
  3353. if (pEnd)
  3354. *(pEnd+1) = 0;
  3355. nextinput = pStart + strlen(psbAttrName->buffer) + 1;
  3356. attr_names = parse_qdescrs(psbAttrName->buffer, &num_names);
  3357. if ( NULL != attr_names ) {
  3358. first_attr_name = attr_names[0];
  3359. } else { /* NAME followed by nothing violates syntax */
  3360. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
  3361. input, "Missing or invalid attribute name" );
  3362. status = invalid_syntax_error;
  3363. goto done;
  3364. }
  3365. }
  3366. if ( schema_ds4x_compat ) nextinput = input;
  3367. /*
  3368. * if the attribute ldif doesn't have an OID, we'll make the oid
  3369. * attrname-oid
  3370. */
  3371. if ( (strcasecmp ( pOid, "NAME" ) == 0) && (first_attr_name)) {
  3372. slapi_ch_free_string( &pOid );
  3373. pOid = slapi_ch_smprintf("%s-oid", first_attr_name );
  3374. }
  3375. /* look for the optional DESCription */
  3376. if ( (pStart = (*keyword_strstr_fn) ( nextinput, "DESC '")) != NULL ) {
  3377. pStart += 6;
  3378. sizedbuffer_allocate(psbAttrDesc,strlen(pStart)+1);
  3379. strcpy ( psbAttrDesc->buffer, pStart);
  3380. if ( (pEnd = strchr (psbAttrDesc->buffer, '\'' )) != NULL ){
  3381. *pEnd ='\0';
  3382. }
  3383. nextinput = pStart + strlen(psbAttrDesc->buffer) + 1;
  3384. }
  3385. if ( schema_ds4x_compat ) nextinput = input;
  3386. /* look for the optional OBSOLETE marker */
  3387. flags |= get_flag_keyword( schema_obsolete_with_spaces,
  3388. SLAPI_ATTR_FLAG_OBSOLETE, &nextinput, keyword_strstr_fn );
  3389. if ( schema_ds4x_compat ) nextinput = input;
  3390. /* look for the optional SUPerior type */
  3391. pSuperior = get_tagged_oid( "SUP ", &nextinput, keyword_strstr_fn );
  3392. if ( schema_ds4x_compat ) nextinput = input;
  3393. /* look for the optional matching rules */
  3394. pMREquality = get_tagged_oid( "EQUALITY ", &nextinput, keyword_strstr_fn );
  3395. if ( schema_ds4x_compat ) nextinput = input;
  3396. pMROrdering = get_tagged_oid( "ORDERING ", &nextinput, keyword_strstr_fn );
  3397. if ( schema_ds4x_compat ) nextinput = input;
  3398. pMRSubstring = get_tagged_oid( "SUBSTR ", &nextinput, keyword_strstr_fn );
  3399. if ( schema_ds4x_compat ) nextinput = input;
  3400. /* look for the optional SYNTAX */
  3401. if ( NULL != ( pSyntax = get_tagged_oid( "SYNTAX ", &nextinput,
  3402. keyword_strstr_fn ))) {
  3403. /*
  3404. * Check for an optional {LEN}, which if present indicates a
  3405. * suggested maximum size for values of this attribute type.
  3406. *
  3407. * XXXmcs: we do not enforce length restrictions, but we do read
  3408. * and include them in the subschemasubentry.
  3409. */
  3410. if ( (pEnd = strchr ( pSyntax, '{')) != NULL /* balance } */ ) {
  3411. *pEnd = '\0';
  3412. syntaxlength = atoi( pEnd + 1 );
  3413. }
  3414. }
  3415. if ( schema_ds4x_compat ) nextinput = input;
  3416. /* look for the optional SINGLE-VALUE marker */
  3417. flags |= get_flag_keyword( " SINGLE-VALUE ",
  3418. SLAPI_ATTR_FLAG_SINGLE, &nextinput, keyword_strstr_fn );
  3419. if ( schema_ds4x_compat ) nextinput = input;
  3420. /* look for the optional COLLECTIVE marker */
  3421. flags |= get_flag_keyword( schema_collective_with_spaces,
  3422. SLAPI_ATTR_FLAG_COLLECTIVE, &nextinput, keyword_strstr_fn );
  3423. if ( schema_ds4x_compat ) nextinput = input;
  3424. /* look for the optional NO-USER-MODIFICATION marker */
  3425. flags |= get_flag_keyword( schema_nousermod_with_spaces,
  3426. SLAPI_ATTR_FLAG_NOUSERMOD, &nextinput, keyword_strstr_fn );
  3427. if ( schema_ds4x_compat ) nextinput = input;
  3428. /* look for the optional USAGE */
  3429. if (NULL != (ss = (*keyword_strstr_fn)(nextinput, " USAGE "))) {
  3430. ss += 7;
  3431. ss = skipWS(ss);
  3432. if (ss) {
  3433. if ( !PL_strncmp(ss, "directoryOperation",
  3434. strlen("directoryOperation"))) {
  3435. flags |= SLAPI_ATTR_FLAG_OPATTR;
  3436. }
  3437. if ( !PL_strncmp(ss, "distributedOperation",
  3438. strlen("distributedOperation"))) {
  3439. flags |= SLAPI_ATTR_FLAG_OPATTR|SLAPI_ATTR_FLAG_DISTRIBUTED_OPERATION;
  3440. }
  3441. if ( !PL_strncmp(ss, "dSAOperation",
  3442. strlen("dSAOperation"))) {
  3443. flags |= SLAPI_ATTR_FLAG_OPATTR|SLAPI_ATTR_FLAG_DSA_OPERATION;
  3444. }
  3445. if ( NULL == ( nextinput = strchr( ss, ' ' ))) {
  3446. nextinput = ss + strlen(ss);
  3447. }
  3448. }
  3449. }
  3450. if ( schema_ds4x_compat ) nextinput = input;
  3451. /* X-ORIGIN list */
  3452. if (is_user_defined) {
  3453. /* add X-ORIGIN 'user defined' */
  3454. extensions = parse_extensions( nextinput, schema_user_defined_origin );
  3455. } else {
  3456. /* add nothing extra*/
  3457. extensions = parse_extensions( nextinput, NULL );
  3458. flags |= SLAPI_ATTR_FLAG_STD_ATTR;
  3459. }
  3460. /* Do some sanity checking to make sure everything was read correctly */
  3461. if (NULL == pOid) {
  3462. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
  3463. first_attr_name, "Missing OID" );
  3464. status = invalid_syntax_error;
  3465. }
  3466. if (!status && (!attr_names || !num_names)) {
  3467. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
  3468. first_attr_name,
  3469. "Missing name (OID is \"%s\")", pOid );
  3470. status = invalid_syntax_error;
  3471. }
  3472. if (!status && (NULL != pSuperior)) {
  3473. struct asyntaxinfo *asi_parent;
  3474. asi_parent = attr_syntax_get_by_name(pSuperior, schema_flags);
  3475. /* if we find no match then server won't start or add the attribute type */
  3476. if (asi_parent == NULL) {
  3477. LDAPDebug (LDAP_DEBUG_PARSE,
  3478. "Cannot find parent attribute type \"%s\"\n",pSuperior,
  3479. NULL,NULL);
  3480. schema_create_errormsg( errorbuf, errorbufsize,
  3481. schema_errprefix_at, first_attr_name,
  3482. "Missing parent attribute syntax OID");
  3483. status = invalid_syntax_error;
  3484. /* We only want to use the parent syntax if a SYNTAX
  3485. * wasn't explicitly specified for this attribute. */
  3486. } else if ((NULL == pSyntax) || (NULL == pMREquality) || (NULL == pMRSubstring) ||
  3487. (NULL == pMROrdering)) {
  3488. char *pso = asi_parent->asi_plugin->plg_syntax_oid;
  3489. if (pso && (NULL == pSyntax)) {
  3490. pSyntax = slapi_ch_strdup(pso);
  3491. LDAPDebug (LDAP_DEBUG_TRACE,
  3492. "Inheriting syntax %s from parent type %s\n",
  3493. pSyntax, pSuperior,NULL);
  3494. } else if (NULL == pSyntax) {
  3495. schema_create_errormsg( errorbuf, errorbufsize,
  3496. schema_errprefix_at, first_attr_name,
  3497. "Missing parent attribute syntax OID");
  3498. status = invalid_syntax_error;
  3499. }
  3500. if (NULL == pMREquality) {
  3501. pMREquality = slapi_ch_strdup(asi_parent->asi_mr_equality);
  3502. }
  3503. if (NULL == pMRSubstring) {
  3504. pMRSubstring = slapi_ch_strdup(asi_parent->asi_mr_substring);
  3505. }
  3506. if (NULL == pMROrdering) {
  3507. pMROrdering = slapi_ch_strdup(asi_parent->asi_mr_ordering);
  3508. }
  3509. attr_syntax_return( asi_parent );
  3510. }
  3511. }
  3512. if (!status && (NULL == pSyntax)) {
  3513. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
  3514. first_attr_name, "Missing attribute syntax OID");
  3515. status = invalid_syntax_error;
  3516. }
  3517. if (!status && (plugin_syntax_find ( pSyntax ) == NULL) ) {
  3518. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
  3519. first_attr_name, "Unknown attribute syntax OID \"%s\"",
  3520. pSyntax );
  3521. status = invalid_syntax_error;
  3522. }
  3523. if (!status) {
  3524. struct objclass *poc;
  3525. /* check to make sure that the OID isn't being used by an objectclass */
  3526. if (!(schema_flags & DSE_SCHEMA_LOCKED))
  3527. oc_lock_read();
  3528. poc = oc_find_oid_nolock( pOid );
  3529. if ( poc != NULL) {
  3530. schema_create_errormsg( errorbuf, errorbufsize,
  3531. schema_errprefix_at, first_attr_name,
  3532. "The OID \"%s\" is also used by the object class \"%s\"",
  3533. pOid, poc->oc_name);
  3534. status = LDAP_TYPE_OR_VALUE_EXISTS;
  3535. }
  3536. if (!(schema_flags & DSE_SCHEMA_LOCKED))
  3537. oc_unlock();
  3538. }
  3539. if (!(schema_flags & DSE_SCHEMA_NO_CHECK) && !status) {
  3540. int ii;
  3541. /* check to see if the attribute name is valid */
  3542. for (ii = 0; !status && (ii < num_names); ++ii) {
  3543. if ( schema_check_name(attr_names[ii], PR_TRUE, errorbuf,
  3544. errorbufsize) == 0 ) {
  3545. status = invalid_syntax_error;
  3546. }
  3547. else if (!(flags & SLAPI_ATTR_FLAG_OVERRIDE) &&
  3548. attr_syntax_exists(attr_names[ii])) {
  3549. schema_create_errormsg( errorbuf, errorbufsize,
  3550. schema_errprefix_at, attr_names[ii],
  3551. "Could not be added because it already exists" );
  3552. status = LDAP_TYPE_OR_VALUE_EXISTS;
  3553. }
  3554. }
  3555. }
  3556. if (!(schema_flags & DSE_SCHEMA_NO_CHECK) && !status) {
  3557. if ( schema_check_oid ( first_attr_name, pOid, PR_TRUE, errorbuf,
  3558. errorbufsize ) == 0 ) {
  3559. status = invalid_syntax_error;
  3560. }
  3561. }
  3562. if (!status) {
  3563. struct asyntaxinfo *tmpasi;
  3564. if (!(flags & SLAPI_ATTR_FLAG_OVERRIDE) &&
  3565. ( NULL != ( tmpasi = attr_syntax_get_by_oid(pOid, schema_flags)))) {
  3566. schema_create_errormsg( errorbuf, errorbufsize,
  3567. schema_errprefix_at, first_attr_name,
  3568. "Could not be added because the OID \"%s\" is already in use",
  3569. pOid);
  3570. status = LDAP_TYPE_OR_VALUE_EXISTS;
  3571. attr_syntax_return( tmpasi );
  3572. }
  3573. }
  3574. if (!status) {
  3575. status = attr_syntax_create( pOid, attr_names,
  3576. *psbAttrDesc->buffer == '\0' ? NULL : psbAttrDesc->buffer,
  3577. pSuperior, pMREquality, pMROrdering, pMRSubstring, extensions,
  3578. pSyntax, syntaxlength, flags, &tmpasip );
  3579. }
  3580. if (!status) {
  3581. if ( NULL != asipp ) {
  3582. *asipp = tmpasip; /* just return it */
  3583. } else { /* add the new attribute to the global store */
  3584. status = attr_syntax_add( tmpasip, schema_flags );
  3585. if ( LDAP_SUCCESS != status ) {
  3586. if ( 0 != (flags & SLAPI_ATTR_FLAG_OVERRIDE) &&
  3587. LDAP_TYPE_OR_VALUE_EXISTS == status ) {
  3588. /*
  3589. * This can only occur if the name and OID don't match the
  3590. * attribute we are trying to override (all other cases of
  3591. * "type or value exists" were trapped above).
  3592. */
  3593. schema_create_errormsg( errorbuf, errorbufsize,
  3594. schema_errprefix_at, first_attr_name,
  3595. "Does not match the OID \"%s\". Another attribute"
  3596. " type is already using the name or OID.", pOid);
  3597. } else {
  3598. schema_create_errormsg( errorbuf, errorbufsize,
  3599. schema_errprefix_at, first_attr_name,
  3600. "Could not be added (OID is \"%s\")", pOid );
  3601. }
  3602. attr_syntax_free( tmpasip );
  3603. }
  3604. }
  3605. }
  3606. done:
  3607. /* free everything */
  3608. free_qdlist(attr_names, num_names);
  3609. sizedbuffer_destroy(psbAttrName);
  3610. sizedbuffer_destroy(psbAttrDesc);
  3611. slapi_ch_free((void **)&pOid);
  3612. slapi_ch_free((void **)&pSuperior);
  3613. slapi_ch_free((void **)&pMREquality);
  3614. slapi_ch_free((void **)&pMROrdering);
  3615. slapi_ch_free((void **)&pMRSubstring);
  3616. slapi_ch_free((void **)&pSyntax);
  3617. schema_free_extensions(extensions);
  3618. return status;
  3619. }
  3620. #else /* (USE_OPENLDAP) */
  3621. /* openldap attribute parser */
  3622. /*
  3623. * if asipp is NULL, the attribute type is added to the global set of schema.
  3624. * if asipp is not NULL, the AT is not added but *asipp is set. When you are
  3625. * finished with *asipp, use attr_syntax_free() to dispose of it.
  3626. *
  3627. * schema_flags: Any or none of the following bits could be set
  3628. * DSE_SCHEMA_NO_CHECK -- schema won't be checked
  3629. * DSE_SCHEMA_NO_GLOCK -- locking of global resources is turned off;
  3630. * this saves time during initialization since
  3631. * the server operates in single threaded mode
  3632. * at that time or in reload_schemafile_lock.
  3633. * DSE_SCHEMA_LOCKED -- already locked with reload_schemafile_lock;
  3634. * no further lock needed
  3635. *
  3636. * if is_user_defined is true, force attribute type to be user defined.
  3637. *
  3638. * returns an LDAP error code (LDAP_SUCCESS if all goes well)
  3639. */
  3640. static int
  3641. parse_attr_str(const char *input, struct asyntaxinfo **asipp, char *errorbuf,
  3642. size_t errorbufsize, PRUint32 schema_flags, int is_user_defined,
  3643. int schema_ds4x_compat, int is_remote)
  3644. {
  3645. struct asyntaxinfo *tmpasip;
  3646. struct asyntaxinfo *tmpasi;
  3647. schemaext *extensions = NULL, *head = NULL;
  3648. struct objclass *poc;
  3649. LDAPAttributeType *atype = NULL;
  3650. const char *errp;
  3651. char *first_attr_name = NULL;
  3652. char **attr_names = NULL;
  3653. unsigned long flags = SLAPI_ATTR_FLAG_OVERRIDE;
  3654. /* If we ever accept openldap schema directly, then make parser_flags configurable */
  3655. const int parser_flags = LDAP_SCHEMA_ALLOW_NONE | LDAP_SCHEMA_ALLOW_NO_OID;
  3656. int invalid_syntax_error;
  3657. int syntaxlength = SLAPI_SYNTAXLENGTH_NONE;
  3658. int num_names = 0;
  3659. int status = 0;
  3660. int rc = 0;
  3661. int a, aa;
  3662. /*
  3663. * OpenLDAP AttributeType struct
  3664. *
  3665. * typedef struct ldap_attributetype {
  3666. * char *at_oid; OID
  3667. * char **at_names; Names
  3668. * char *at_desc; Description
  3669. * int at_obsolete; Is obsolete?
  3670. * char *at_sup_oid; OID of superior type
  3671. * char *at_equality_oid; OID of equality matching rule
  3672. * char *at_ordering_oid; OID of ordering matching rule
  3673. * char *at_substr_oid; OID of substrings matching rule
  3674. * char *at_syntax_oid; OID of syntax of values
  3675. * int at_syntax_len; Suggested minimum maximum length
  3676. * int at_single_value; Is single-valued?
  3677. * int at_collective; Is collective?
  3678. * int at_no_user_mod; Are changes forbidden through LDAP?
  3679. * int at_usage; Usage, see below
  3680. * LDAPSchemaExtensionItem **at_extensions; Extensions
  3681. * } LDAPAttributeType;
  3682. */
  3683. /*
  3684. * Set the appropriate error code
  3685. */
  3686. if ( schema_ds4x_compat ) {
  3687. invalid_syntax_error = LDAP_OPERATIONS_ERROR;
  3688. } else {
  3689. invalid_syntax_error = LDAP_INVALID_SYNTAX;
  3690. }
  3691. /*
  3692. * Verify we have input
  3693. */
  3694. if(input == NULL || '\0' == input[0]){
  3695. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at, NULL,
  3696. "One or more values are required for the attributeTypes attribute" );
  3697. LDAPDebug ( LDAP_DEBUG_ANY, "NULL args passed to parse_attr_str\n",0,0,0);
  3698. return invalid_syntax_error;
  3699. }
  3700. /*
  3701. * Parse the line and create of attribute structure
  3702. */
  3703. while(isspace(*input)){
  3704. /* trim any leading spaces */
  3705. input++;
  3706. }
  3707. if((atype = ldap_str2attributetype(input, &rc, &errp, parser_flags )) == NULL){
  3708. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at, input,
  3709. "Failed to parse attribute, error(%d - %s) at (%s)", rc, ldap_scherr2str(rc), errp );
  3710. return invalid_syntax_error;
  3711. }
  3712. if (schema_flags & DSE_SCHEMA_NO_GLOCK){
  3713. flags |= SLAPI_ATTR_FLAG_NOLOCKING;
  3714. }
  3715. /*
  3716. * Check the NAME and update our name list
  3717. */
  3718. if ( NULL != atype->at_names ) {
  3719. for(; atype->at_names[num_names]; num_names++){
  3720. charray_add(&attr_names, slapi_ch_strdup(atype->at_names[num_names]));
  3721. }
  3722. first_attr_name = atype->at_names[0];
  3723. } else { /* NAME followed by nothing violates syntax */
  3724. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at, input,
  3725. "Missing or invalid attribute name" );
  3726. status = invalid_syntax_error;
  3727. goto done;
  3728. }
  3729. /*
  3730. * If the attribute type doesn't have an OID, we'll make the oid attrname-oid.
  3731. */
  3732. if (NULL == atype->at_oid) {
  3733. atype->at_oid = slapi_ch_smprintf("%s-oid", first_attr_name );
  3734. }
  3735. /*
  3736. * Set the flags
  3737. */
  3738. if(atype->at_obsolete){
  3739. flags |= SLAPI_ATTR_FLAG_OBSOLETE;
  3740. }
  3741. if(atype->at_single_value){
  3742. flags |= SLAPI_ATTR_FLAG_SINGLE;
  3743. }
  3744. if(atype->at_collective){
  3745. flags |= SLAPI_ATTR_FLAG_COLLECTIVE;
  3746. }
  3747. if(atype->at_no_user_mod){
  3748. flags |= SLAPI_ATTR_FLAG_NOUSERMOD;
  3749. }
  3750. if(atype->at_usage == LDAP_SCHEMA_DIRECTORY_OPERATION){
  3751. flags |= SLAPI_ATTR_FLAG_OPATTR;
  3752. }
  3753. if(atype->at_usage == LDAP_SCHEMA_DISTRIBUTED_OPERATION){
  3754. flags |= SLAPI_ATTR_FLAG_OPATTR|SLAPI_ATTR_FLAG_DISTRIBUTED_OPERATION;
  3755. }
  3756. if(atype->at_usage == LDAP_SCHEMA_DSA_OPERATION){
  3757. flags |= SLAPI_ATTR_FLAG_OPATTR|SLAPI_ATTR_FLAG_DSA_OPERATION;
  3758. }
  3759. /*
  3760. * Check the superior, and use it fill in any missing oids on this attribute
  3761. */
  3762. if (NULL != atype->at_sup_oid) {
  3763. struct asyntaxinfo *asi_parent;
  3764. asi_parent = attr_syntax_get_by_name(atype->at_sup_oid, schema_flags);
  3765. /* if we find no match then server won't start or add the attribute type */
  3766. if (asi_parent == NULL) {
  3767. LDAPDebug (LDAP_DEBUG_ANY, "Cannot find parent attribute type \"%s\"\n",
  3768. atype->at_sup_oid, NULL, NULL);
  3769. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at, first_attr_name,
  3770. "Missing parent attribute syntax OID");
  3771. status = invalid_syntax_error;
  3772. goto done;
  3773. } else if ((NULL == atype->at_syntax_oid) || (NULL == atype->at_equality_oid) ||
  3774. (NULL == atype->at_substr_oid) || (NULL == atype->at_ordering_oid))
  3775. {
  3776. /*
  3777. * We only want to use the parent syntax if a SYNTAX
  3778. * wasn't explicitly specified for this attribute.
  3779. */
  3780. char *pso = asi_parent->asi_plugin->plg_syntax_oid;
  3781. if (pso && (NULL == atype->at_syntax_oid)) {
  3782. atype->at_syntax_oid = slapi_ch_strdup(pso);
  3783. LDAPDebug (LDAP_DEBUG_TRACE,
  3784. "Inheriting syntax %s from parent type %s\n",
  3785. atype->at_syntax_oid, atype->at_sup_oid,NULL);
  3786. } else if (NULL == atype->at_syntax_oid) {
  3787. schema_create_errormsg( errorbuf, errorbufsize,
  3788. schema_errprefix_at, first_attr_name,
  3789. "Missing parent attribute syntax OID");
  3790. status = invalid_syntax_error;
  3791. goto done;
  3792. }
  3793. if (NULL == atype->at_equality_oid) {
  3794. atype->at_equality_oid = slapi_ch_strdup(asi_parent->asi_mr_equality);
  3795. }
  3796. if (NULL == atype->at_substr_oid) {
  3797. atype->at_substr_oid = slapi_ch_strdup(asi_parent->asi_mr_substring);
  3798. }
  3799. if (NULL == atype->at_ordering_oid) {
  3800. atype->at_ordering_oid = slapi_ch_strdup(asi_parent->asi_mr_ordering);
  3801. }
  3802. attr_syntax_return( asi_parent );
  3803. }
  3804. }
  3805. /*
  3806. * Make sure we have a syntax oid set
  3807. */
  3808. if (NULL == atype->at_syntax_oid) {
  3809. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
  3810. first_attr_name, "Missing attribute syntax OID");
  3811. status = invalid_syntax_error;
  3812. goto done;
  3813. }
  3814. /*
  3815. * Make sure the OID is known
  3816. */
  3817. if (!status && (plugin_syntax_find ( atype->at_syntax_oid ) == NULL) ) {
  3818. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
  3819. first_attr_name, "Unknown attribute syntax OID \"%s\"",
  3820. atype->at_syntax_oid );
  3821. status = invalid_syntax_error;
  3822. goto done;
  3823. }
  3824. /*
  3825. * Check to make sure that the OID isn't being used by an objectclass
  3826. */
  3827. if (!(schema_flags & DSE_SCHEMA_LOCKED)){
  3828. oc_lock_read();
  3829. }
  3830. poc = oc_find_oid_nolock( atype->at_oid );
  3831. if ( poc != NULL) {
  3832. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at, first_attr_name,
  3833. "The OID \"%s\" is also used by the object class \"%s\"", atype->at_oid, poc->oc_name);
  3834. status = LDAP_TYPE_OR_VALUE_EXISTS;
  3835. }
  3836. if (!(schema_flags & DSE_SCHEMA_LOCKED)){
  3837. oc_unlock();
  3838. }
  3839. if(status){
  3840. goto done;
  3841. }
  3842. /*
  3843. * Walk the "at_extensions" and set the schema extensions
  3844. */
  3845. for(a = 0; atype->at_extensions && atype->at_extensions[a]; a++){
  3846. schemaext *newext = (schemaext *)slapi_ch_calloc(1, sizeof (schemaext));
  3847. newext->term = slapi_ch_strdup(atype->at_extensions[a]->lsei_name);
  3848. for (aa = 0; atype->at_extensions[a]->lsei_values && atype->at_extensions[a]->lsei_values[aa]; aa++){
  3849. charray_add(&newext->values, slapi_ch_strdup(atype->at_extensions[a]->lsei_values[aa]));
  3850. newext->value_count++;
  3851. }
  3852. if(extensions == NULL){
  3853. extensions = newext;
  3854. head = newext;
  3855. } else {
  3856. extensions->next = newext;
  3857. extensions = newext;
  3858. }
  3859. }
  3860. extensions = head; /* reset to the top of the list */
  3861. /*
  3862. * Make sure if we are user-defined, that the attr_origins represents it
  3863. */
  3864. if (!extension_is_user_defined( extensions )) {
  3865. if ( is_user_defined ) {
  3866. int added = 0;
  3867. /* see if we have a X-ORIGIN term already */
  3868. while(extensions){
  3869. if(strcmp(extensions->term, "X-ORIGIN") == 0){
  3870. charray_add(&extensions->values, slapi_ch_strdup(schema_user_defined_origin[0]));
  3871. extensions->value_count++;
  3872. added = 1;
  3873. break;
  3874. }
  3875. extensions = extensions->next;
  3876. }
  3877. if(!added){
  3878. /* X-ORIGIN is completely missing, add it */
  3879. extensions = head;
  3880. schemaext *newext = (schemaext *)slapi_ch_calloc(1, sizeof (schemaext));
  3881. newext->term = slapi_ch_strdup("X-ORIGIN");
  3882. charray_add(&newext->values, slapi_ch_strdup(schema_user_defined_origin[0]));
  3883. newext->value_count++;
  3884. while(extensions && extensions->next){
  3885. /* move to the end of the list */
  3886. extensions = extensions->next;
  3887. }
  3888. if(extensions == NULL){
  3889. extensions = newext;
  3890. head = extensions;
  3891. } else {
  3892. extensions->next = newext;
  3893. }
  3894. }
  3895. } else {
  3896. flags |= SLAPI_ATTR_FLAG_STD_ATTR;
  3897. }
  3898. }
  3899. extensions = head; /* reset to the top of the list */
  3900. /*
  3901. * Check to see if the attribute name is valid
  3902. */
  3903. if (!(schema_flags & DSE_SCHEMA_NO_CHECK)) {
  3904. for (a = 0; a < num_names; ++a) {
  3905. if ( schema_check_name(attr_names[a], PR_TRUE, errorbuf, errorbufsize) == 0 ) {
  3906. status = invalid_syntax_error;
  3907. goto done;
  3908. } else if (!(flags & SLAPI_ATTR_FLAG_OVERRIDE) && attr_syntax_exists(attr_names[a])) {
  3909. schema_create_errormsg( errorbuf, errorbufsize,
  3910. schema_errprefix_at, attr_names[a],
  3911. "Could not be added because it already exists" );
  3912. status = LDAP_TYPE_OR_VALUE_EXISTS;
  3913. goto done;
  3914. }
  3915. }
  3916. }
  3917. /*
  3918. * Check if the OID is valid
  3919. */
  3920. if (!(schema_flags & DSE_SCHEMA_NO_CHECK)) {
  3921. if ( schema_check_oid ( first_attr_name, atype->at_oid, PR_TRUE, errorbuf,
  3922. errorbufsize ) == 0 ) {
  3923. status = invalid_syntax_error;
  3924. goto done;
  3925. }
  3926. }
  3927. /*
  3928. * Check if the OID is already being used
  3929. */
  3930. if (!(flags & SLAPI_ATTR_FLAG_OVERRIDE) && ( NULL != (tmpasi = attr_syntax_get_by_oid(atype->at_oid, schema_flags)))) {
  3931. schema_create_errormsg( errorbuf, errorbufsize,
  3932. schema_errprefix_at, first_attr_name,
  3933. "Could not be added because the OID \"%s\" is already in use", atype->at_oid);
  3934. status = LDAP_TYPE_OR_VALUE_EXISTS;
  3935. attr_syntax_return( tmpasi );
  3936. goto done;
  3937. }
  3938. /*
  3939. * Finally create the attribute
  3940. */
  3941. status = attr_syntax_create( atype->at_oid, attr_names, atype->at_desc, atype->at_sup_oid,
  3942. atype->at_equality_oid, atype->at_ordering_oid, atype->at_substr_oid,
  3943. extensions, atype->at_syntax_oid, syntaxlength, flags, &tmpasip );
  3944. if (!status) {
  3945. if ( NULL != asipp ) {
  3946. *asipp = tmpasip; /* just return it */
  3947. } else {
  3948. /* add the new attribute to the global store */
  3949. status = attr_syntax_add( tmpasip, schema_flags );
  3950. if ( LDAP_SUCCESS != status ) {
  3951. if ( 0 != (flags & SLAPI_ATTR_FLAG_OVERRIDE) &&
  3952. LDAP_TYPE_OR_VALUE_EXISTS == status ) {
  3953. /*
  3954. * This can only occur if the name and OID don't match the
  3955. * attribute we are trying to override (all other cases of
  3956. * "type or value exists" were trapped above).
  3957. */
  3958. schema_create_errormsg( errorbuf, errorbufsize,
  3959. schema_errprefix_at, first_attr_name,
  3960. "Does not match the OID \"%s\". Another attribute "
  3961. "type is already using the name or OID.", atype->at_oid);
  3962. } else {
  3963. schema_create_errormsg( errorbuf, errorbufsize,
  3964. schema_errprefix_at, first_attr_name,
  3965. "Could not be added (OID is \"%s\")", atype->at_oid );
  3966. }
  3967. attr_syntax_free( tmpasip );
  3968. }
  3969. }
  3970. }
  3971. done:
  3972. /* free everything */
  3973. ldap_attributetype_free(atype);
  3974. charray_free(attr_names);
  3975. schema_free_extensions(extensions);
  3976. return status;
  3977. }
  3978. /*
  3979. * parse_objclass_str
  3980. *
  3981. * Read the value of the objectclasses attribute in cn=schema, convert it
  3982. * into an objectclass struct.
  3983. *
  3984. * Arguments:
  3985. *
  3986. * input : value of objectclasses attribute to read
  3987. * oc : pointer write the objectclass to
  3988. * errorbuf : buffer to write any errors to
  3989. * is_user_defined : if non-zero, force objectclass to be user defined
  3990. * schema_flags : Any or none of the following bits could be set
  3991. * DSE_SCHEMA_NO_CHECK -- schema won't be checked
  3992. * DSE_SCHEMA_NO_GLOCK -- don't lock global resources
  3993. * DSE_SCHEMA_LOCKED -- already locked with
  3994. * reload_schemafile_lock;
  3995. * no further lock needed
  3996. * schema_ds4x_compat: if non-zero, act like Netscape DS 4.x
  3997. *
  3998. * Returns: an LDAP error code
  3999. *
  4000. * LDAP_SUCCESS if the objectclass was sucessfully read, the new
  4001. * objectclass will be written to oc
  4002. *
  4003. * All others: there was an error, an error message will
  4004. * be written to errorbuf
  4005. */
  4006. static int
  4007. parse_objclass_str ( const char *input, struct objclass **oc, char *errorbuf,
  4008. size_t errorbufsize, PRUint32 schema_flags, int is_user_defined,
  4009. int schema_ds4x_compat, struct objclass *private_schema )
  4010. {
  4011. LDAPObjectClass *objClass;
  4012. struct objclass *pnew_oc = NULL, *psup_oc = NULL;
  4013. schemaext *extensions = NULL, *head = NULL;
  4014. const char *errp;
  4015. char **OrigRequiredAttrsArray, **OrigAllowedAttrsArray;
  4016. char *first_oc_name = NULL;
  4017. /* If we ever accept openldap schema directly, then make parser_flags configurable */
  4018. const int parser_flags = LDAP_SCHEMA_ALLOW_NONE | LDAP_SCHEMA_ALLOW_NO_OID;
  4019. PRUint8 flags = 0;
  4020. int invalid_syntax_error;
  4021. int i, j;
  4022. int rc = 0;
  4023. /*
  4024. * openLDAP Objectclass struct
  4025. *
  4026. * typedef struct ldap_objectclass {
  4027. * char *oc_oid; OID
  4028. * char **oc_names; Names
  4029. * char *oc_desc; Description
  4030. * int oc_obsolete; Is obsolete?
  4031. * char **oc_sup_oids; OIDs of superior classes
  4032. * int oc_kind; Kind
  4033. * char **oc_at_oids_must; OIDs of required attribute types
  4034. * char **oc_at_oids_may; OIDs of optional attribute types
  4035. * LDAPSchemaExtensionItem **oc_extensions; Extensions
  4036. * } LDAPObjectClass;
  4037. */
  4038. /*
  4039. * Set the appropriate error code
  4040. */
  4041. if ( schema_ds4x_compat ) {
  4042. invalid_syntax_error = LDAP_OPERATIONS_ERROR;
  4043. } else {
  4044. invalid_syntax_error = LDAP_INVALID_SYNTAX;
  4045. }
  4046. /*
  4047. * Verify we have input
  4048. */
  4049. if ( NULL == input || '\0' == input[0] ) {
  4050. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc, NULL,
  4051. "One or more values are required for the objectClasses attribute" );
  4052. LDAPDebug ( LDAP_DEBUG_ANY, "NULL args passed to read_oc_ldif\n",0,0,0);
  4053. return LDAP_OPERATIONS_ERROR;
  4054. }
  4055. /*
  4056. * Parse the input and create the openLdap objectclass structure
  4057. */
  4058. while(isspace(*input)){
  4059. /* trim any leading spaces */
  4060. input++;
  4061. }
  4062. if((objClass = ldap_str2objectclass(input, &rc, &errp, parser_flags )) == NULL){
  4063. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc, input,
  4064. "Failed to parse objectclass, error(%d) at (%s)", rc, errp );
  4065. return invalid_syntax_error;
  4066. }
  4067. /*
  4068. * Check the NAME and update our name list
  4069. */
  4070. if ( NULL != objClass->oc_names ) {
  4071. first_oc_name = objClass->oc_names[0];
  4072. } else { /* NAME followed by nothing violates syntax */
  4073. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc, input,
  4074. "Missing or invalid objectclass name" );
  4075. rc = invalid_syntax_error;
  4076. goto done;
  4077. }
  4078. /*
  4079. * If the objectclass type doesn't have an OID, we'll make the oid objClass-oid.
  4080. */
  4081. if (NULL == objClass->oc_oid) {
  4082. objClass->oc_oid = slapi_ch_smprintf("%s-oid", first_oc_name );
  4083. }
  4084. /*
  4085. * Check to see if the objectclass name is valid
  4086. */
  4087. if (!(schema_flags & DSE_SCHEMA_NO_CHECK)) {
  4088. for (i = 0; objClass->oc_names[i]; ++i) {
  4089. if ( schema_check_name(objClass->oc_names[i], PR_TRUE, errorbuf, errorbufsize) == 0 ) {
  4090. rc = invalid_syntax_error;
  4091. goto done;
  4092. }
  4093. }
  4094. }
  4095. /*
  4096. * Check if the OID is valid
  4097. */
  4098. if (!(schema_flags & DSE_SCHEMA_NO_CHECK)) {
  4099. if ( schema_check_oid ( first_oc_name, objClass->oc_oid, PR_TRUE, errorbuf,
  4100. errorbufsize ) == 0 ) {
  4101. rc = invalid_syntax_error;
  4102. goto done;
  4103. }
  4104. }
  4105. /*
  4106. * Look for the superior objectclass. We first look for a parenthesized
  4107. * list and if not found we look for a simple OID.
  4108. *
  4109. * XXXmcs: Since we do not yet support multiple superior objectclasses, we
  4110. * just grab the first OID in a parenthesized list.
  4111. */
  4112. if (!(schema_flags & DSE_SCHEMA_NO_GLOCK)) {
  4113. /* needed because we access the superior oc */
  4114. oc_lock_read();
  4115. }
  4116. if(objClass->oc_sup_oids && objClass->oc_sup_oids[0]) {
  4117. if (schema_flags & DSE_SCHEMA_USE_PRIV_SCHEMA) {
  4118. /* We have built an objectclass list on a private variable
  4119. * This is used to check the schema of a remote consumer
  4120. */
  4121. psup_oc = oc_find_nolock(objClass->oc_sup_oids[0], private_schema, PR_TRUE);
  4122. } else {
  4123. psup_oc = oc_find_nolock(objClass->oc_sup_oids[0], NULL, PR_FALSE);
  4124. }
  4125. }
  4126. /*
  4127. * Walk the "oc_extensions" and set the schema extensions
  4128. */
  4129. for(i = 0; objClass->oc_extensions && objClass->oc_extensions[i]; i++){
  4130. schemaext *newext = (schemaext *)slapi_ch_calloc(1, sizeof (schemaext));
  4131. newext->term = slapi_ch_strdup(objClass->oc_extensions[i]->lsei_name);
  4132. for (j = 0; objClass->oc_extensions[i]->lsei_values && objClass->oc_extensions[i]->lsei_values[j]; j++){
  4133. charray_add(&newext->values, slapi_ch_strdup(objClass->oc_extensions[i]->lsei_values[j]));
  4134. newext->value_count++;
  4135. }
  4136. if(extensions == NULL){
  4137. extensions = newext;
  4138. head = extensions;
  4139. } else {
  4140. extensions->next = newext;
  4141. extensions = newext;
  4142. }
  4143. }
  4144. extensions = head; /* reset to the top of the list */
  4145. /*
  4146. * Set the remaining flags
  4147. */
  4148. if(objClass->oc_obsolete){
  4149. flags |= OC_FLAG_OBSOLETE;
  4150. }
  4151. if ( extension_is_user_defined( extensions )) {
  4152. flags |= OC_FLAG_USER_OC;
  4153. } else if ( is_user_defined ) {
  4154. int added = 0;
  4155. /* see if we have a X-ORIGIN term already */
  4156. while(extensions){
  4157. if(strcmp(extensions->term, "X-ORIGIN") == 0){
  4158. charray_add(&extensions->values, slapi_ch_strdup(schema_user_defined_origin[0]));
  4159. extensions->value_count++;
  4160. added = 1;
  4161. break;
  4162. }
  4163. extensions = extensions->next;
  4164. }
  4165. if(!added){
  4166. /* X-ORIGIN is completely missing, add it */
  4167. extensions = head;
  4168. schemaext *newext = (schemaext *)slapi_ch_calloc(1, sizeof (schemaext));
  4169. newext->term = slapi_ch_strdup("X-ORIGIN");
  4170. charray_add( &newext->values, slapi_ch_strdup( schema_user_defined_origin[0] ));
  4171. newext->value_count++;
  4172. while(extensions && extensions->next){
  4173. extensions = extensions->next;
  4174. }
  4175. if(extensions == NULL){
  4176. extensions = newext;
  4177. head = extensions;
  4178. } else {
  4179. extensions->next = newext;
  4180. }
  4181. }
  4182. flags |= OC_FLAG_USER_OC;
  4183. } else {
  4184. flags |= OC_FLAG_STANDARD_OC;
  4185. }
  4186. extensions = head; /* reset to the top of the list */
  4187. /*
  4188. * Generate OrigRequiredAttrsArray and OrigAllowedAttrsArray from the superior oc
  4189. */
  4190. if (psup_oc) {
  4191. int found_it;
  4192. OrigRequiredAttrsArray = (char **) slapi_ch_malloc (1 * sizeof(char *)) ;
  4193. OrigRequiredAttrsArray[0] = NULL;
  4194. OrigAllowedAttrsArray = (char **) slapi_ch_malloc (1 * sizeof(char *)) ;
  4195. OrigAllowedAttrsArray[0] = NULL;
  4196. if (psup_oc->oc_required && objClass->oc_at_oids_must) {
  4197. for (i = 0; objClass->oc_at_oids_must[i]; i++) {
  4198. found_it = 0;
  4199. for (j = 0; psup_oc->oc_required[j]; j++) {
  4200. if (strcasecmp (psup_oc->oc_required[j], objClass->oc_at_oids_must[i]) == 0) {
  4201. found_it = 1;
  4202. break;
  4203. }
  4204. }
  4205. if (!found_it) {
  4206. charray_add (&OrigRequiredAttrsArray, slapi_ch_strdup ( objClass->oc_at_oids_must[i] ) );
  4207. }
  4208. }
  4209. } else {
  4210. /* we still need to set the originals */
  4211. charray_free(OrigRequiredAttrsArray);
  4212. OrigRequiredAttrsArray = charray_dup(objClass->oc_at_oids_must);
  4213. }
  4214. if (psup_oc->oc_allowed && objClass->oc_at_oids_may) {
  4215. for (i = 0; objClass->oc_at_oids_may[i]; i++) {
  4216. found_it = 0;
  4217. for (j = 0; psup_oc->oc_allowed[j]; j++) {
  4218. if (strcasecmp (psup_oc->oc_allowed[j], objClass->oc_at_oids_may[i]) == 0) {
  4219. found_it = 1;
  4220. break;
  4221. }
  4222. }
  4223. if (!found_it) {
  4224. charray_add (&OrigAllowedAttrsArray, slapi_ch_strdup (objClass->oc_at_oids_may[i]) );
  4225. }
  4226. }
  4227. } else {
  4228. /* we still need to set the originals */
  4229. charray_free(OrigAllowedAttrsArray);
  4230. OrigAllowedAttrsArray = charray_dup(objClass->oc_at_oids_may);
  4231. }
  4232. } else {
  4233. /* if no parent oc */
  4234. OrigRequiredAttrsArray = charray_dup ( objClass->oc_at_oids_must );
  4235. OrigAllowedAttrsArray = charray_dup ( objClass->oc_at_oids_may );
  4236. }
  4237. if (!(schema_flags & DSE_SCHEMA_NO_GLOCK)) {
  4238. oc_unlock(); /* we are done accessing superior oc (psup_oc) */
  4239. }
  4240. /*
  4241. * Finally - create new the objectclass
  4242. */
  4243. pnew_oc = (struct objclass *) slapi_ch_calloc (1, sizeof (struct objclass));
  4244. pnew_oc->oc_name = slapi_ch_strdup ( objClass->oc_names[0] );
  4245. if(objClass->oc_sup_oids){
  4246. pnew_oc->oc_superior = slapi_ch_strdup( objClass->oc_sup_oids[0] );
  4247. }
  4248. pnew_oc->oc_oid = slapi_ch_strdup( objClass->oc_oid );
  4249. pnew_oc->oc_desc = slapi_ch_strdup( objClass->oc_desc );
  4250. pnew_oc->oc_required = charray_dup( objClass->oc_at_oids_must );
  4251. pnew_oc->oc_allowed = charray_dup( objClass->oc_at_oids_may );
  4252. pnew_oc->oc_orig_required = OrigRequiredAttrsArray;
  4253. pnew_oc->oc_orig_allowed = OrigAllowedAttrsArray;
  4254. pnew_oc->oc_kind = objClass->oc_kind;
  4255. pnew_oc->oc_extensions = extensions;
  4256. pnew_oc->oc_next = NULL;
  4257. pnew_oc->oc_flags = flags;
  4258. *oc = pnew_oc;
  4259. done:
  4260. ldap_objectclass_free(objClass);
  4261. return rc;
  4262. }
  4263. #endif
  4264. /*
  4265. * schema_check_oc_attrs:
  4266. * Check to see if the required and allowed attributes are valid attributes
  4267. *
  4268. * arguments: poc : pointer to the objectclass to check
  4269. * errorbuf : buffer to write any error messages to
  4270. * stripOptions: 1 if you want to silently strip any options
  4271. * 0 if options should cause an error
  4272. *
  4273. * Returns:
  4274. *
  4275. * 0 if there's a unknown attribute, and errorbuf will contain an
  4276. * error message.
  4277. *
  4278. * 1 if everything is ok
  4279. *
  4280. * Note: no locking of poc is needed because poc is always a newly allocated
  4281. * objclass struct (this function is only called by add_oc_internal).
  4282. */
  4283. static int
  4284. schema_check_oc_attrs ( struct objclass *poc,
  4285. char *errorbuf, size_t errorbufsize,
  4286. int stripOptions )
  4287. {
  4288. int i;
  4289. if ( errorbuf == NULL || poc == NULL || poc->oc_name == NULL) {
  4290. /* error */
  4291. LDAPDebug (LDAP_DEBUG_PARSE,
  4292. "Null args passed to schema_check_oc_attrs\n",
  4293. NULL, NULL, NULL);
  4294. return -1;
  4295. }
  4296. /* remove any options like ;binary from the oc's attributes */
  4297. if ( strip_oc_options( poc ) && !stripOptions) {
  4298. /* there were options present, this oc should be rejected */
  4299. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
  4300. poc->oc_name, "Contains attribute options. "
  4301. "Attribute options, such as \";binary\" are not allowed in "
  4302. "object class definitions." );
  4303. return 0;
  4304. }
  4305. for ( i = 0; poc->oc_allowed && poc->oc_allowed[i]; i++ ) {
  4306. if ( attr_syntax_exists ( poc->oc_allowed[i] ) == 0 ) {
  4307. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
  4308. poc->oc_name, "Unknown allowed attribute type \"%s\"",
  4309. poc->oc_allowed[i]);
  4310. return 0;
  4311. }
  4312. }
  4313. for ( i = 0; poc->oc_required && poc->oc_required[i]; i++ ) {
  4314. if ( attr_syntax_exists ( poc->oc_required[i] ) == 0 ) {
  4315. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
  4316. poc->oc_name, "Unknown required attribute type \"%s\"",
  4317. poc->oc_required[i]);
  4318. return 0;
  4319. }
  4320. }
  4321. return 1;
  4322. }
  4323. /*
  4324. * schema_check_name:
  4325. * Check if the attribute or objectclass name is valid. Names can only contain
  4326. * characters, digits, and hyphens. In addition, names must begin with
  4327. * a character. If the nsslapd-attribute-name-exceptions attribute in cn=config
  4328. * is true, then we also allow underscores.
  4329. *
  4330. * XXX We're also supposed to allow semicolons, but we already use them to deal
  4331. * with attribute options XXX
  4332. *
  4333. * returns 1 if the attribute has a legal name
  4334. * 0 if not
  4335. *
  4336. * If the attribute name is invalid, an error message will be written to msg
  4337. */
  4338. static int
  4339. schema_check_name(char *name, PRBool isAttribute, char *errorbuf,
  4340. size_t errorbufsize )
  4341. {
  4342. int i;
  4343. /* allowed characters */
  4344. static char allowed[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-";
  4345. /* additional characters to allow if allow_exceptions is true */
  4346. static char allowedExceptions[] = "_";
  4347. int allow_exceptions = config_get_attrname_exceptions();
  4348. if ( name == NULL || errorbuf == NULL) {
  4349. /* this is bad */
  4350. return 0;
  4351. }
  4352. if (!strcasecmp(name, PSEUDO_ATTR_UNHASHEDUSERPASSWORD)) {
  4353. /* explicitly allow this badly named attribute */
  4354. return 1;
  4355. }
  4356. /* attribute names must begin with a letter */
  4357. if ( (isascii (name[0]) == 0) || (isalpha (name[0]) == 0)) {
  4358. if ( (strlen(name) + 80) < BUFSIZ ) {
  4359. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
  4360. name, "The name is invalid. Names must begin with a letter" );
  4361. }
  4362. else {
  4363. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
  4364. name, "The name is invalid, and probably too long. "
  4365. "Names must begin with a letter" );
  4366. }
  4367. return 0;
  4368. }
  4369. for (i = 1; name[i]; i++ ) {
  4370. if ( (NULL == strchr( allowed, name[i] )) &&
  4371. (!allow_exceptions ||
  4372. (NULL == strchr(allowedExceptions, name[i])) ) ) {
  4373. if ( (strlen(name) + 80) < BUFSIZ ) {
  4374. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
  4375. name, "The name contains the invalid character \"%c\"", name[i] );
  4376. }
  4377. else {
  4378. schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
  4379. name, "The name contains the invalid character \"%c\". The name"
  4380. " is also probably too long.", name[i] );
  4381. }
  4382. return 0;
  4383. }
  4384. }
  4385. return 1;
  4386. }
  4387. /*
  4388. * schema_check_oid:
  4389. * Check if the oid is valid.
  4390. *
  4391. * returns 1 if the attribute has a legal oid
  4392. * 0 if not
  4393. *
  4394. * If the oid is invalid, an error message will be written to errorbuf
  4395. *
  4396. * Oids can either have the form <attr/oc name>-oid or
  4397. * start and end with a digit, and contain only digits and periods
  4398. */
  4399. static int
  4400. schema_check_oid( const char *name, const char *oid, PRBool isAttribute,
  4401. char *errorbuf, size_t errorbufsize ) {
  4402. int i = 0, length_oid = 0, rc = 0;
  4403. char *namePlusOid = NULL;
  4404. if ( name == NULL || oid == NULL) {
  4405. /* this is bad */
  4406. LDAPDebug (LDAP_DEBUG_ANY, "NULL passed to schema_check_oid\n",0,0,0);
  4407. return 0;
  4408. }
  4409. /* check to see if the OID is <name>-oid */
  4410. namePlusOid = slapi_ch_smprintf("%s-oid", name );
  4411. rc = strcasecmp( oid, namePlusOid );
  4412. slapi_ch_free( (void **) &namePlusOid );
  4413. if ( 0 == rc ) {
  4414. return 1;
  4415. }
  4416. /* If not, the OID must begin and end with a digit, and contain only
  4417. digits and dots */
  4418. /* check to see that it begins and ends with a digit */
  4419. length_oid = strlen(oid);
  4420. if ( !isdigit(oid[0]) ||
  4421. !isdigit(oid[length_oid-1]) ) {
  4422. schema_create_errormsg( errorbuf, errorbufsize,
  4423. isAttribute ? schema_errprefix_at : schema_errprefix_oc,
  4424. name,
  4425. "The OID \"%s\" must begin and end with a digit, or be \"%s-oid\"",
  4426. oid, name );
  4427. return 0;
  4428. }
  4429. /* check to see that it contains only digits and dots */
  4430. for ( i = 0; i < length_oid; i++ ) {
  4431. if ( !isdigit(oid[i]) && oid[i] != '.' ){
  4432. schema_create_errormsg( errorbuf, errorbufsize,
  4433. isAttribute ? schema_errprefix_at : schema_errprefix_oc,
  4434. name,
  4435. "The OID \"%s\" contains an invalid character: \"%c\"; the"
  4436. " OID must contain only digits and periods, or be \"%s-oid\"",
  4437. oid, oid[i], name );
  4438. return 0;
  4439. }
  4440. }
  4441. /* The oid is OK if we're here */
  4442. return 1;
  4443. }
  4444. /*
  4445. * Some utility functions for dealing with a dynamically
  4446. * allocated buffer.
  4447. */
  4448. static struct sizedbuffer *sizedbuffer_construct(size_t size)
  4449. {
  4450. struct sizedbuffer *p= (struct sizedbuffer *)slapi_ch_malloc(sizeof(struct sizedbuffer));
  4451. p->size= size;
  4452. if(size>0)
  4453. {
  4454. p->buffer= (char*)slapi_ch_malloc(size);
  4455. p->buffer[0]= '\0';
  4456. }
  4457. else
  4458. {
  4459. p->buffer= NULL;
  4460. }
  4461. return p;
  4462. }
  4463. static void sizedbuffer_destroy(struct sizedbuffer *p)
  4464. {
  4465. if(p!=NULL)
  4466. {
  4467. slapi_ch_free((void**)&p->buffer);
  4468. }
  4469. slapi_ch_free((void**)&p);
  4470. }
  4471. static void sizedbuffer_allocate(struct sizedbuffer *p, size_t sizeneeded)
  4472. {
  4473. if(p!=NULL)
  4474. {
  4475. if(sizeneeded>p->size)
  4476. {
  4477. if(p->buffer!=NULL)
  4478. {
  4479. slapi_ch_free((void**)&p->buffer);
  4480. }
  4481. p->buffer= (char*)slapi_ch_malloc(sizeneeded);
  4482. p->buffer[0]= '\0';
  4483. p->size= sizeneeded;
  4484. }
  4485. }
  4486. }
  4487. /*
  4488. * Check if the object class is extensible
  4489. */
  4490. static int isExtensibleObjectclass(const char *objectclass)
  4491. {
  4492. if ( strcasecmp( objectclass, "extensibleobject" ) == 0 ) {
  4493. return( 1 );
  4494. }
  4495. /* The Easter Egg is based on a special object class */
  4496. if ( strcasecmp( objectclass, EGG_OBJECT_CLASS ) == 0 ) {
  4497. return( 1 );
  4498. }
  4499. return 0;
  4500. }
  4501. /*
  4502. * strip_oc_options: strip any attribute options from the objectclass'
  4503. * attributes (remove things like ;binary from the attrs)
  4504. *
  4505. * argument: pointer to an objectclass, attributes will have their
  4506. * options removed in place
  4507. *
  4508. * returns: number of options removed
  4509. *
  4510. * Note: no locking of poc is needed because poc is always a newly allocated
  4511. * objclass struct (this function is only called by schema_check_oc_attrs,
  4512. * which is only called by add_oc_internal).
  4513. */
  4514. static int
  4515. strip_oc_options( struct objclass *poc ) {
  4516. int i, numRemoved = 0;
  4517. char *mod = NULL;
  4518. for ( i = 0; poc->oc_allowed && poc->oc_allowed[i]; i++ ) {
  4519. if ( (mod = stripOption( poc->oc_allowed[i] )) != NULL ){
  4520. LDAPDebug (LDAP_DEBUG_ANY,
  4521. "Removed option \"%s\" from allowed attribute type "
  4522. "\"%s\" in object class \"%s\".\n",
  4523. mod, poc->oc_allowed[i], poc->oc_name );
  4524. numRemoved++;
  4525. }
  4526. }
  4527. for ( i = 0; poc->oc_required && poc->oc_required[i]; i++ ) {
  4528. if ( (mod = stripOption( poc->oc_required[i] )) != NULL ){
  4529. LDAPDebug (LDAP_DEBUG_ANY,
  4530. "Removed option \"%s\" from required attribute type "
  4531. "\"%s\" in object class \"%s\".\n",
  4532. mod, poc->oc_required[i], poc->oc_name );
  4533. numRemoved++;
  4534. }
  4535. }
  4536. return numRemoved;
  4537. }
  4538. /*
  4539. * stripOption:
  4540. * removes options such as ";binary" from attribute names
  4541. *
  4542. * argument: pointer to an attribute name, such as "userCertificate;binary"
  4543. *
  4544. * returns: pointer to the option, such as "binary"
  4545. * NULL if there's no option
  4546. *
  4547. */
  4548. static char *
  4549. stripOption(char *attr) {
  4550. char *pSemiColon = strchr( attr, ';' );
  4551. if (pSemiColon) {
  4552. *pSemiColon = '\0';
  4553. }
  4554. return pSemiColon ? pSemiColon + 1 : NULL;
  4555. }
  4556. /*
  4557. * load_schema_dse: called by dse_read_file() when target is cn=schema
  4558. *
  4559. * Initialize attributes and objectclasses from the schema
  4560. *
  4561. * Note that this function removes all values for `attributetypes'
  4562. * and `objectclasses' attributes from the entry `e'.
  4563. *
  4564. * returntext is always at least SLAPI_DSE_RETURNTEXT_SIZE bytes in size.
  4565. */
  4566. int
  4567. load_schema_dse(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *ignored,
  4568. int *returncode, char *returntext, void *arg)
  4569. {
  4570. Slapi_Attr *attr = 0;
  4571. int primary_file = 0; /* this is the primary (writeable) schema file */
  4572. int schema_ds4x_compat = config_get_ds4_compatible_schema();
  4573. PRUint32 flags = *(PRUint32 *)arg;
  4574. *returncode = 0;
  4575. /*
  4576. * Note: there is no need to call schema_lock_write() here because this
  4577. * function is only called during server startup.
  4578. */
  4579. slapi_pblock_get( pb, SLAPI_DSE_IS_PRIMARY_FILE, &primary_file );
  4580. if (!slapi_entry_attr_find(e, "attributetypes", &attr) && attr)
  4581. {
  4582. /* enumerate the values in attr */
  4583. Slapi_Value *v = 0;
  4584. int index = 0;
  4585. for (index = slapi_attr_first_value(attr, &v);
  4586. v && (index != -1);
  4587. index = slapi_attr_next_value(attr, index, &v))
  4588. {
  4589. const char *s = slapi_value_get_string(v);
  4590. if (!s)
  4591. continue;
  4592. if (flags & DSE_SCHEMA_NO_LOAD)
  4593. {
  4594. struct asyntaxinfo *tmpasip = NULL;
  4595. if ((*returncode = parse_at_str(s, &tmpasip, returntext,
  4596. SLAPI_DSE_RETURNTEXT_SIZE, flags,
  4597. primary_file /* force user defined? */,
  4598. schema_ds4x_compat, 0)) != 0)
  4599. break;
  4600. attr_syntax_free( tmpasip ); /* trash it */
  4601. }
  4602. else
  4603. {
  4604. if ((*returncode = parse_at_str(s, NULL, returntext,
  4605. SLAPI_DSE_RETURNTEXT_SIZE, flags,
  4606. primary_file /* force user defined? */,
  4607. schema_ds4x_compat, 0)) != 0)
  4608. break;
  4609. }
  4610. }
  4611. slapi_entry_attr_delete(e, "attributetypes");
  4612. }
  4613. if (*returncode)
  4614. return SLAPI_DSE_CALLBACK_ERROR;
  4615. flags |= DSE_SCHEMA_NO_GLOCK; /* don't lock global resources
  4616. during initialization */
  4617. if (!slapi_entry_attr_find(e, "objectclasses", &attr) && attr)
  4618. {
  4619. /* enumerate the values in attr */
  4620. Slapi_Value *v = 0;
  4621. int index = 0;
  4622. for (index = slapi_attr_first_value(attr, &v);
  4623. v && (index != -1);
  4624. index = slapi_attr_next_value(attr, index, &v))
  4625. {
  4626. struct objclass *oc = 0;
  4627. const char *s = slapi_value_get_string(v);
  4628. if (!s)
  4629. continue;
  4630. if ( LDAP_SUCCESS != (*returncode = parse_oc_str(s, &oc, returntext,
  4631. SLAPI_DSE_RETURNTEXT_SIZE, flags,
  4632. primary_file /* force user defined? */,
  4633. schema_ds4x_compat, NULL)))
  4634. {
  4635. oc_free( &oc );
  4636. break;
  4637. }
  4638. if (flags & DSE_SCHEMA_NO_LOAD)
  4639. {
  4640. /* we don't load the objectclase; free it */
  4641. oc_free( &oc );
  4642. }
  4643. else
  4644. {
  4645. if ( LDAP_SUCCESS !=
  4646. (*returncode = add_oc_internal(oc, returntext,
  4647. SLAPI_DSE_RETURNTEXT_SIZE, schema_ds4x_compat,
  4648. flags))) {
  4649. oc_free( &oc );
  4650. break;
  4651. }
  4652. }
  4653. }
  4654. slapi_entry_attr_delete(e, "objectclasses");
  4655. }
  4656. /* Set the schema CSN */
  4657. if (!(flags & DSE_SCHEMA_NO_LOAD) &&
  4658. !slapi_entry_attr_find(e, "nsschemacsn", &attr) && attr)
  4659. {
  4660. Slapi_Value *v = NULL;
  4661. slapi_attr_first_value(attr, &v);
  4662. if (NULL != v) {
  4663. const char *s = slapi_value_get_string(v);
  4664. if (NULL != s) {
  4665. CSN *csn = csn_new_by_string(s);
  4666. g_set_global_schema_csn(csn);
  4667. }
  4668. }
  4669. }
  4670. return (*returncode == LDAP_SUCCESS) ? SLAPI_DSE_CALLBACK_OK
  4671. : SLAPI_DSE_CALLBACK_ERROR;
  4672. }
  4673. /*
  4674. * Try to initialize the schema from the LDIF file. Read
  4675. * the file and convert it to the avl tree of DSEs. If the
  4676. * file doesn't exist, we try to create it and put a minimal
  4677. * schema entry into it.
  4678. *
  4679. * Returns 1 for OK, 0 for Fail.
  4680. *
  4681. * schema_flags:
  4682. * DSE_SCHEMA_NO_LOAD -- schema won't get loaded
  4683. * DSE_SCHEMA_NO_CHECK -- schema won't be checked
  4684. * DSE_SCHEMA_NO_BACKEND -- don't add as backend
  4685. * DSE_SCHEMA_LOCKED -- already locked; no further lock needed
  4686. */
  4687. static int
  4688. init_schema_dse_ext(char *schemadir, Slapi_Backend *be,
  4689. struct dse **local_pschemadse, PRUint32 schema_flags)
  4690. {
  4691. int rc= 1; /* OK */
  4692. char *userschemafile = 0;
  4693. char *userschematmpfile = 0;
  4694. char **filelist = 0;
  4695. char *myschemadir = NULL;
  4696. Slapi_DN schema;
  4697. if (NULL == local_pschemadse)
  4698. {
  4699. return 0; /* cannot proceed; return failure */
  4700. }
  4701. *local_pschemadse = NULL;
  4702. slapi_sdn_init_ndn_byref(&schema,"cn=schema");
  4703. /* get schemadir if not given */
  4704. if (NULL == schemadir)
  4705. {
  4706. myschemadir = config_get_schemadir();
  4707. if (NULL == myschemadir)
  4708. {
  4709. return 0; /* cannot proceed; return failure */
  4710. }
  4711. }
  4712. else
  4713. {
  4714. myschemadir = schemadir;
  4715. }
  4716. filelist = get_priority_filelist(myschemadir, ".*ldif$");
  4717. if (!filelist || !*filelist)
  4718. {
  4719. slapi_log_error(SLAPI_LOG_FATAL, "schema",
  4720. "No schema files were found in the directory %s\n", myschemadir);
  4721. free_filelist(filelist);
  4722. rc = 0;
  4723. }
  4724. else
  4725. {
  4726. /* figure out the last file in the list; it is the user schema */
  4727. int ii = 0;
  4728. while (filelist[ii]) ++ii;
  4729. userschemafile = filelist[ii-1];
  4730. userschematmpfile = slapi_ch_smprintf("%s.tmp", userschemafile);
  4731. }
  4732. if(rc)
  4733. {
  4734. *local_pschemadse = dse_new_with_filelist(userschemafile,
  4735. userschematmpfile, NULL, NULL, myschemadir, filelist);
  4736. }
  4737. PR_ASSERT(*local_pschemadse);
  4738. if ((rc = (*local_pschemadse != NULL)) != 0)
  4739. {
  4740. /* pass schema_flags as arguments */
  4741. dse_register_callback(*local_pschemadse,
  4742. DSE_OPERATION_READ, DSE_FLAG_PREOP, &schema,
  4743. LDAP_SCOPE_BASE, NULL,
  4744. load_schema_dse, (void *)&schema_flags, NULL);
  4745. }
  4746. slapi_ch_free_string(&userschematmpfile);
  4747. if (NULL == schemadir)
  4748. slapi_ch_free_string(&myschemadir); /* allocated in this function */
  4749. if(rc)
  4750. {
  4751. char errorbuf[SLAPI_DSE_RETURNTEXT_SIZE] = {0};
  4752. char *attr_str;
  4753. int dont_write = 1;
  4754. int merge = 1;
  4755. int dont_dup_check = 1;
  4756. Slapi_PBlock pb;
  4757. memset(&pb, 0, sizeof(pb));
  4758. /* don't write out the file when reading */
  4759. slapi_pblock_set(&pb, SLAPI_DSE_DONT_WRITE_WHEN_ADDING, (void*)&dont_write);
  4760. /* duplicate entries are allowed */
  4761. slapi_pblock_set(&pb, SLAPI_DSE_MERGE_WHEN_ADDING, (void*)&merge);
  4762. /* use the non duplicate checking str2entry */
  4763. slapi_pblock_set(&pb, SLAPI_DSE_DONT_CHECK_DUPS, (void*)&dont_dup_check);
  4764. /* borrow the task flag space */
  4765. slapi_pblock_set(&pb, SLAPI_SCHEMA_FLAGS, (void*)&schema_flags);
  4766. /* add the objectclass attribute so we can do some basic schema
  4767. checking during initialization; this will be overridden when
  4768. its "real" definition is read from the schema conf files */
  4769. #ifdef USE_OPENLDAP
  4770. attr_str = "( 2.5.4.0 NAME 'objectClass' "
  4771. "DESC 'Standard schema for LDAP' SYNTAX "
  4772. "1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2252' )";
  4773. #else
  4774. attr_str = "attributeTypes: ( 2.5.4.0 NAME 'objectClass' "
  4775. "DESC 'Standard schema for LDAP' SYNTAX "
  4776. "1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2252' )";
  4777. #endif
  4778. if (schema_flags & DSE_SCHEMA_NO_LOAD)
  4779. {
  4780. struct asyntaxinfo *tmpasip = NULL;
  4781. rc = parse_at_str(attr_str, &tmpasip, errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
  4782. DSE_SCHEMA_NO_GLOCK|schema_flags, 0, 0, 0);
  4783. attr_syntax_free( tmpasip ); /* trash it */
  4784. }
  4785. else
  4786. {
  4787. rc = parse_at_str(attr_str, NULL, errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
  4788. schema_flags, 0, 0, 0);
  4789. }
  4790. if (rc)
  4791. {
  4792. slapi_log_error(SLAPI_LOG_FATAL, "schema", "Could not add"
  4793. " attribute type \"objectClass\" to the schema: %s\n",
  4794. errorbuf);
  4795. }
  4796. rc = dse_read_file(*local_pschemadse, &pb);
  4797. }
  4798. if (rc && !(schema_flags & DSE_SCHEMA_NO_BACKEND))
  4799. {
  4800. /* make sure the schema is normalized */
  4801. if (schema_flags & DSE_SCHEMA_LOCKED)
  4802. normalize_oc_nolock();
  4803. else
  4804. normalize_oc();
  4805. /* register callbacks */
  4806. dse_register_callback(*local_pschemadse, SLAPI_OPERATION_SEARCH,
  4807. DSE_FLAG_PREOP,&schema, LDAP_SCOPE_BASE,
  4808. NULL, read_schema_dse, NULL, NULL);
  4809. dse_register_callback(*local_pschemadse, SLAPI_OPERATION_MODIFY,
  4810. DSE_FLAG_PREOP,&schema, LDAP_SCOPE_BASE,
  4811. NULL, modify_schema_dse, NULL, NULL);
  4812. dse_register_callback(*local_pschemadse, SLAPI_OPERATION_DELETE,
  4813. DSE_FLAG_PREOP, &schema, LDAP_SCOPE_BASE,
  4814. NULL,dont_allow_that,NULL, NULL);
  4815. dse_register_callback(*local_pschemadse, DSE_OPERATION_WRITE,
  4816. DSE_FLAG_PREOP, &schema, LDAP_SCOPE_BASE,
  4817. NULL, refresh_user_defined_schema, NULL, NULL);
  4818. if (rc) {
  4819. if (NULL == be) { /* be is not given. select it */
  4820. be = slapi_be_select_by_instance_name( DSE_SCHEMA );
  4821. }
  4822. if (NULL == be) { /* first time */
  4823. /* add as a backend */
  4824. be = be_new_internal(*local_pschemadse, "DSE", DSE_SCHEMA);
  4825. be_addsuffix(be, &schema);
  4826. } else { /* schema file reload */
  4827. struct slapdplugin *backend_plugin = NULL;
  4828. be_replace_dse_internal(be, *local_pschemadse);
  4829. /* ldbm has some internal attributes to be added */
  4830. backend_plugin = plugin_get_by_name("ldbm database");
  4831. if (backend_plugin) {
  4832. if (backend_plugin->plg_add_schema) {
  4833. (backend_plugin->plg_add_schema)( NULL );
  4834. } else {
  4835. slapi_log_error( SLAPI_LOG_FATAL, "init_schema_dse",
  4836. "backend has not set internal schema\n" );
  4837. }
  4838. }
  4839. }
  4840. }
  4841. }
  4842. slapi_sdn_done(&schema);
  4843. return rc;
  4844. }
  4845. int
  4846. init_schema_dse(const char *configdir)
  4847. {
  4848. char *schemadir = config_get_schemadir();
  4849. int rc = 0;
  4850. if (NULL == schemadir)
  4851. {
  4852. schemadir = slapi_ch_smprintf("%s/%s", configdir, SCHEMA_SUBDIR_NAME);
  4853. }
  4854. rc = init_schema_dse_ext(schemadir, NULL, &pschemadse, DSE_SCHEMA_NO_GLOCK);
  4855. slapi_ch_free_string(&schemadir);
  4856. return rc;
  4857. }
  4858. #if !defined (USE_OPENLDAP)
  4859. static char **
  4860. parse_xstring_list( const char *schema_value, const char *name, size_t namelen, int *num_xvalsp,
  4861. char **default_list )
  4862. {
  4863. char *start, *end, *xval_tmp;
  4864. char **xvals = NULL;
  4865. if (( start = PL_strstr ( schema_value, name )) != NULL) {
  4866. start += namelen+1; /* +1 for space */
  4867. xval_tmp = slapi_ch_strdup( start );
  4868. if ( *start == '(' ) {
  4869. end = strchr( xval_tmp, ')' );
  4870. } else {
  4871. end = strchr( xval_tmp + 1, '\'' );
  4872. }
  4873. if (end) {
  4874. *(end+1) = 0;
  4875. }
  4876. xvals = parse_qdstrings( xval_tmp, num_xvalsp );
  4877. slapi_ch_free( (void **)&xval_tmp );
  4878. } else {
  4879. xvals = NULL;
  4880. *num_xvalsp = 0;
  4881. }
  4882. if ( NULL == xvals && NULL != default_list ) {
  4883. int i;
  4884. for ( i = 0; default_list[i] != NULL; ++i ) {
  4885. ;
  4886. }
  4887. *num_xvalsp = i;
  4888. xvals = (char **)slapi_ch_malloc( (i+1) * sizeof(char *));
  4889. for ( i = 0; default_list[i] != NULL; ++i ) {
  4890. xvals[i] = slapi_ch_strdup( default_list[i] );
  4891. }
  4892. xvals[i] = NULL;
  4893. }
  4894. /* for debugging
  4895. if ( xvals == NULL || xvals[0] == NULL ) {
  4896. LDAPDebug( LDAP_DEBUG_ANY, "no xstring values for xstring (%s) in (%s)\n", name, schema_value, 0 );
  4897. }
  4898. */
  4899. return xvals;
  4900. }
  4901. /* used by mozldap read_at_ldif() & read_oc_ldif() */
  4902. static schemaext*
  4903. parse_extensions( const char *schema_value, char **default_list )
  4904. {
  4905. schemaext *extensions = NULL, *head = NULL;
  4906. char *input, *token, *iter = NULL;
  4907. int i;
  4908. /*
  4909. * First make a copy of the input, then grab all the "X-" words,
  4910. * and extract the values.
  4911. */
  4912. input = slapi_ch_strdup(schema_value);
  4913. token = ldap_utf8strtok_r(input, " ", &iter);
  4914. while(token){
  4915. if(strncmp(token,"X-", 2) == 0){
  4916. /* we have a new extension */
  4917. schemaext *newext;
  4918. newext = (schemaext *)slapi_ch_calloc(1, sizeof (schemaext));
  4919. newext->term = slapi_ch_strdup(token);
  4920. newext->values = parse_xstring_list(schema_value, token, strlen(token), &newext->value_count, default_list);
  4921. if(extensions == NULL){
  4922. extensions = newext;
  4923. head = newext;
  4924. } else {
  4925. extensions->next = newext;
  4926. extensions = extensions->next;
  4927. }
  4928. }
  4929. token = ldap_utf8strtok_r(iter, " ", &iter);
  4930. }
  4931. extensions = head;
  4932. /*
  4933. * Ok, if X-ORIGIN was not specified, then add it with the default values
  4934. */
  4935. if ( !extension_is_user_defined(extensions) && default_list ) {
  4936. int added = 0;
  4937. while(extensions){
  4938. if(strcmp(extensions->term, "X-ORIGIN") == 0){
  4939. charray_add(&extensions->values, slapi_ch_strdup(default_list[0]) );
  4940. extensions->value_count++;
  4941. added = 1;
  4942. extensions = head;
  4943. break;
  4944. }
  4945. extensions = extensions->next;
  4946. }
  4947. if(!added){
  4948. schemaext *newext = (schemaext *)slapi_ch_calloc(1, sizeof (schemaext));
  4949. newext->term = slapi_ch_strdup("X-ORIGIN");
  4950. for ( i = 0; default_list[i]; ++i ){
  4951. newext->value_count++;
  4952. charray_add(&newext->values, slapi_ch_strdup(default_list[i]) );
  4953. }
  4954. extensions = head;
  4955. while(extensions && extensions->next){
  4956. /* move to the end of the list */
  4957. extensions = extensions->next;
  4958. }
  4959. if(extensions == NULL){
  4960. extensions = newext;
  4961. } else {
  4962. extensions->next = newext;
  4963. }
  4964. }
  4965. }
  4966. slapi_ch_free_string(&input);
  4967. return extensions;
  4968. }
  4969. /*
  4970. * Look for `keyword' within `*inputp' and return the flag_value if found
  4971. * (zero if returned if not found).
  4972. *
  4973. * If the keyword is found, `*inputp' is set to point just beyond the end of
  4974. * the keyword. If the keyword is not found, `*inputp' is not changed.
  4975. *
  4976. * The `strstr_fn' function pointer is used to search for `keyword', e.g., it
  4977. * could be PL_strcasestr().
  4978. *
  4979. * The string passed in `keyword' MUST include a trailing space, e.g.,
  4980. *
  4981. * flag |= get_flag_keyword( " COLLECTIVE ", SLAPI_ATTR_FLAG_COLLECTIVE,
  4982. * &input, PL_strcasestr );
  4983. *
  4984. */
  4985. static int
  4986. get_flag_keyword( const char *keyword, int flag_value, const char **inputp,
  4987. schema_strstr_fn_t strstr_fn )
  4988. {
  4989. const char *kw;
  4990. PR_ASSERT( NULL != inputp );
  4991. PR_ASSERT( NULL != *inputp );
  4992. PR_ASSERT( ' ' == keyword[ strlen( keyword ) - 1 ] );
  4993. if ( NULL == strstr_fn ) {
  4994. strstr_fn = PL_strcasestr;
  4995. }
  4996. kw = (*strstr_fn)( *inputp, keyword );
  4997. if ( NULL == kw ) {
  4998. flag_value = 0; /* not found -- return no value */
  4999. } else {
  5000. *inputp = kw + strlen( keyword ) - 1; /* advance input */
  5001. }
  5002. return flag_value;
  5003. }
  5004. /*
  5005. * Look for `tag' within `*inputp' and return the OID string following `tag'.
  5006. * If the OID has single quotes around it they are removed (they are allowed
  5007. * for compatibility with DS 3.x and 4.x).
  5008. *
  5009. * If the tag is found, `*inputp' is set to point just beyond the end of
  5010. * the OID that was extracted and returned. If the tag is not found,
  5011. * `*inputp' is not changed.
  5012. *
  5013. * The `strstr_fn' function pointer is used to search for `tag', e.g., it
  5014. * could be PL_strcasestr().
  5015. *
  5016. * The string passed in `tag' SHOULD generally include a trailing space, e.g.,
  5017. *
  5018. * pSuperior = get_tagged_oid( "SUP ", &input, PL_strcasestr );
  5019. *
  5020. * The exception to this is when the tag contains '(' as a trailing character.
  5021. * This is used to process lists of oids, such as the following:
  5022. *
  5023. * SUP (inetOrgPerson $ testUser)
  5024. *
  5025. * A malloc'd string is returned if `tag; is found and NULL if not.
  5026. */
  5027. static char *
  5028. get_tagged_oid( const char *tag, const char **inputp,
  5029. schema_strstr_fn_t strstr_fn )
  5030. {
  5031. const char *startp, *endp;
  5032. char *oid;
  5033. PR_ASSERT( NULL != inputp );
  5034. PR_ASSERT( NULL != *inputp );
  5035. PR_ASSERT( NULL != tag );
  5036. PR_ASSERT( '\0' != tag[ 0 ] );
  5037. if('(' !=tag[0])
  5038. PR_ASSERT((' ' == tag[ strlen( tag ) - 1 ]) || ('(' == tag[ strlen( tag ) - 1 ]));
  5039. if ( NULL == strstr_fn ) {
  5040. strstr_fn = PL_strcasestr;
  5041. }
  5042. oid = NULL;
  5043. if ( NULL != ( startp = (*strstr_fn)( *inputp, tag ))) {
  5044. startp += strlen( tag );
  5045. /* skip past any extra white space */
  5046. if ( NULL == ( startp = skipWS( startp ))) {
  5047. return( NULL );
  5048. }
  5049. /* skip past the leading single quote, if present */
  5050. if ( *startp == '\'' ) {
  5051. ++startp;
  5052. /* skip past any extra white space */
  5053. startp = skipWS( startp );
  5054. }
  5055. /* locate the end of the OID */
  5056. if ((NULL != ( endp = strchr( startp, ' '))) ||
  5057. (NULL != (endp = strchr( startp, ')'))) ) {
  5058. if ( '\'' == *(endp-1) && endp > startp ) {
  5059. --endp; /* ignore trailing quote */
  5060. }
  5061. } else {
  5062. endp = startp + strlen( startp ); /* remainder of input */
  5063. }
  5064. oid = slapi_ch_malloc( endp - startp + 1 );
  5065. memcpy( oid, startp, endp - startp );
  5066. oid[ endp - startp ] = '\0';
  5067. *inputp = endp;
  5068. }
  5069. return( oid );
  5070. }
  5071. #endif
  5072. /*
  5073. * sprintf to `outp' the contents of `tag' followed by `oid' followed by a
  5074. * trailing space. If enquote is non-zero, single quotes are included
  5075. * around the `oid' string. If `suffix' is not NULL, it is output directly
  5076. * after the `oid' (before the trailing space).
  5077. * Note that `tag' should typically include a trailing space, e.g.,
  5078. *
  5079. * outp += put_tagged_oid( outp, "SUP ", "1.2.3.4", NULL, enquote_oids );
  5080. *
  5081. * Returns the number of bytes copied to `outp' or 0 if `oid' is NULL.
  5082. */
  5083. static int
  5084. put_tagged_oid( char *outp, const char *tag, const char *oid,
  5085. const char *suffix, int enquote )
  5086. {
  5087. int count = 0;
  5088. if ( NULL == suffix ) {
  5089. suffix = "";
  5090. }
  5091. if ( NULL != oid ) {
  5092. if ( enquote ) {
  5093. count = sprintf( outp, "%s'%s%s' ", tag, oid, suffix );
  5094. } else {
  5095. count = sprintf( outp, "%s%s%s ", tag, oid, suffix );
  5096. }
  5097. }
  5098. return( count );
  5099. }
  5100. /*
  5101. * Add to `buf' a string of the form:
  5102. *
  5103. * prefix SPACE ( oid1 $ oid2 ... ) SPACE
  5104. * OR
  5105. * prefix SPACE oid SPACE
  5106. *
  5107. * The part after <prefix> matches the `oids' definition
  5108. * from RFC 2252 section 4.1.
  5109. *
  5110. * If oids is NULL or an empty array, `buf' is not touched.
  5111. */
  5112. static void
  5113. strcat_oids( char *buf, char *prefix, char **oids, int schema_ds4x_compat )
  5114. {
  5115. char *p;
  5116. int i;
  5117. if ( NULL != oids && NULL != oids[0] ) {
  5118. p = buf + strlen(buf); /* skip past existing content */
  5119. if ( NULL == oids[1] && !schema_ds4x_compat ) {
  5120. sprintf( p, "%s %s ", prefix, oids[0] ); /* just one oid */
  5121. } else {
  5122. sprintf( p, "%s ( ", prefix ); /* oidlist */
  5123. for ( i = 0; oids[i] != NULL; ++i ) {
  5124. if ( i > 0 ) {
  5125. strcat( p, " $ " );
  5126. }
  5127. strcat( p, oids[i] );
  5128. }
  5129. strcat( p, " ) " );
  5130. }
  5131. }
  5132. }
  5133. /*
  5134. * Add to `buf' a string of the form:
  5135. *
  5136. * prefix SPACE ( 's1' 's2' ... ) SPACE
  5137. * OR
  5138. * prefix SPACE 's1' SPACE
  5139. *
  5140. * The part after <prefix> matches the qdescs definition
  5141. * from RFC 2252 section 4.1.
  5142. *
  5143. * A count of the number of bytes added to buf or needed is returned.
  5144. *
  5145. * If buf is NULL, no copying is done but the number of bytes needed
  5146. * is calculated and returned. This is useful if you need to allocate
  5147. * space before calling this function will a buffer.
  5148. *
  5149. */
  5150. static size_t
  5151. strcat_qdlist( char *buf, char *prefix, char **qdlist )
  5152. {
  5153. int i;
  5154. char *start, *p;
  5155. size_t len = 0;
  5156. if ( NULL != qdlist && NULL != qdlist[0] ) {
  5157. if ( NULL == buf ) { /* calculate length only */
  5158. len += strlen( prefix );
  5159. if ( NULL != qdlist[1] ) {
  5160. len += 4; /* surrounding spaces and '(' and ')' */
  5161. }
  5162. for ( i = 0; NULL != qdlist[i]; ++i ) {
  5163. len += 3; /* leading space and quote marks */
  5164. len += strlen(qdlist[i]);
  5165. }
  5166. ++len; /* trailing space */
  5167. } else {
  5168. p = start = buf + strlen(buf); /* skip past existing content */
  5169. if ( NULL == qdlist[1] ) { /* just one string */
  5170. p += sprintf( p, "%s '%s' ", prefix, qdlist[0] );
  5171. } else { /* a list of strings */
  5172. p += sprintf( p, "%s (", prefix );
  5173. for ( i = 0; qdlist[i] != NULL; ++i ) {
  5174. p += sprintf( p, " '%s'", qdlist[i] );
  5175. }
  5176. *p++ = ' ';
  5177. *p++ = ')';
  5178. *p++ = ' ';
  5179. *p = '\0';
  5180. }
  5181. len = p - start;
  5182. }
  5183. }
  5184. return( len );
  5185. }
  5186. /*
  5187. * Loop over the extensions calling strcat_qdlist for each one.
  5188. */
  5189. static size_t
  5190. strcat_extensions( char *buf, schemaext *extension )
  5191. {
  5192. size_t len = 0;
  5193. while(extension){
  5194. len += strcat_qdlist(buf, extension->term, extension->values);
  5195. extension = extension->next;
  5196. }
  5197. return( len );
  5198. }
  5199. /*
  5200. * Just like strlen() except that 0 is returned if `s' is NULL.
  5201. */
  5202. static size_t
  5203. strlen_null_ok(const char *s)
  5204. {
  5205. if ( NULL == s ) {
  5206. return( 0 );
  5207. }
  5208. return( strlen( s ));
  5209. }
  5210. /*
  5211. * Like strcpy() except a count of the number of bytes copied is returned.
  5212. */
  5213. static int
  5214. strcpy_count( char *dst, const char *src )
  5215. {
  5216. char *p;
  5217. p = dst;
  5218. while ( *src != '\0' ) {
  5219. *p++ = *src++;
  5220. }
  5221. *p = '\0';
  5222. return( p - dst );
  5223. }
  5224. static int
  5225. extension_is_user_defined( schemaext *extensions )
  5226. {
  5227. while(extensions){
  5228. if(strcasecmp(extensions->term, "X-ORIGIN") == 0 ){
  5229. int i = 0;
  5230. while(extensions->values && extensions->values[i]){
  5231. if(strcasecmp(schema_user_defined_origin[0], extensions->values[i]) == 0) {
  5232. return 1;
  5233. }
  5234. i++;
  5235. }
  5236. }
  5237. extensions = extensions->next;
  5238. }
  5239. return 0;
  5240. }
  5241. /*
  5242. * Return PR_TRUE if the attribute type named 'type' is one of those that
  5243. * we handle directly in this file (in the scheme DSE callbacks).
  5244. * Other types are handled by the generic DSE code in dse.c.
  5245. */
  5246. /* subschema DSE attribute types we handle within the DSE callback */
  5247. static char *schema_interesting_attr_types[] = {
  5248. "dITStructureRules",
  5249. "nameForms",
  5250. "dITContentRules",
  5251. "objectClasses",
  5252. "attributeTypes",
  5253. "matchingRules",
  5254. "matchingRuleUse",
  5255. "ldapSyntaxes",
  5256. "nsschemacsn",
  5257. NULL
  5258. };
  5259. static PRBool
  5260. schema_type_is_interesting( const char *type )
  5261. {
  5262. int i;
  5263. for ( i = 0; schema_interesting_attr_types[i] != NULL; ++i ) {
  5264. if ( 0 == strcasecmp( type, schema_interesting_attr_types[i] )) {
  5265. return PR_TRUE;
  5266. }
  5267. }
  5268. return PR_FALSE;
  5269. }
  5270. static void
  5271. schema_create_errormsg(
  5272. char *errorbuf,
  5273. size_t errorbufsize,
  5274. const char *prefix,
  5275. const char *name,
  5276. const char *fmt,
  5277. ...
  5278. )
  5279. {
  5280. if ( NULL != errorbuf ) {
  5281. va_list ap;
  5282. int rc = 0;
  5283. va_start( ap, fmt );
  5284. if ( NULL != name ) {
  5285. rc = PR_snprintf( errorbuf, errorbufsize, prefix, name );
  5286. }
  5287. /* ok to cast here because rc is positive */
  5288. if ( (rc >= 0) && ((size_t)rc < errorbufsize) ) {
  5289. (void)PR_vsnprintf( errorbuf + rc, errorbufsize - rc, fmt, ap );
  5290. }
  5291. va_end( ap );
  5292. }
  5293. }
  5294. /*
  5295. * va_locate_oc_val finds an objectclass within the array of values in va.
  5296. * First oc_name is used, falling back to oc_oid. oc_oid can be NULL.
  5297. * oc_name and oc_oid should be official names (no trailing spaces). But
  5298. * trailing spaces within the va are ignored if appropriate.
  5299. *
  5300. * Returns >=0 if found (index into va) and -1 if not found.
  5301. */
  5302. static int
  5303. va_locate_oc_val( Slapi_Value **va, const char *oc_name, const char *oc_oid )
  5304. {
  5305. int i;
  5306. const char *strval;
  5307. if ( NULL == va || oc_name == NULL ) { /* nothing to look for */
  5308. return -1;
  5309. }
  5310. if ( !schema_ignore_trailing_spaces ) {
  5311. for ( i = 0; va[i] != NULL; i++ ) {
  5312. strval = slapi_value_get_string(va[i]);
  5313. if ( NULL != strval ) {
  5314. if ( 0 == strcasecmp(strval, oc_name)) {
  5315. return i;
  5316. }
  5317. if ( NULL != oc_oid
  5318. && 0 == strcasecmp( strval, oc_oid )) {
  5319. return i;
  5320. }
  5321. }
  5322. }
  5323. } else {
  5324. /*
  5325. * Ignore trailing spaces when comparing object class names.
  5326. */
  5327. size_t len;
  5328. const char *p;
  5329. for ( i = 0; va[i] != NULL; i++ ) {
  5330. strval = slapi_value_get_string(va[i]);
  5331. if ( NULL != strval ) {
  5332. for ( p = strval, len = 0; (*p != '\0') && (*p != ' ');
  5333. p++, len++ ) {
  5334. ; /* NULL */
  5335. }
  5336. if ( 0 == strncasecmp(oc_name, strval, len )
  5337. && ( len == strlen(oc_name))) {
  5338. return i;
  5339. }
  5340. if ( NULL != oc_oid
  5341. && ( 0 == strncasecmp( oc_oid, strval, len ))
  5342. && ( len == strlen(oc_oid))) {
  5343. return i;
  5344. }
  5345. }
  5346. }
  5347. }
  5348. return -1; /* not found */
  5349. }
  5350. /*
  5351. * va_expand_one_oc is used to add missing superclass values to the
  5352. * objectclass attribute when an entry is added or modified.
  5353. *
  5354. * missing values are always added to the end of the 'vap' array.
  5355. *
  5356. * Note: calls to this function MUST be bracketed by lock()/unlock(), i.e.,
  5357. *
  5358. * oc_lock_read();
  5359. * va_expand_one_oc( b, o );
  5360. * oc_unlock();
  5361. */
  5362. static void
  5363. va_expand_one_oc( const char *dn, const Slapi_Attr *a, Slapi_ValueSet *vs, const char *ocs )
  5364. {
  5365. struct objclass *this_oc, *sup_oc;
  5366. int p;
  5367. Slapi_Value **va = vs->va;
  5368. this_oc = oc_find_nolock( ocs, NULL, PR_FALSE );
  5369. if ( this_oc == NULL ) {
  5370. return; /* skip unknown object classes */
  5371. }
  5372. if ( this_oc->oc_superior == NULL ) {
  5373. return; /* no superior */
  5374. }
  5375. sup_oc = oc_find_nolock( this_oc->oc_superior, NULL, PR_FALSE );
  5376. if ( sup_oc == NULL ) {
  5377. return; /* superior is unknown -- ignore */
  5378. }
  5379. p = va_locate_oc_val( va, sup_oc->oc_name, sup_oc->oc_oid );
  5380. if ( p != -1 ) {
  5381. return; /* value already present -- done! */
  5382. }
  5383. if ( slapi_valueset_count(vs) > 1000 ) {
  5384. return;
  5385. }
  5386. slapi_valueset_add_attr_value_ext(a, vs, slapi_value_new_string(sup_oc->oc_name), SLAPI_VALUE_FLAG_PASSIN);
  5387. LDAPDebug( LDAP_DEBUG_TRACE,
  5388. "Entry \"%s\": added missing objectClass value %s\n",
  5389. dn, sup_oc->oc_name, 0 );
  5390. }
  5391. /*
  5392. * Expand the objectClass values in 'e' to take superior classes into account.
  5393. * All missing superior classes are added to the objectClass attribute, as
  5394. * is 'top' if it is missing.
  5395. */
  5396. static void
  5397. schema_expand_objectclasses_ext( Slapi_Entry *e, int lock)
  5398. {
  5399. Slapi_Attr *sa;
  5400. Slapi_Value *v;
  5401. Slapi_ValueSet *vs;
  5402. const char *dn = slapi_entry_get_dn_const( e );
  5403. int i;
  5404. if ( 0 != slapi_entry_attr_find( e, SLAPI_ATTR_OBJECTCLASS, &sa )) {
  5405. return; /* no OC values -- nothing to do */
  5406. }
  5407. vs = &sa->a_present_values;
  5408. if ( slapi_valueset_isempty(vs) ) {
  5409. return; /* no OC values -- nothing to do */
  5410. }
  5411. if (lock)
  5412. oc_lock_read();
  5413. /*
  5414. * This loop relies on the fact that bv_expand_one_oc()
  5415. * always adds to the end
  5416. */
  5417. i = slapi_valueset_first_value(vs,&v);
  5418. while ( v != NULL) {
  5419. if ( NULL != slapi_value_get_string(v) ) {
  5420. va_expand_one_oc( dn, sa, &sa->a_present_values, slapi_value_get_string(v) );
  5421. }
  5422. i = slapi_valueset_next_value(vs, i, &v);
  5423. }
  5424. /* top must always be present */
  5425. va_expand_one_oc( dn, sa, &sa->a_present_values, "top" );
  5426. if (lock)
  5427. oc_unlock();
  5428. }
  5429. void
  5430. slapi_schema_expand_objectclasses( Slapi_Entry *e )
  5431. {
  5432. schema_expand_objectclasses_ext( e, 1);
  5433. }
  5434. void
  5435. schema_expand_objectclasses_nolock( Slapi_Entry *e )
  5436. {
  5437. schema_expand_objectclasses_ext( e, 0);
  5438. }
  5439. /* lock to protect both objectclass and schema_dse */
  5440. static void
  5441. reload_schemafile_lock()
  5442. {
  5443. oc_lock_write();
  5444. schema_dse_lock_write();
  5445. }
  5446. static void
  5447. reload_schemafile_unlock()
  5448. {
  5449. schema_dse_unlock();
  5450. oc_unlock();
  5451. }
  5452. /* API to validate the schema files */
  5453. int
  5454. slapi_validate_schema_files(char *schemadir)
  5455. {
  5456. struct dse *my_pschemadse = NULL;
  5457. int rc = init_schema_dse_ext(schemadir, NULL, &my_pschemadse,
  5458. DSE_SCHEMA_NO_LOAD | DSE_SCHEMA_NO_BACKEND);
  5459. dse_destroy(my_pschemadse); /* my_pschemadse was created just to
  5460. validate the schema */
  5461. if (rc) {
  5462. return LDAP_SUCCESS;
  5463. } else {
  5464. slapi_log_error( SLAPI_LOG_FATAL, "schema_reload",
  5465. "schema file validation failed\n" );
  5466. return LDAP_OBJECT_CLASS_VIOLATION;
  5467. }
  5468. }
  5469. /*
  5470. * Reload the schema files
  5471. *
  5472. * This is only called from the schema_reload task. The flag DSE_SCHEMA_LOCKED
  5473. * is also only set been called from this function. To not interrupt clients
  5474. * we will rebuild the schema in separate hash tables, and then swap the
  5475. * hash tables once the schema is completely reloaded. We use the DSE_SCHEMA_LOCKED
  5476. * flag to tell the attribute syntax functions to use the temporary hashtables.
  5477. */
  5478. int
  5479. slapi_reload_schema_files(char *schemadir)
  5480. {
  5481. int rc = LDAP_SUCCESS;
  5482. struct dse *my_pschemadse = NULL;
  5483. /* get be to lock */
  5484. Slapi_Backend *be = slapi_be_select_by_instance_name( DSE_SCHEMA );
  5485. if (NULL == be)
  5486. {
  5487. slapi_log_error( SLAPI_LOG_FATAL, "schema_reload",
  5488. "schema file reload failed\n" );
  5489. return LDAP_LOCAL_ERROR;
  5490. }
  5491. slapi_be_Wlock(be); /* be lock must be outer of schemafile lock */
  5492. reload_schemafile_lock();
  5493. oc_delete_all_nolock();
  5494. rc = init_schema_dse_ext(schemadir, be, &my_pschemadse,
  5495. DSE_SCHEMA_NO_CHECK | DSE_SCHEMA_LOCKED);
  5496. if (rc) {
  5497. /*
  5498. * The schema has been reloaded into the temporary hash tables.
  5499. * Take the write lock, wipe out the existing hash tables, and
  5500. * swap in the new ones.
  5501. */
  5502. attr_syntax_write_lock();
  5503. attr_syntax_delete_all_for_schemareload(SLAPI_ATTR_FLAG_KEEP);
  5504. attr_syntax_swap_ht();
  5505. attr_syntax_unlock_write();
  5506. slapi_reload_internal_attr_syntax();
  5507. dse_destroy(pschemadse);
  5508. pschemadse = my_pschemadse;
  5509. reload_schemafile_unlock();
  5510. slapi_be_Unlock(be);
  5511. return LDAP_SUCCESS;
  5512. } else {
  5513. reload_schemafile_unlock();
  5514. slapi_be_Unlock(be);
  5515. slapi_log_error( SLAPI_LOG_FATAL, "schema_reload",
  5516. "schema file reload failed\n" );
  5517. return LDAP_LOCAL_ERROR;
  5518. }
  5519. }
  5520. /*
  5521. * slapi_schema_list_objectclass_attributes:
  5522. * Return the list of attributes belonging to the objectclass
  5523. *
  5524. * The caller is responsible to free the returned list with charray_free.
  5525. * flags: one of them or both:
  5526. * SLAPI_OC_FLAG_REQUIRED
  5527. * SLAPI_OC_FLAG_ALLOWED
  5528. */
  5529. char **
  5530. slapi_schema_list_objectclass_attributes(const char *ocname_or_oid,
  5531. PRUint32 flags)
  5532. {
  5533. struct objclass *oc = NULL;
  5534. char **attrs = NULL;
  5535. PRUint32 mask = SLAPI_OC_FLAG_REQUIRED | SLAPI_OC_FLAG_ALLOWED;
  5536. if (!flags) {
  5537. return attrs;
  5538. }
  5539. oc_lock_read();
  5540. oc = oc_find_nolock(ocname_or_oid, NULL, PR_FALSE);
  5541. if (oc) {
  5542. switch (flags & mask) {
  5543. case SLAPI_OC_FLAG_REQUIRED:
  5544. attrs = charray_dup(oc->oc_required);
  5545. break;
  5546. case SLAPI_OC_FLAG_ALLOWED:
  5547. attrs = charray_dup(oc->oc_allowed);
  5548. break;
  5549. case SLAPI_OC_FLAG_REQUIRED|SLAPI_OC_FLAG_ALLOWED:
  5550. attrs = charray_dup(oc->oc_required);
  5551. charray_merge(&attrs, oc->oc_allowed, 1/*copy_strs*/);
  5552. break;
  5553. default:
  5554. slapi_log_error( SLAPI_LOG_FATAL, "list objectclass attributes",
  5555. "flag 0x%x not supported\n", flags );
  5556. break;
  5557. }
  5558. }
  5559. oc_unlock();
  5560. return attrs;
  5561. }
  5562. /*
  5563. * slapi_schema_get_superior_name:
  5564. * Return the name of the superior objectclass
  5565. *
  5566. * The caller is responsible to free the returned name
  5567. */
  5568. char *
  5569. slapi_schema_get_superior_name(const char *ocname_or_oid)
  5570. {
  5571. struct objclass *oc = NULL;
  5572. char *superior = NULL;
  5573. oc_lock_read();
  5574. oc = oc_find_nolock(ocname_or_oid, NULL, PR_FALSE);
  5575. if (oc) {
  5576. superior = slapi_ch_strdup(oc->oc_superior);
  5577. }
  5578. oc_unlock();
  5579. return superior;
  5580. }
  5581. /* Check if the oc_list1 is a superset of oc_list2.
  5582. * oc_list1 is a superset if it exists objectclass in oc_list1 that
  5583. * do not exist in oc_list2. Or if a OC in oc_list1 required more attributes
  5584. * that the OC in oc_list2. Or if a OC in oc_list1 allowed more attributes
  5585. * that the OC in oc_list2.
  5586. *
  5587. * It returns 1 if oc_list1 is a superset of oc_list2, else it returns 0
  5588. *
  5589. * If oc_list1 or oc_list2 is global_oc, the caller must hold the oc_lock
  5590. */
  5591. static int
  5592. schema_oc_superset_check(struct objclass *oc_list1, struct objclass *oc_list2, char *message, int replica_role) {
  5593. struct objclass *oc_1, *oc_2;
  5594. const char *description;
  5595. int debug_logging = 0;
  5596. int rc;
  5597. int repl_schema_policy;
  5598. if (message == NULL) {
  5599. description = (const char *) "";
  5600. } else {
  5601. description = (const char *) message;
  5602. }
  5603. /* by default assum oc_list1 == oc_list2 */
  5604. rc = 0;
  5605. /* Are we doing replication logging */
  5606. if(slapi_is_loglevel_set(SLAPI_LOG_REPL)){
  5607. debug_logging = 1;
  5608. }
  5609. /* Check if all objectclass in oc_list1
  5610. * - exists in oc_list2
  5611. * - required attributes are also required in oc_2
  5612. * - allowed attributes are also allowed in oc_2
  5613. */
  5614. slapi_rwlock_rdlock( schema_policy_lock );
  5615. for (oc_1 = oc_list1; oc_1 != NULL; oc_1 = oc_1->oc_next) {
  5616. /* Check if there is a specific policy for that objectclass */
  5617. repl_schema_policy = schema_check_policy(replica_role, REPL_SCHEMA_OBJECTCLASS, oc_1->oc_name, oc_1->oc_oid);
  5618. if (repl_schema_policy == REPL_SCHEMA_UPDATE_ACCEPT_VALUE) {
  5619. /* We are skipping the superset checking for that objectclass */
  5620. slapi_log_error(SLAPI_LOG_REPL, "schema", "Do not check if this OBJECTCLASS is missing on local/remote schema [%s or %s]\n", oc_1->oc_name, oc_1->oc_oid);
  5621. continue;
  5622. } else if (repl_schema_policy == REPL_SCHEMA_UPDATE_REJECT_VALUE) {
  5623. /* This objectclass being present, we need to fail as if it was a superset
  5624. * keep evaluating to have all the objectclass checking
  5625. */
  5626. slapi_log_error(SLAPI_LOG_REPL, "schema", "%s objectclass prevents replication of the schema\n", oc_1->oc_name);
  5627. rc = 1;
  5628. if(debug_logging){
  5629. /* we continue to check all the objectclasses so we log what is wrong */
  5630. continue;
  5631. } else {
  5632. break;
  5633. }
  5634. }
  5635. /* Retrieve the remote objectclass in our local schema */
  5636. oc_2 = oc_find_nolock(oc_1->oc_oid, oc_list2, PR_TRUE);
  5637. if (oc_2 == NULL) {
  5638. /* try to retrieve it with the name*/
  5639. oc_2 = oc_find_nolock(oc_1->oc_name, oc_list2, PR_TRUE);
  5640. }
  5641. if (oc_2) {
  5642. if (schema_oc_compare(oc_1, oc_2, description) > 0) {
  5643. rc = 1;
  5644. if (debug_logging) {
  5645. if (replica_role == REPL_SCHEMA_AS_CONSUMER) {
  5646. slapi_log_error(SLAPI_LOG_REPL, "schema", "Local %s schema objectclasses is a superset of"
  5647. " the received one.\n", oc_1->oc_name);
  5648. } else {
  5649. slapi_log_error(SLAPI_LOG_REPL, "schema", "Remote %s schema objectclasses is a superset of"
  5650. " the received one.\n", oc_1->oc_name);
  5651. }
  5652. continue;
  5653. } else {
  5654. break;
  5655. }
  5656. }
  5657. } else {
  5658. slapi_log_error(SLAPI_LOG_REPL, "schema", "Fail to retrieve in the %s schema [%s or %s]\n",
  5659. description,
  5660. oc_1->oc_name,
  5661. oc_1->oc_oid);
  5662. /* The oc_1 objectclasses is supperset */
  5663. rc = 1;
  5664. if(debug_logging){
  5665. /* we continue to check all the objectclasses so we log what is wrong */
  5666. continue;
  5667. } else {
  5668. break;
  5669. }
  5670. }
  5671. }
  5672. slapi_rwlock_unlock( schema_policy_lock );
  5673. return rc;
  5674. }
  5675. static char *
  5676. schema_oc_to_string(struct objclass *oc)
  5677. {
  5678. char *oc_str;
  5679. int i;
  5680. int size = 0;
  5681. /* Compute the size of the string that can contain
  5682. * the oc definition and allocates it
  5683. */
  5684. if (oc->oc_oid) size += strlen(oc->oc_oid);
  5685. if (oc->oc_name) size += strlen(oc->oc_name);
  5686. if (oc->oc_desc) size += strlen(oc->oc_desc);
  5687. if (oc->oc_orig_required) {
  5688. for (i =0; oc->oc_orig_required[i] != NULL; i++) {
  5689. size += strlen(oc->oc_orig_required[i]);
  5690. size += 3;
  5691. }
  5692. }
  5693. if (oc->oc_orig_allowed) {
  5694. for (i =0; oc->oc_orig_allowed[i] != NULL; i++) {
  5695. size += strlen(oc->oc_orig_allowed[i]);
  5696. size += 3;
  5697. }
  5698. }
  5699. size += strlen(schema_oc_kind_strings_with_spaces[oc->oc_kind]);
  5700. size += 128; /* for all keywords: NAME, DESC, SUP... */
  5701. if ((oc_str = (char *) slapi_ch_calloc(1, size)) == NULL) {
  5702. return NULL;
  5703. }
  5704. /* OID + name */
  5705. sprintf(oc_str, "( %s NAME '%s'", (oc->oc_oid) ? oc->oc_oid : "", oc->oc_name);
  5706. /* description */
  5707. strcat(oc_str, " DESC '");
  5708. if (oc->oc_desc) {
  5709. strcat(oc_str, oc->oc_desc);
  5710. }
  5711. strcat(oc_str, "'");
  5712. /* SUP */
  5713. if (oc->oc_superior) {
  5714. strcat(oc_str, " SUP '");
  5715. strcat(oc_str, oc->oc_superior);
  5716. strcat(oc_str, "'");
  5717. }
  5718. /* oc_kind */
  5719. strcat(oc_str, schema_oc_kind_strings_with_spaces[oc->oc_kind]);
  5720. /* MUST */
  5721. if (oc->oc_orig_required) {
  5722. strcat(oc_str, " MUST ( ");
  5723. for ( i = 0; oc->oc_orig_required[i] != NULL; ++i ) {
  5724. if (i > 0) {
  5725. strcat(oc_str, " $ ");
  5726. }
  5727. strcat(oc_str, oc->oc_orig_required[i]);
  5728. }
  5729. strcat(oc_str, " ) ");
  5730. }
  5731. /* MAY */
  5732. if (oc->oc_orig_allowed) {
  5733. strcat(oc_str, " MAY ( ");
  5734. for ( i = 0; oc->oc_orig_allowed[i] != NULL; ++i ) {
  5735. if (i > 0) {
  5736. strcat(oc_str, " $ ");
  5737. }
  5738. strcat(oc_str, oc->oc_orig_allowed[i]);
  5739. }
  5740. strcat(oc_str, " ) ");
  5741. }
  5742. /* flags */
  5743. if (oc->oc_flags & OC_FLAG_USER_OC) {
  5744. strcat(oc_str, " X-ORIGIN 'blahblahblah'");
  5745. }
  5746. strcat(oc_str, " )");
  5747. slapi_log_error(SLAPI_LOG_REPL, "schema", "schema_oc_to_string: replace (old[%d]=%s)\n",
  5748. size, oc_str);
  5749. return(oc_str);
  5750. }
  5751. /* call must hold oc_lock at least in read */
  5752. static struct schema_mods_indexes *
  5753. schema_list_oc2learn(struct objclass *oc_remote_list, struct objclass *oc_local_list, int replica_role) {
  5754. struct objclass *oc_remote, *oc_local;
  5755. struct schema_mods_indexes *head = NULL, *mods_index;
  5756. struct schema_mods_indexes *tail = NULL;
  5757. int index = 0;
  5758. int repl_schema_policy;
  5759. const char *message;
  5760. if (replica_role == REPL_SCHEMA_AS_SUPPLIER) {
  5761. message = (const char *) "remote consumer";
  5762. } else {
  5763. message = (const char *) "remote supplier";
  5764. }
  5765. slapi_rwlock_rdlock( schema_policy_lock );
  5766. for (oc_remote = oc_remote_list; oc_remote != NULL; oc_remote = oc_remote->oc_next, index++) {
  5767. /* If this objectclass is not checked (accept) or rejects schema update */
  5768. repl_schema_policy = schema_check_policy(replica_role, REPL_SCHEMA_OBJECTCLASS, oc_remote->oc_name, oc_remote->oc_oid);
  5769. if ((repl_schema_policy == REPL_SCHEMA_UPDATE_ACCEPT_VALUE) || (repl_schema_policy == REPL_SCHEMA_UPDATE_REJECT_VALUE)) {
  5770. continue;
  5771. }
  5772. oc_local = oc_find_nolock(oc_remote->oc_oid, oc_local_list, PR_TRUE);
  5773. if (oc_local == NULL) {
  5774. /* try to retrieve it with the name*/
  5775. oc_local = oc_find_nolock(oc_remote->oc_name, oc_local_list, PR_TRUE);
  5776. }
  5777. if ((oc_local == NULL) ||
  5778. (schema_oc_compare(oc_local, oc_remote, message) < 0)) {
  5779. /* This replica does not know this objectclass, It needs to be added */
  5780. slapi_log_error(SLAPI_LOG_REPL, "schema", "Add that unknown/extended objectclass %s (%s)\n",
  5781. oc_remote->oc_name,
  5782. oc_remote->oc_oid);
  5783. if ((mods_index = (struct schema_mods_indexes *) slapi_ch_calloc(1, sizeof (struct schema_mods_indexes))) == NULL) {
  5784. slapi_log_error(SLAPI_LOG_FATAL, "schema", "Fail to Add (no memory) objectclass %s (%s)\n",
  5785. oc_remote->oc_name,
  5786. oc_remote->oc_oid);
  5787. continue;
  5788. }
  5789. /* insert it at the end of the list
  5790. * to keep the order of the original schema
  5791. * For example superior oc should be declared first
  5792. */
  5793. mods_index->index = index;
  5794. mods_index->next = NULL;
  5795. mods_index->new_value = NULL;
  5796. if (oc_local) {
  5797. mods_index->old_value = schema_oc_to_string(oc_local);
  5798. }
  5799. if (head == NULL) {
  5800. head = mods_index;
  5801. } else {
  5802. tail->next = mods_index;
  5803. }
  5804. tail = mods_index;
  5805. }
  5806. }
  5807. slapi_rwlock_unlock( schema_policy_lock );
  5808. return head;
  5809. }
  5810. static struct schema_mods_indexes *
  5811. schema_list_attr2learn(struct asyntaxinfo *at_list_local, struct asyntaxinfo *at_list_remote, int replica_role)
  5812. {
  5813. struct asyntaxinfo *at_remote, *at_local;
  5814. struct schema_mods_indexes *head = NULL, *mods_index;
  5815. int index = 0;
  5816. int repl_schema_policy;
  5817. int debug_logging = 0;
  5818. char *message;
  5819. if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) {
  5820. debug_logging = 1;
  5821. }
  5822. if (replica_role == REPL_SCHEMA_AS_SUPPLIER) {
  5823. message = "remote consumer";
  5824. } else {
  5825. message = "remote supplier";
  5826. }
  5827. slapi_rwlock_rdlock(schema_policy_lock);
  5828. for (at_remote = at_list_remote; at_remote != NULL; at_remote = at_remote->asi_next, index++) {
  5829. /* If this objectclass is not checked (accept) or rejects schema update */
  5830. repl_schema_policy = schema_check_policy(replica_role, REPL_SCHEMA_ATTRIBUTE, at_remote->asi_name, at_remote->asi_oid);;
  5831. if ((repl_schema_policy == REPL_SCHEMA_UPDATE_ACCEPT_VALUE) || (repl_schema_policy == REPL_SCHEMA_UPDATE_REJECT_VALUE)) {
  5832. continue;
  5833. }
  5834. if (((at_local = attr_syntax_find(at_remote, at_list_local)) == NULL) ||
  5835. (schema_at_compare(at_local, at_remote, message, debug_logging) < 0)) {
  5836. /* This replica does not know this attribute, It needs to be added */
  5837. slapi_log_error(SLAPI_LOG_REPL, "schema", "Add that unknown/extended attribute %s (%s)\n",
  5838. at_remote->asi_name,
  5839. at_remote->asi_oid);
  5840. if ((mods_index = (struct schema_mods_indexes *) slapi_ch_calloc(1, sizeof (struct schema_mods_indexes))) == NULL) {
  5841. slapi_log_error(SLAPI_LOG_FATAL, "schema", "Fail to Add (no memory) attribute %s (%s)\n",
  5842. at_remote->asi_name,
  5843. at_remote->asi_oid);
  5844. continue;
  5845. }
  5846. /* insert it in the list */
  5847. mods_index->index = index;
  5848. mods_index->next = head;
  5849. mods_index->new_value = NULL;
  5850. head = mods_index;
  5851. }
  5852. }
  5853. slapi_rwlock_unlock(schema_policy_lock);
  5854. return head;
  5855. }
  5856. /* If oc_1 > oc2 returns 1
  5857. * else it returns 0
  5858. */
  5859. static PRBool
  5860. schema_oc_compare_strict(struct objclass *oc_1, struct objclass *oc_2, const char *description)
  5861. {
  5862. int found;
  5863. int i,j;
  5864. PRBool moved_must_to_may;
  5865. /* safety checking */
  5866. if (!oc_1) {
  5867. return 0;
  5868. } else if (!oc_2) {
  5869. return 1;
  5870. }
  5871. /* First check the MUST */
  5872. if (oc_1->oc_orig_required) {
  5873. for (i = 0; oc_1->oc_orig_required[i] != NULL; i++) {
  5874. /* For each required attribute from oc1 schema check that
  5875. * it is also required in the oc2 schema
  5876. */
  5877. found = 0;
  5878. if (oc_2->oc_orig_required) {
  5879. for (j = 0; oc_2->oc_orig_required[j] != NULL; j++) {
  5880. if (strcasecmp(oc_2->oc_orig_required[j], oc_1->oc_orig_required[i]) == 0) {
  5881. found = 1;
  5882. break;
  5883. }
  5884. }
  5885. }
  5886. if (!found) {
  5887. /* Before stating that oc1 is a superset of oc2, we need to verify that the 'required'
  5888. * attribute (from oc1) is missing in 'required' oc2 because it is
  5889. * now 'allowed' in oc2
  5890. */
  5891. moved_must_to_may = PR_FALSE;
  5892. if (oc_2->oc_orig_allowed) {
  5893. for (j = 0; oc_2->oc_orig_allowed[j] != NULL; j++) {
  5894. if (strcasecmp(oc_2->oc_orig_allowed[j], oc_1->oc_orig_required[i]) == 0) {
  5895. moved_must_to_may = PR_TRUE;
  5896. break;
  5897. }
  5898. }
  5899. }
  5900. if (moved_must_to_may) {
  5901. /* This is a special case where oc1 is actually NOT a superset of oc2 */
  5902. slapi_log_error(SLAPI_LOG_REPL, "schema", "Attribute %s is no longer 'required' in '%s' of the %s schema but is now 'allowed'\n",
  5903. oc_1->oc_orig_required[i],
  5904. oc_1->oc_name,
  5905. description);
  5906. } else {
  5907. /* The required attribute in the oc1
  5908. * is not required in the oc2
  5909. */
  5910. slapi_log_error(SLAPI_LOG_REPL, "schema", "Attribute %s is not required in '%s' of the %s schema\n",
  5911. oc_1->oc_orig_required[i],
  5912. oc_1->oc_name,
  5913. description);
  5914. /* The oc_1 objectclasses is supperset */
  5915. return 1;
  5916. }
  5917. }
  5918. }
  5919. }
  5920. /* Second check the MAY */
  5921. if (oc_1->oc_orig_allowed) {
  5922. for (i = 0; oc_1->oc_orig_allowed[i] != NULL; i++) {
  5923. /* For each required attribute from the remote schema check that
  5924. * it is also required in the local schema
  5925. */
  5926. found = 0;
  5927. if (oc_2->oc_orig_allowed) {
  5928. for (j = 0; oc_2->oc_orig_allowed[j] != NULL; j++) {
  5929. if (strcasecmp(oc_2->oc_orig_allowed[j], oc_1->oc_orig_allowed[i]) == 0) {
  5930. found = 1;
  5931. break;
  5932. }
  5933. }
  5934. }
  5935. if (!found) {
  5936. /* The allowed attribute in the remote schema (remote_oc->oc_orig_allowed[i])
  5937. * is not allowed in the local schema
  5938. */
  5939. slapi_log_error(SLAPI_LOG_REPL, "schema", "Attribute %s is not allowed in '%s' of the %s schema\n",
  5940. oc_1->oc_orig_allowed[i],
  5941. oc_1->oc_name,
  5942. description);
  5943. /* The oc_1 objectclasses is superset */
  5944. return 1;
  5945. }
  5946. }
  5947. }
  5948. return 0;
  5949. }
  5950. /* Compare two objectclass definitions
  5951. * it compares:
  5952. * It returns:
  5953. * 1: if oc_1 is a superset of oc_2
  5954. * -1: if oc_2 is a superset of oc_1
  5955. * 0: if oc_1 and at_2 are equivalent
  5956. */
  5957. static int
  5958. schema_oc_compare(struct objclass *oc_1, struct objclass *oc_2, const char *description)
  5959. {
  5960. if (schema_oc_compare_strict(oc_1, oc_2, description) > 0) {
  5961. return 1;
  5962. } else if (schema_oc_compare_strict(oc_2, oc_1, description) > 0) {
  5963. return -1;
  5964. } else {
  5965. return 0;
  5966. }
  5967. }
  5968. /* Compare two attributes definitions
  5969. * it compares:
  5970. * - single/multi value
  5971. * - syntax
  5972. * - matching rules
  5973. * It returns:
  5974. * 1: if at_1 is a superset of at_2
  5975. * -1: if at_2 is a superset of at_1
  5976. * 0: if at_1 and at_2 are equivalent
  5977. */
  5978. static int
  5979. schema_at_compare(struct asyntaxinfo *at_1, struct asyntaxinfo *at_2, char *message, int debug_logging)
  5980. {
  5981. char *info = NULL;
  5982. /* safety checking */
  5983. if (! at_1) {
  5984. if (!at_2) {
  5985. return 0;
  5986. } else {
  5987. return -1;
  5988. }
  5989. } else if (!at_2) {
  5990. return 1;
  5991. }
  5992. /*
  5993. * Check for single vs. multi value
  5994. */
  5995. if (!(at_1->asi_flags & SLAPI_ATTR_FLAG_SINGLE) && (at_2->asi_flags & SLAPI_ATTR_FLAG_SINGLE)) {
  5996. /* at_1 is a superset */
  5997. if (debug_logging) {
  5998. slapi_log_error(SLAPI_LOG_REPL, "schema", "%s schema attribute [%s] is not "
  5999. "\"single-valued\" \n", message, at_1->asi_name);
  6000. }
  6001. return 1;
  6002. }
  6003. if ((at_1->asi_flags & SLAPI_ATTR_FLAG_SINGLE) && !(at_2->asi_flags & SLAPI_ATTR_FLAG_SINGLE)) {
  6004. /* at_2 is a superset */
  6005. if (debug_logging) {
  6006. slapi_log_error(SLAPI_LOG_REPL, "schema", "%s schema attribute [%s] is not "
  6007. "\"single-valued\" \n", message, at_1->asi_name);
  6008. }
  6009. return -1;
  6010. }
  6011. /*
  6012. * Check the syntaxes
  6013. */
  6014. if (schema_at_superset_check_syntax_oids(at_1->asi_syntax_oid, at_2->asi_syntax_oid)) {
  6015. /* at_1 is a superset */
  6016. if (debug_logging) {
  6017. slapi_log_error(SLAPI_LOG_REPL, "schema", "%s schema attribute [%s] syntax "
  6018. "can not be overwritten\n", message, at_1->asi_name);
  6019. }
  6020. return 1;
  6021. }
  6022. if (schema_at_superset_check_syntax_oids(at_2->asi_syntax_oid, at_1->asi_syntax_oid)) {
  6023. /* at_2 is a superset */
  6024. if (debug_logging) {
  6025. slapi_log_error(SLAPI_LOG_REPL, "schema", "%s schema attribute [%s] syntax "
  6026. "can not be overwritten\n", message, at_2->asi_name);
  6027. }
  6028. return -1;
  6029. }
  6030. /*
  6031. * Check some matching rules - not finished yet...
  6032. *
  6033. * For now, skip the matching rule check (rc is never equal to -1)
  6034. */
  6035. if (schema_at_superset_check_mr(at_1, at_2, info)) {
  6036. if (debug_logging) {
  6037. slapi_log_error(SLAPI_LOG_REPL, "schema", "%s schema attribute [%s] matching "
  6038. "rule can not be overwritten\n", message, at_1->asi_name);
  6039. }
  6040. return 1;
  6041. }
  6042. if (schema_at_superset_check_mr(at_2, at_1, info)) {
  6043. if (debug_logging) {
  6044. slapi_log_error(SLAPI_LOG_REPL, "schema", "%s schema attribute [%s] matching "
  6045. "rule can not be overwritten\n", message, at_2->asi_name);
  6046. }
  6047. return -1;
  6048. }
  6049. return 0;
  6050. }
  6051. static int
  6052. schema_at_superset_check(struct asyntaxinfo *at_list1, struct asyntaxinfo *at_list2, char *message, int replica_role)
  6053. {
  6054. struct asyntaxinfo *at_1, *at_2;
  6055. int debug_logging = 0;
  6056. int repl_schema_policy;
  6057. int rc = 0;
  6058. if(at_list1 == NULL || at_list2 == NULL){
  6059. return 0;
  6060. }
  6061. /* Are we doing replication logging */
  6062. if(slapi_is_loglevel_set(SLAPI_LOG_REPL)){
  6063. debug_logging = 1;
  6064. }
  6065. slapi_rwlock_rdlock( schema_policy_lock );
  6066. for (at_1 = at_list1; at_1 != NULL; at_1 = at_1->asi_next) {
  6067. /* Check if there is a specific policy for that objectclass */
  6068. repl_schema_policy = schema_check_policy(replica_role, REPL_SCHEMA_ATTRIBUTE, at_1->asi_name, at_1->asi_oid);
  6069. if (repl_schema_policy == REPL_SCHEMA_UPDATE_ACCEPT_VALUE) {
  6070. /* We are skipping the superset checking for that attribute */
  6071. slapi_log_error(SLAPI_LOG_REPL, "schema", "Do not check if this ATTRIBUTE is missing on local/remote schema [%s or %s]\n", at_1->asi_name, at_1->asi_oid);
  6072. continue;
  6073. } else if (repl_schema_policy == REPL_SCHEMA_UPDATE_REJECT_VALUE) {
  6074. /* This attribute being present, we need to fail as if it was a superset
  6075. * but keep evaluating to have all the attribute checking
  6076. */
  6077. slapi_log_error(SLAPI_LOG_REPL, "schema", "%s attribute prevents replication of the schema\n", at_1->asi_name);
  6078. rc = 1;
  6079. if (debug_logging) {
  6080. /* we continue to check all the objectclasses so we log what is wrong */
  6081. continue;
  6082. } else {
  6083. break;
  6084. }
  6085. }
  6086. /* check if at_1 exists in at_list2 */
  6087. if((at_2 = attr_syntax_find(at_1, at_list2))) {
  6088. if (schema_at_compare(at_1, at_2, message, debug_logging) > 0) {
  6089. rc = 1;
  6090. if (debug_logging) {
  6091. if (replica_role == REPL_SCHEMA_AS_CONSUMER) {
  6092. slapi_log_error(SLAPI_LOG_REPL, "schema", "Local %s schema attributetypes is a superset of"
  6093. " the received one.\n", at_1->asi_name);
  6094. } else {
  6095. slapi_log_error(SLAPI_LOG_REPL, "schema", "Remote %s schema attributetypes is a superset of"
  6096. " the received one.\n", at_1->asi_name);
  6097. }
  6098. continue;
  6099. } else {
  6100. break;
  6101. }
  6102. }
  6103. } else {
  6104. rc = 1;
  6105. if(debug_logging){
  6106. /* we continue to check all attributes so we log what is wrong */
  6107. slapi_log_error(SLAPI_LOG_REPL, "schema", "Fail to retrieve in the %s schema [%s or %s]\n",
  6108. message, at_1->asi_name, at_1->asi_oid);
  6109. continue;
  6110. } else {
  6111. break;
  6112. }
  6113. }
  6114. }
  6115. slapi_rwlock_unlock( schema_policy_lock );
  6116. return rc;
  6117. }
  6118. /*
  6119. * Return 1 if a1's matching rules are superset(not to be overwritten). If just one of
  6120. * the matching rules should not be overwritten, even if one should, we can not allow it.
  6121. */
  6122. static int
  6123. schema_at_superset_check_mr(struct asyntaxinfo *a1, struct asyntaxinfo *a2, char *info)
  6124. {
  6125. char *a1_mrtype[3] = { a1->asi_mr_equality, a1->asi_mr_substring, a1->asi_mr_ordering };
  6126. char *a2_mrtype[3] = { a2->asi_mr_equality, a2->asi_mr_substring, a2->asi_mr_ordering };
  6127. int rc = 0, i;
  6128. /*
  6129. * Loop over the three matching rule types
  6130. */
  6131. for(i = 0; i < 3; i++){
  6132. if(a1_mrtype[i]){
  6133. if(a2_mrtype[i]){
  6134. /*
  6135. * Future action item - determine matching rule precedence:
  6136. *
  6137. ces
  6138. "caseExactIA5Match", "1.3.6.1.4.1.1466.109.114.1"
  6139. "caseExactMatch", "2.5.13.5"
  6140. "caseExactOrderingMatch", "2.5.13.6"
  6141. "caseExactSubstringsMatch", "2.5.13.7"
  6142. "caseExactIA5SubstringsMatch", "2.16.840.1.113730.3.3.1"
  6143. cis
  6144. "generalizedTimeMatch", "2.5.13.27"
  6145. "generalizedTimeOrderingMatch", "2.5.13.28"
  6146. "booleanMatch", "2.5.13.13"
  6147. "caseIgnoreIA5Match", "1.3.6.1.4.1.1466.109.114.2"
  6148. "caseIgnoreIA5SubstringsMatch", "1.3.6.1.4.1.1466.109.114.3"
  6149. "caseIgnoreListMatch", "2.5.13.11"
  6150. "caseIgnoreListSubstringsMatch", "2.5.13.12"
  6151. "caseIgnoreMatch", "2.5.13.2" -------------------------------
  6152. "caseIgnoreOrderingMatch", "2.5.13.3" -----------------------> can have lang options
  6153. "caseIgnoreSubstringsMatch", "2.5.13.4" --------------------- (as seen in the console)!
  6154. "directoryStringFirstComponentMatch", "2.5.13.31"
  6155. "objectIdentifierMatch", "2.5.13.0"
  6156. "objectIdentifierFirstComponentMatch", "2.5.13.30"
  6157. bitstring
  6158. "bitStringMatch", "2.5.13.16","2.16.840.1.113730.3.3.1"
  6159. bin
  6160. "octetStringMatch", "2.5.13.17"
  6161. "octetStringOrderingMatch", "2.5.13.18"
  6162. DN
  6163. "distinguishedNameMatch", "2.5.13.1"
  6164. Int
  6165. "integerMatch", "2.5.13.14"
  6166. "integerOrderingMatch", "2.5.13.15"
  6167. "integerFirstComponentMatch", "2.5.13.29"
  6168. NameAndOptUID
  6169. "uniqueMemberMatch", "2.5.13.23"
  6170. NumericString
  6171. "numericStringMatch", "2.5.13.8"
  6172. "numericStringOrderingMatch", "2.5.13.9"
  6173. "numericStringSubstringsMatch", "2.5.13.10"
  6174. Telephone
  6175. "telephoneNumberMatch", "2.5.13.20"
  6176. "telephoneNumberSubstringsMatch", "2.5.13.21"
  6177. */
  6178. }
  6179. }
  6180. }
  6181. return rc;
  6182. }
  6183. /*
  6184. * Return 1 if oid1 is a superset(oid1 is not to be overwritten)
  6185. */
  6186. static int
  6187. schema_at_superset_check_syntax_oids(char *oid1, char *oid2)
  6188. {
  6189. if(oid1 == NULL && oid2 == NULL){
  6190. return 0;
  6191. } else if (oid2 == NULL){
  6192. return 0;
  6193. } else if (oid1 == NULL){
  6194. return 1;
  6195. }
  6196. if(strcmp(oid1, BINARY_SYNTAX_OID) == 0){
  6197. if(strcmp(oid2, BINARY_SYNTAX_OID) &&
  6198. strcmp(oid2, INTEGER_SYNTAX_OID) &&
  6199. strcmp(oid2, NUMERICSTRING_SYNTAX_OID) &&
  6200. strcmp(oid2, IA5STRING_SYNTAX_OID) &&
  6201. strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
  6202. strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
  6203. strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
  6204. strcmp(oid2, FACSIMILE_SYNTAX_OID) &&
  6205. strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
  6206. strcmp(oid2, TELEPHONE_SYNTAX_OID) &&
  6207. strcmp(oid2, TELETEXTERMID_SYNTAX_OID) &&
  6208. strcmp(oid2, TELEXNUMBER_SYNTAX_OID))
  6209. {
  6210. return 1;
  6211. }
  6212. } else if(strcmp(oid1, BITSTRING_SYNTAX_OID) == 0){
  6213. if(strcmp(oid2, BINARY_SYNTAX_OID) &&
  6214. strcmp(oid2, BITSTRING_SYNTAX_OID) &&
  6215. strcmp(oid2, INTEGER_SYNTAX_OID) &&
  6216. strcmp(oid2, NUMERICSTRING_SYNTAX_OID) &&
  6217. strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
  6218. strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
  6219. strcmp(oid2, IA5STRING_SYNTAX_OID) &&
  6220. strcmp(oid2, FACSIMILE_SYNTAX_OID) &&
  6221. strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
  6222. strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
  6223. strcmp(oid2, TELEPHONE_SYNTAX_OID) &&
  6224. strcmp(oid2, TELETEXTERMID_SYNTAX_OID) &&
  6225. strcmp(oid2, TELEXNUMBER_SYNTAX_OID))
  6226. {
  6227. return 1;
  6228. }
  6229. } else if(strcmp(oid1, BOOLEAN_SYNTAX_OID) == 0){
  6230. if(strcmp(oid2, BOOLEAN_SYNTAX_OID) &&
  6231. strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
  6232. strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
  6233. strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
  6234. strcmp(oid2, IA5STRING_SYNTAX_OID))
  6235. {
  6236. return 1;
  6237. }
  6238. } else if(strcmp(oid1, COUNTRYSTRING_SYNTAX_OID) ==0){
  6239. if(strcmp(oid2, COUNTRYSTRING_SYNTAX_OID) &&
  6240. strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
  6241. strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
  6242. strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
  6243. strcmp(oid2, IA5STRING_SYNTAX_OID))
  6244. {
  6245. return 1;
  6246. }
  6247. } else if(strcmp(oid1, DN_SYNTAX_OID) == 0){
  6248. if(strcmp(oid2, DN_SYNTAX_OID) &&
  6249. strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
  6250. strcmp(oid2, DIRSTRING_SYNTAX_OID) )
  6251. {
  6252. return 1;
  6253. }
  6254. } else if(strcmp(oid1, DELIVERYMETHOD_SYNTAX_OID) ==0){
  6255. if(strcmp(oid2, DELIVERYMETHOD_SYNTAX_OID) &&
  6256. strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
  6257. strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
  6258. strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
  6259. strcmp(oid2, IA5STRING_SYNTAX_OID))
  6260. {
  6261. return 1;
  6262. }
  6263. } else if(strcmp(oid1, DIRSTRING_SYNTAX_OID) == 0){
  6264. if(strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
  6265. strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID)){
  6266. return 1;
  6267. }
  6268. } else if(strcmp(oid1, ENHANCEDGUIDE_SYNTAX_OID) == 0){
  6269. if(strcmp(oid2, ENHANCEDGUIDE_SYNTAX_OID) &&
  6270. strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
  6271. strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
  6272. strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
  6273. strcmp(oid2, IA5STRING_SYNTAX_OID))
  6274. {
  6275. return 1;
  6276. }
  6277. } else if(strcmp(oid1, IA5STRING_SYNTAX_OID) == 0){
  6278. if(strcmp(oid2, IA5STRING_SYNTAX_OID) &&
  6279. strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
  6280. strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
  6281. strcmp(oid2, PRINTABLESTRING_SYNTAX_OID))
  6282. {
  6283. return 1;
  6284. }
  6285. } else if(strcmp(oid1, INTEGER_SYNTAX_OID) == 0){
  6286. if(strcmp(oid2, INTEGER_SYNTAX_OID) &&
  6287. strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
  6288. strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
  6289. strcmp(oid2, NUMERICSTRING_SYNTAX_OID) &&
  6290. strcmp(oid2, TELEPHONE_SYNTAX_OID) &&
  6291. strcmp(oid2, TELETEXTERMID_SYNTAX_OID) &&
  6292. strcmp(oid2, TELEXNUMBER_SYNTAX_OID) &&
  6293. strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
  6294. strcmp(oid2, IA5STRING_SYNTAX_OID) )
  6295. {
  6296. return 1;
  6297. }
  6298. } else if(strcmp(oid1, JPEG_SYNTAX_OID) == 0){
  6299. if(strcmp(oid2, JPEG_SYNTAX_OID) &&
  6300. strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
  6301. strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
  6302. strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
  6303. strcmp(oid2, IA5STRING_SYNTAX_OID))
  6304. {
  6305. return 1;
  6306. }
  6307. } else if(strcmp(oid1, NAMEANDOPTIONALUID_SYNTAX_OID) == 0){
  6308. if(strcmp(oid2, NAMEANDOPTIONALUID_SYNTAX_OID) &&
  6309. strcmp(oid2, NAMEANDOPTIONALUID_SYNTAX_OID) &&
  6310. strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
  6311. strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
  6312. strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
  6313. strcmp(oid2, IA5STRING_SYNTAX_OID))
  6314. {
  6315. return 1;
  6316. }
  6317. } else if(strcmp(oid1, NUMERICSTRING_SYNTAX_OID) == 0){
  6318. if(strcmp(oid2, NUMERICSTRING_SYNTAX_OID) &&
  6319. strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
  6320. strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
  6321. strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
  6322. strcmp(oid2, IA5STRING_SYNTAX_OID))
  6323. {
  6324. return 1;
  6325. }
  6326. } else if(strcmp(oid1, OID_SYNTAX_OID) == 0){
  6327. if(strcmp(oid2, OID_SYNTAX_OID) &&
  6328. strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
  6329. strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
  6330. strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
  6331. strcmp(oid2, IA5STRING_SYNTAX_OID))
  6332. {
  6333. return 1;
  6334. }
  6335. } else if (strcmp(oid1, OCTETSTRING_SYNTAX_OID) == 0){
  6336. if(strcmp(oid2, OCTETSTRING_SYNTAX_OID) &&
  6337. strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
  6338. strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
  6339. strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
  6340. strcmp(oid2, IA5STRING_SYNTAX_OID))
  6341. {
  6342. return 1;
  6343. }
  6344. } else if(strcmp(oid1, POSTALADDRESS_SYNTAX_OID) ==0){
  6345. if(strcmp(oid2, POSTALADDRESS_SYNTAX_OID) &&
  6346. strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
  6347. strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
  6348. strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
  6349. strcmp(oid2, IA5STRING_SYNTAX_OID))
  6350. {
  6351. return 1;
  6352. }
  6353. } else if(strcmp(oid1, PRINTABLESTRING_SYNTAX_OID) == 0){
  6354. if(strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
  6355. strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
  6356. strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
  6357. strcmp(oid2, IA5STRING_SYNTAX_OID))
  6358. {
  6359. return 1;
  6360. }
  6361. } else if(strcmp(oid1, TELEPHONE_SYNTAX_OID) == 0){
  6362. if(strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
  6363. strcmp(oid2, TELEPHONE_SYNTAX_OID) &&
  6364. strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
  6365. strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
  6366. strcmp(oid2, IA5STRING_SYNTAX_OID))
  6367. {
  6368. return 1;
  6369. }
  6370. } else if(strcmp(oid1, TELETEXTERMID_SYNTAX_OID) == 0){
  6371. if(strcmp(oid2, TELETEXTERMID_SYNTAX_OID) &&
  6372. strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
  6373. strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
  6374. strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
  6375. strcmp(oid2, IA5STRING_SYNTAX_OID))
  6376. {
  6377. return 1;
  6378. }
  6379. } else if(strcmp(oid1, TELEXNUMBER_SYNTAX_OID) == 0){
  6380. if(strcmp(oid2, TELEXNUMBER_SYNTAX_OID) &&
  6381. strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
  6382. strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
  6383. strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
  6384. strcmp(oid2, IA5STRING_SYNTAX_OID))
  6385. {
  6386. return 1;
  6387. }
  6388. } else if (strcmp(oid1, SPACE_INSENSITIVE_STRING_SYNTAX_OID) == 0){
  6389. if(strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
  6390. strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
  6391. strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
  6392. strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
  6393. strcmp(oid2, IA5STRING_SYNTAX_OID))
  6394. {
  6395. return 1;
  6396. }
  6397. }
  6398. return 0;
  6399. }
  6400. static void
  6401. schema_oclist_free(struct objclass *oc_list)
  6402. {
  6403. struct objclass *oc, *oc_next;
  6404. for (oc = oc_list; oc != NULL; oc = oc_next) {
  6405. oc_next = oc->oc_next;
  6406. oc_free(&oc);
  6407. }
  6408. }
  6409. static void
  6410. schema_atlist_free(struct asyntaxinfo *at_list)
  6411. {
  6412. struct asyntaxinfo *at, *at_next;
  6413. for (at = at_list; at != NULL; at = at_next) {
  6414. at_next = at->asi_next;
  6415. attr_syntax_free(at);
  6416. }
  6417. }
  6418. static struct objclass *
  6419. schema_berval_to_oclist(struct berval **oc_berval)
  6420. {
  6421. struct objclass *oc, *oc_list, *oc_tail;
  6422. char errorbuf[BUFSIZ];
  6423. int schema_ds4x_compat, rc;
  6424. int i;
  6425. schema_ds4x_compat = config_get_ds4_compatible_schema();
  6426. rc = 0;
  6427. oc_list = NULL;
  6428. oc_tail = NULL;
  6429. if (oc_berval != NULL) {
  6430. for (i = 0; oc_berval[i] != NULL; i++) {
  6431. /* parse the objectclass value */
  6432. if (LDAP_SUCCESS != (rc = parse_oc_str(oc_berval[i]->bv_val, &oc,
  6433. errorbuf, sizeof (errorbuf), DSE_SCHEMA_NO_CHECK | DSE_SCHEMA_USE_PRIV_SCHEMA, 0,
  6434. schema_ds4x_compat, oc_list))) {
  6435. oc_free(&oc);
  6436. rc = 1;
  6437. break;
  6438. }
  6439. /* Add oc at the end of the oc_list */
  6440. oc->oc_next = NULL;
  6441. if (oc_list == NULL) {
  6442. oc_list = oc;
  6443. oc_tail = oc;
  6444. } else {
  6445. oc_tail->oc_next = oc;
  6446. oc_tail = oc;
  6447. }
  6448. }
  6449. }
  6450. if (rc) {
  6451. schema_oclist_free(oc_list);
  6452. oc_list = NULL;
  6453. }
  6454. return oc_list;
  6455. }
  6456. static struct asyntaxinfo *
  6457. schema_berval_to_atlist(struct berval **at_berval)
  6458. {
  6459. struct asyntaxinfo *at, *head = NULL, *at_list = NULL;
  6460. char errorbuf[BUFSIZ];
  6461. int schema_ds4x_compat, rc = 0, i;
  6462. schema_ds4x_compat = config_get_ds4_compatible_schema();
  6463. if (at_berval != NULL) {
  6464. for (i = 0; at_berval[i] != NULL; i++) {
  6465. /* parse the objectclass value */
  6466. rc = parse_at_str(at_berval[i]->bv_val, &at, errorbuf, sizeof (errorbuf),
  6467. DSE_SCHEMA_NO_CHECK | DSE_SCHEMA_USE_PRIV_SCHEMA, 0, schema_ds4x_compat, 0);
  6468. if(rc){
  6469. attr_syntax_free(at);
  6470. break;
  6471. }
  6472. if(!head){
  6473. head = at_list = at;
  6474. } else {
  6475. at_list->asi_next = at;
  6476. at->asi_prev = at_list;
  6477. at_list = at;
  6478. }
  6479. }
  6480. }
  6481. if (rc) {
  6482. schema_atlist_free(head);
  6483. }
  6484. return head;
  6485. }
  6486. int
  6487. schema_objectclasses_superset_check(struct berval **remote_schema, char *type)
  6488. {
  6489. int rc;
  6490. struct objclass *remote_oc_list;
  6491. rc = 0;
  6492. /* head is the future list of the objectclass of the remote schema */
  6493. remote_oc_list = NULL;
  6494. if (remote_schema != NULL) {
  6495. /* First build an objectclass list from the remote schema */
  6496. if ((remote_oc_list = schema_berval_to_oclist(remote_schema)) == NULL) {
  6497. rc = 1;
  6498. return rc;
  6499. }
  6500. /* Check that for each object from the remote schema
  6501. * - MUST attributes are also MUST in local schema
  6502. * - ALLOWED attributes are also ALLOWED in local schema
  6503. */
  6504. if (remote_oc_list) {
  6505. oc_lock_read();
  6506. if (strcmp(type, OC_SUPPLIER) == 0) {
  6507. /* Check if the remote_oc_list from a consumer are or not
  6508. * a superset of the objectclasses of the local supplier schema
  6509. */
  6510. rc = schema_oc_superset_check(remote_oc_list, g_get_global_oc_nolock(), "remote consumer", REPL_SCHEMA_AS_SUPPLIER);
  6511. } else {
  6512. /* Check if the objectclasses of the local consumer schema are or not
  6513. * a superset of the remote_oc_list from a supplier
  6514. */
  6515. rc = schema_oc_superset_check(g_get_global_oc_nolock(), remote_oc_list, "remote supplier", REPL_SCHEMA_AS_CONSUMER);
  6516. }
  6517. oc_unlock();
  6518. }
  6519. /* Free the remote schema list*/
  6520. schema_oclist_free(remote_oc_list);
  6521. }
  6522. return rc;
  6523. }
  6524. int
  6525. schema_attributetypes_superset_check(struct berval **remote_schema, char *type)
  6526. {
  6527. struct asyntaxinfo *remote_at_list = NULL;
  6528. int rc = 0;
  6529. if (remote_schema != NULL) {
  6530. /* First build an attribute list from the remote schema */
  6531. if ((remote_at_list = schema_berval_to_atlist(remote_schema)) == NULL) {
  6532. rc = 1;
  6533. return rc;
  6534. }
  6535. /*
  6536. * Check that for each object from the remote schema
  6537. * - MUST attributes are also MUST in local schema
  6538. * - ALLOWED attributes are also ALLOWED in local schema
  6539. */
  6540. if (remote_at_list) {
  6541. attr_syntax_read_lock();
  6542. if (strcmp(type, OC_SUPPLIER) == 0) {
  6543. /*
  6544. * Check if the remote_at_list from a consumer are or not
  6545. * a superset of the attributetypes of the local supplier schema
  6546. */
  6547. rc = schema_at_superset_check(remote_at_list, attr_syntax_get_global_at(), "local supplier", REPL_SCHEMA_AS_SUPPLIER);
  6548. } else {
  6549. /*
  6550. * Check if the attributeypes of the local consumer schema are or not
  6551. * a superset of the remote_at_list from a supplier
  6552. */
  6553. rc = schema_at_superset_check(attr_syntax_get_global_at(), remote_at_list, "remote supplier", REPL_SCHEMA_AS_CONSUMER);
  6554. }
  6555. attr_syntax_unlock_read();
  6556. }
  6557. /* Free the remote schema list */
  6558. schema_atlist_free(remote_at_list);
  6559. }
  6560. return rc;
  6561. }
  6562. /* Do the internal MOD and update the local "nsSchemaCSN" with a local timestamp
  6563. * It could be a good idea to set the 'nsSchemaCSN' with the maximum of local time and
  6564. * the CSN received with the remote schema
  6565. */
  6566. static void
  6567. modify_schema_internal_mod(Slapi_DN *sdn, Slapi_Mods *smods)
  6568. {
  6569. Slapi_PBlock *newpb;
  6570. int op_result;
  6571. CSN *schema_csn;
  6572. /* allocate internal mod components: pblock*/
  6573. newpb = slapi_pblock_new();
  6574. slapi_modify_internal_set_pb_ext (
  6575. newpb,
  6576. sdn,
  6577. slapi_mods_get_ldapmods_byref (smods),
  6578. NULL, /* Controls */
  6579. NULL,
  6580. (void *)plugin_get_default_component_id(),
  6581. 0);
  6582. /* do modify */
  6583. slapi_modify_internal_pb (newpb);
  6584. slapi_pblock_get (newpb, SLAPI_PLUGIN_INTOP_RESULT, &op_result);
  6585. if (op_result == LDAP_SUCCESS) {
  6586. char *type;
  6587. if (smods && smods->mods) {
  6588. type = smods->mods[0]->mod_type;
  6589. } else {
  6590. type = "unknown";
  6591. }
  6592. slapi_log_error(SLAPI_LOG_REPL, "schema", "modify_schema_internal_mod: successfully learn %s definitions\n", type);
  6593. /* Update the schema csn if the operation succeeded */
  6594. schema_csn = csn_new();
  6595. if (NULL != schema_csn) {
  6596. csn_set_replicaid(schema_csn, 0);
  6597. csn_set_time(schema_csn, current_time());
  6598. g_set_global_schema_csn(schema_csn);
  6599. }
  6600. } else {
  6601. slapi_log_error(SLAPI_LOG_FATAL, "schema", "modify_schema_internal_mod: fail to learn schema definitions (%d) \n", op_result);
  6602. }
  6603. slapi_pblock_destroy(newpb);
  6604. }
  6605. /* Prepare slapi_mods for the internal mod
  6606. * Caller must free smods with slapi_mods_done
  6607. */
  6608. static void
  6609. modify_schema_prepare_mods(Slapi_Mods *smods, char *type, struct schema_mods_indexes *values)
  6610. {
  6611. struct schema_mods_indexes *object;
  6612. struct berval *bv;
  6613. struct berval **bvps_del = NULL;
  6614. struct berval **bvps_add = NULL;
  6615. int nb_values_del, nb_values_add, i;
  6616. int nb_mods;
  6617. /* Checks the values to delete */
  6618. for (object = values, nb_values_del = 0; object != NULL; object = object->next) {
  6619. if (object->old_value) {
  6620. nb_values_del++;
  6621. }
  6622. }
  6623. if (nb_values_del) {
  6624. bvps_del = (struct berval **) slapi_ch_calloc(1, (nb_values_del + 1) * sizeof (struct berval *));
  6625. for (i = 0, object = values; object != NULL; object = object->next) {
  6626. if (object->old_value) {
  6627. bv = (struct berval *) slapi_ch_malloc(sizeof (struct berval));
  6628. bv->bv_len = strlen(object->old_value);
  6629. bv->bv_val = (void*) object->old_value;
  6630. bvps_del[i] = bv;
  6631. i++;
  6632. slapi_log_error(SLAPI_LOG_REPL, "schema", "MOD[%d] del (%s): %s\n", i, type, object->old_value);
  6633. }
  6634. }
  6635. bvps_del[nb_values_del] = NULL;
  6636. }
  6637. /* Checks the values to add */
  6638. for (object = values, nb_values_add = 0; object != NULL; object = object->next, nb_values_add++);
  6639. if (nb_values_add) {
  6640. bvps_add = (struct berval **) slapi_ch_calloc(1, (nb_values_add + 1) * sizeof (struct berval *));
  6641. for (i = 0, object = values; object != NULL; i++, object = object->next) {
  6642. bv = (struct berval *) slapi_ch_malloc(sizeof (struct berval));
  6643. bv->bv_len = strlen(object->new_value);
  6644. bv->bv_val = (void*) object->new_value;
  6645. bvps_add[i] = bv;
  6646. slapi_log_error(SLAPI_LOG_REPL, "schema", "MOD[%d] add (%s): %s\n", i, type, object->new_value);
  6647. }
  6648. bvps_add[nb_values_add] = NULL;
  6649. }
  6650. /* Prepare the mods */
  6651. nb_mods = 1;
  6652. if (bvps_del) nb_mods++;
  6653. if (bvps_add) nb_mods++;
  6654. slapi_mods_init(smods, nb_mods);
  6655. if (bvps_del) slapi_mods_add_modbvps(smods, LDAP_MOD_DELETE, type, bvps_del);
  6656. if (bvps_add) slapi_mods_add_modbvps(smods, LDAP_MOD_ADD, type, bvps_add);
  6657. /* clean up */
  6658. if (bvps_del) {
  6659. for (i = 0; bvps_del[i] != NULL; i++) {
  6660. /* bv_val should not be free. It belongs to the incoming MOD */
  6661. slapi_ch_free((void **) &bvps_del[i]);
  6662. }
  6663. slapi_ch_free((void **) &bvps_del);
  6664. }
  6665. if (bvps_add) {
  6666. for (i = 0; bvps_add[i] != NULL; i++) {
  6667. /* bv_val should not be free. It belongs to the incoming MOD */
  6668. slapi_ch_free((void **) &bvps_add[i]);
  6669. }
  6670. slapi_ch_free((void **) &bvps_add);
  6671. }
  6672. }
  6673. /* called by modify_schema_dse/supplier_learn_new_definitions to learn new
  6674. * definitions via internal mod.
  6675. * Internal mod is important, because we want those definitions to be updated in 99user.ldif
  6676. * and we are not sure that the current operation will succeeds or not.
  6677. */
  6678. static void
  6679. modify_schema_apply_new_definitions(char *attr_name, struct schema_mods_indexes *list)
  6680. {
  6681. Slapi_Mods smods = {0};
  6682. Slapi_DN *sdn = NULL;
  6683. if (list == NULL)
  6684. return;
  6685. /* Then the sdn */
  6686. sdn = slapi_sdn_new();
  6687. if (!sdn) {
  6688. slapi_log_error( SLAPI_LOG_FATAL, "schema", "modify_schema_apply_new_definitions Out of memory \n");
  6689. goto done;
  6690. }
  6691. slapi_sdn_set_dn_byval(sdn, SLAPD_SCHEMA_DN);
  6692. /* prepare the mods */
  6693. modify_schema_prepare_mods(&smods, attr_name, list);
  6694. /* update the schema with the new attributetypes */
  6695. /* No need to lock the schema_dse as the internal mod will do */
  6696. modify_schema_internal_mod(sdn, &smods);
  6697. done:
  6698. if (sdn) {
  6699. slapi_sdn_free(&sdn);
  6700. }
  6701. slapi_mods_done (&smods);
  6702. }
  6703. /*
  6704. * This routines retrieves from the remote schema (mods) the
  6705. * definitions (attributetypes/objectclasses), that are:
  6706. * - unknown from the local schema
  6707. * - a superset of the local definition
  6708. *
  6709. * It then builds two lists (to be freed by the caller) with those definitions.
  6710. * Those list contains a duplicate of the definition (string).
  6711. */
  6712. static void
  6713. modify_schema_get_new_definitions(Slapi_PBlock *pb, LDAPMod **mods, struct schema_mods_indexes **at_list, struct schema_mods_indexes **oc_list)
  6714. {
  6715. struct asyntaxinfo *remote_at_list;
  6716. struct objclass *remote_oc_list;
  6717. int is_replicated_operation = 0;
  6718. int replace_allowed = 0;
  6719. slapdFrontendConfig_t *slapdFrontendConfig;
  6720. int i;
  6721. struct schema_mods_indexes *at2learn_list = NULL;
  6722. struct schema_mods_indexes *at2learn;
  6723. struct schema_mods_indexes *oc2learn_list = NULL;
  6724. struct schema_mods_indexes *oc2learn;
  6725. slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &is_replicated_operation);
  6726. /* by default nothing to learn */
  6727. *at_list = NULL;
  6728. *oc_list = NULL;
  6729. /* We are only looking for schema received from a supplier */
  6730. if (!is_replicated_operation || !mods) {
  6731. return ;
  6732. }
  6733. /* Check if we are allowed to update the schema (if needed) */
  6734. slapdFrontendConfig = getFrontendConfig();
  6735. CFG_LOCK_READ(slapdFrontendConfig);
  6736. if ((0 == strcasecmp(slapdFrontendConfig->schemareplace, CONFIG_SCHEMAREPLACE_STR_ON)) ||
  6737. (0 == strcasecmp(slapdFrontendConfig->schemareplace, CONFIG_SCHEMAREPLACE_STR_REPLICATION_ONLY))) {
  6738. replace_allowed = 1;
  6739. }
  6740. CFG_UNLOCK_READ(slapdFrontendConfig);
  6741. if (!replace_allowed) {
  6742. return;
  6743. }
  6744. /* First retrieve unknowns attributetypes because an unknown objectclasses
  6745. * may be composed of unknown attributetypes
  6746. */
  6747. at2learn_list = NULL;
  6748. oc2learn_list = NULL;
  6749. schema_dse_lock_read();
  6750. for (i = 0; mods[i]; i++) {
  6751. if (SLAPI_IS_MOD_REPLACE(mods[i]->mod_op) && (mods[i]->mod_bvalues)) {
  6752. if (strcasecmp(mods[i]->mod_type, "attributetypes") == 0) {
  6753. /* we have some MOD_replace of attributetypes*/
  6754. /* First build an attribute list from the remote schema */
  6755. if ((remote_at_list = schema_berval_to_atlist(mods[i]->mod_bvalues)) == NULL) {
  6756. /* If we can not build an attributes list from the mods, just skip
  6757. * it and look for objectclasses
  6758. */
  6759. slapi_log_error(SLAPI_LOG_FATAL, "schema",
  6760. "Not able to build an attributes list (%s) from the schema received from the supplier\n",
  6761. mods[i]->mod_type);
  6762. continue;
  6763. }
  6764. /* Build a list of attributestype to learn from the remote definitions */
  6765. attr_syntax_read_lock();
  6766. at2learn_list = schema_list_attr2learn(attr_syntax_get_global_at(), remote_at_list, REPL_SCHEMA_AS_CONSUMER);
  6767. attr_syntax_unlock_read();
  6768. /* For each of them copy the value to set */
  6769. for (at2learn = at2learn_list; at2learn != NULL; at2learn = at2learn->next) {
  6770. struct berval *bv;
  6771. bv = mods[i]->mod_bvalues[at2learn->index]; /* takes the berval from the selected mod */
  6772. at2learn->new_value = (char *) slapi_ch_malloc(bv->bv_len + 1);
  6773. memcpy(at2learn->new_value, bv->bv_val, bv->bv_len);
  6774. at2learn->new_value[bv->bv_len] = '\0';
  6775. slapi_log_error(SLAPI_LOG_REPL, "schema", "take attributetypes: %s\n", at2learn->new_value);
  6776. }
  6777. /* Free the remote schema list */
  6778. schema_atlist_free(remote_at_list);
  6779. } else if (strcasecmp(mods[i]->mod_type, "objectclasses") == 0) {
  6780. /* we have some MOD_replace of objectclasses */
  6781. /* First build an objectclass list from the remote schema */
  6782. if ((remote_oc_list = schema_berval_to_oclist(mods[i]->mod_bvalues)) == NULL) {
  6783. /* If we can not build an objectclasses list from the mods, just skip
  6784. * it and look for attributes
  6785. */
  6786. slapi_log_error(SLAPI_LOG_FATAL, "schema",
  6787. "Not able to build an objectclasses list (%s) from the schema received from the supplier\n",
  6788. mods[i]->mod_type);
  6789. continue;
  6790. }
  6791. /* Build a list of objectclasses to learn from the remote definitions */
  6792. oc_lock_read();
  6793. oc2learn_list = schema_list_oc2learn(remote_oc_list, g_get_global_oc_nolock(), REPL_SCHEMA_AS_CONSUMER);
  6794. oc_unlock();
  6795. /* For each of them copy the value to set */
  6796. for (oc2learn = oc2learn_list; oc2learn != NULL; oc2learn = oc2learn->next) {
  6797. struct berval *bv;
  6798. bv = mods[i]->mod_bvalues[oc2learn->index]; /* takes the berval from the selected mod */
  6799. oc2learn->new_value = (char *) slapi_ch_malloc(bv->bv_len + 1);
  6800. memcpy(oc2learn->new_value, bv->bv_val, bv->bv_len);
  6801. oc2learn->new_value[bv->bv_len] = '\0';
  6802. slapi_log_error(SLAPI_LOG_REPL, "schema", "take objectclass: %s\n", oc2learn->new_value);
  6803. }
  6804. /* Free the remote schema list*/
  6805. schema_oclist_free(remote_oc_list);
  6806. }
  6807. }
  6808. }
  6809. schema_dse_unlock();
  6810. *at_list = at2learn_list;
  6811. *oc_list = oc2learn_list;
  6812. }
  6813. /*
  6814. * It evaluate if the schema in the mods, is a superset of
  6815. * the local schema.
  6816. * Called when we know the mods comes from/to a replicated session
  6817. * Caller must not hold schema_dse lock
  6818. *
  6819. * mods: set of mod to apply to the schema
  6820. * replica_role:
  6821. * OC_CONSUMER: means the caller is acting as a consumer (receiving a schema)
  6822. * OC_SUPPLIER: means the caller is acting as a supplier (sending a schema)
  6823. *
  6824. * It returns:
  6825. * - PR_TRUE: if replicated schema is a superset of local schema
  6826. * - PR_FALSE: if local schema is a superset of local schema
  6827. */
  6828. static PRBool
  6829. check_replicated_schema(LDAPMod **mods, char *replica_role, char **attr_name)
  6830. {
  6831. int i;
  6832. PRBool rc = PR_TRUE;
  6833. schema_dse_lock_read();
  6834. for (i = 0; mods[i]; i++) {
  6835. if ((SLAPI_IS_MOD_REPLACE(mods[i]->mod_op)) && strcasecmp (mods[i]->mod_type, "attributetypes") == 0) {
  6836. if (schema_attributetypes_superset_check(mods[i]->mod_bvalues, replica_role)) {
  6837. rc = PR_FALSE;
  6838. *attr_name = mods[i]->mod_type;
  6839. break;
  6840. }
  6841. } else if ((SLAPI_IS_MOD_REPLACE(mods[i]->mod_op)) && strcasecmp (mods[i]->mod_type, "objectclasses") == 0) {
  6842. if (schema_objectclasses_superset_check(mods[i]->mod_bvalues, replica_role)) {
  6843. rc = PR_FALSE;
  6844. *attr_name = mods[i]->mod_type;
  6845. break;
  6846. }
  6847. }
  6848. }
  6849. schema_dse_unlock();
  6850. return rc;
  6851. }
  6852. /* Free the list of definitions allocated in modify_schema_get_new_definitions/supplier_get_new_definitions */
  6853. static void
  6854. modify_schema_free_new_definitions(struct schema_mods_indexes *def_list)
  6855. {
  6856. struct schema_mods_indexes *def, *head;
  6857. for (head = def_list; head != NULL; ) {
  6858. def = head;
  6859. head = head->next;
  6860. /* Free the string definition that was copied from the berval */
  6861. if (def->new_value) {
  6862. slapi_ch_free((void**) &def->new_value);
  6863. }
  6864. /* Then the definition cell */
  6865. slapi_ch_free((void **) &def);
  6866. }
  6867. }
  6868. /* This functions is called by a supplier.
  6869. * It builds lists of definitions (attributetypes/objectclasses) to learn
  6870. * objectclasses: received objectclass definitions
  6871. * attributetypes: received attribute definitions
  6872. * new_oc: list of definitions to learn (list should be freed by the caller)
  6873. * new_at: list of definitions to learn (list should be freed by the caller)
  6874. */
  6875. static void
  6876. supplier_get_new_definitions(struct berval **objectclasses, struct berval **attributetypes, struct schema_mods_indexes **new_oc, struct schema_mods_indexes **new_at)
  6877. {
  6878. int replace_allowed = 0;
  6879. slapdFrontendConfig_t *slapdFrontendConfig;
  6880. struct asyntaxinfo *remote_at_list;
  6881. struct objclass *remote_oc_list;
  6882. struct schema_mods_indexes *at2learn_list = NULL;
  6883. struct schema_mods_indexes *at2learn;
  6884. struct schema_mods_indexes *oc2learn_list = NULL;
  6885. struct schema_mods_indexes *oc2learn;
  6886. *new_oc = NULL;
  6887. *new_at = NULL;
  6888. if ((objectclasses == NULL) && (attributetypes == NULL)) {
  6889. return;
  6890. }
  6891. /* Check if we are allowed to update the schema (if needed) */
  6892. slapdFrontendConfig = getFrontendConfig();
  6893. CFG_LOCK_READ(slapdFrontendConfig);
  6894. if ((0 == strcasecmp(slapdFrontendConfig->schemareplace, CONFIG_SCHEMAREPLACE_STR_ON)) ||
  6895. (0 == strcasecmp(slapdFrontendConfig->schemareplace, CONFIG_SCHEMAREPLACE_STR_REPLICATION_ONLY))) {
  6896. replace_allowed = 1;
  6897. }
  6898. CFG_UNLOCK_READ(slapdFrontendConfig);
  6899. if (!replace_allowed) {
  6900. return;
  6901. }
  6902. schema_dse_lock_read();
  6903. /*
  6904. * Build the list of objectclasses
  6905. */
  6906. /* from berval to objclass more convenient to compare */
  6907. if ((remote_oc_list = schema_berval_to_oclist(objectclasses)) != NULL) {
  6908. /* Build a list of objectclasses to learn from the remote definitions */
  6909. oc_lock_read();
  6910. oc2learn_list = schema_list_oc2learn(remote_oc_list, g_get_global_oc_nolock(), REPL_SCHEMA_AS_SUPPLIER);
  6911. oc_unlock();
  6912. /* For each of them copy the value to set */
  6913. for (oc2learn = oc2learn_list; oc2learn != NULL; oc2learn = oc2learn->next) {
  6914. struct berval *bv;
  6915. bv = objectclasses[oc2learn->index]; /* takes the berval from the selected objectclass */
  6916. oc2learn->new_value = (char *) slapi_ch_malloc(bv->bv_len + 1);
  6917. memcpy(oc2learn->new_value, bv->bv_val, bv->bv_len);
  6918. oc2learn->new_value[bv->bv_len] = '\0';
  6919. slapi_log_error(SLAPI_LOG_REPL, "schema", "supplier takes objectclass: %s\n", oc2learn->new_value);
  6920. }
  6921. /* Free the remote schema list*/
  6922. schema_oclist_free(remote_oc_list);
  6923. } else {
  6924. /* If we can not build an objectclasses list */
  6925. slapi_log_error(SLAPI_LOG_FATAL, "schema",
  6926. "Not able to build an objectclasses list from the consumer schema\n");
  6927. }
  6928. /*
  6929. * Build the list of attributetypes
  6930. */
  6931. /* First build an attribute list from the remote schema */
  6932. if ((remote_at_list = schema_berval_to_atlist(attributetypes)) != NULL) {
  6933. /* Build a list of attributestype to learn from the remote definitions */
  6934. attr_syntax_read_lock();
  6935. at2learn_list = schema_list_attr2learn(attr_syntax_get_global_at(), remote_at_list, REPL_SCHEMA_AS_SUPPLIER);
  6936. attr_syntax_unlock_read();
  6937. /* For each of them copy the value to set */
  6938. for (at2learn = at2learn_list; at2learn != NULL; at2learn = at2learn->next) {
  6939. struct berval *bv;
  6940. bv = attributetypes[at2learn->index]; /* takes the berval from the selected mod */
  6941. at2learn->new_value = (char *) slapi_ch_malloc(bv->bv_len + 1);
  6942. memcpy(at2learn->new_value, bv->bv_val, bv->bv_len);
  6943. at2learn->new_value[bv->bv_len] = '\0';
  6944. slapi_log_error(SLAPI_LOG_REPL, "schema", "supplier takes attributetypes: %s\n", at2learn->new_value);
  6945. }
  6946. /* Free the remote schema list */
  6947. schema_atlist_free(remote_at_list);
  6948. } else {
  6949. /* If we can not build an attributes list from the mods, just skip
  6950. * it and look for objectclasses
  6951. */
  6952. slapi_log_error(SLAPI_LOG_FATAL, "schema",
  6953. "Not able to build an attributes list from the consumer schema");
  6954. }
  6955. schema_dse_unlock();
  6956. *new_oc = oc2learn_list;
  6957. *new_at = at2learn_list;
  6958. }
  6959. /* This functions is called by a supplier when it detects new definitions (objectclasses/attributetypes)
  6960. * or extension of existing definitions in a consumer schema.
  6961. * This function, build lists of definitions to "learn" and add those definitions in the schema and 99user.ldif
  6962. */
  6963. void
  6964. supplier_learn_new_definitions(struct berval **objectclasses, struct berval **attributetypes)
  6965. {
  6966. struct schema_mods_indexes *oc_list = NULL;
  6967. struct schema_mods_indexes *at_list = NULL;
  6968. supplier_get_new_definitions(objectclasses, attributetypes, &oc_list, &at_list);
  6969. if (at_list) {
  6970. modify_schema_apply_new_definitions("attributetypes", at_list);
  6971. }
  6972. if (oc_list) {
  6973. modify_schema_apply_new_definitions("objectclasses", oc_list);
  6974. }
  6975. /* No need to hold the lock for these list that are local */
  6976. modify_schema_free_new_definitions(at_list);
  6977. modify_schema_free_new_definitions(oc_list);
  6978. }