WebDAVFileSystem.cpp 400 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226
  1. //---------------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include <malloc.h>
  5. #include <stdio.h>
  6. #include <wincrypt.h>
  7. #include <apr_hash.h>
  8. #include <apr_strings.h>
  9. #include <apr_tables.h>
  10. #include <apr_file_io.h>
  11. #include <apr_portable.h>
  12. #include <apr_atomic.h>
  13. #include <ne_basic.h>
  14. #include <ne_auth.h>
  15. #include <ne_compress.h>
  16. #include <ne_props.h>
  17. #include <ne_defs.h>
  18. #include <ne_uri.h>
  19. #include <ne_session.h>
  20. #include <ne_request.h>
  21. #include <ne_xml.h>
  22. #include <ne_pkcs11.h>
  23. #include "WebDAVFileSystem.h"
  24. #include "Interface.h"
  25. #include "Common.h"
  26. #include "Exceptions.h"
  27. #include "Terminal.h"
  28. #include "TextsCore.h"
  29. #include "SecureShell.h"
  30. #include "FileZillaIntf.h"
  31. #include "HelpCore.h"
  32. //---------------------------------------------------------------------------
  33. #pragma package(smart_init)
  34. //---------------------------------------------------------------------------
  35. const int tfFirstLevel = 0x01;
  36. const int tfAutoResume = 0x02;
  37. //---------------------------------------------------------------------------
  38. struct TSinkFileParams
  39. {
  40. UnicodeString TargetDir;
  41. const TCopyParamType * CopyParam;
  42. int Params;
  43. TFileOperationProgressType * OperationProgress;
  44. bool Skipped;
  45. unsigned int Flags;
  46. };
  47. //---------------------------------------------------------------------------
  48. struct TFileTransferData
  49. {
  50. TFileTransferData()
  51. {
  52. Params = 0;
  53. AutoResume = false;
  54. OverwriteResult = -1;
  55. CopyParam = NULL;
  56. }
  57. UnicodeString FileName;
  58. int Params;
  59. bool AutoResume;
  60. int OverwriteResult;
  61. const TCopyParamType * CopyParam;
  62. };
  63. //---------------------------------------------------------------------------
  64. struct TClipboardHandler
  65. {
  66. UnicodeString Text;
  67. void __fastcall Copy(TObject * /*Sender*/)
  68. {
  69. CopyToClipboard(Text);
  70. }
  71. };
  72. //---------------------------------------------------------------------------
  73. namespace webdav {
  74. #pragma warn -8004
  75. const AnsiString __cdecl Format(const char * format, va_list args)
  76. {
  77. int len = AnsiString().vprintf(format, args);
  78. AnsiString Result;
  79. Result.SetLength(len + 1);
  80. vsprintf(&Result[1], format, args);
  81. return Result.c_str();
  82. }
  83. const AnsiString __cdecl Format(const char * format, ...)
  84. {
  85. va_list args;
  86. va_start(args, format);
  87. AnsiString Result = Format(format, args);
  88. va_end(args);
  89. return Result;
  90. }
  91. //---------------------------------------------------------------------------
  92. struct auth_baton_t;
  93. struct vtable_t;
  94. struct stream_t;
  95. struct client_ctx_t;
  96. struct auth_iterstate_t;
  97. //---------------------------------------------------------------------------
  98. typedef enum tristate_t
  99. {
  100. tristate_false = 2,
  101. tristate_true,
  102. tristate_unknown
  103. } tristate_t;
  104. //------------------------------------------------------------------------------
  105. // Userdata for the `proxy_auth' function.
  106. struct proxy_auth_baton_t
  107. {
  108. const char * username; // Cannot be NULL, but "" is okay.
  109. const char * password; // Cannot be NULL, but "" is okay.
  110. };
  111. //------------------------------------------------------------------------------
  112. // from svn_types.h
  113. typedef error_t (*cancel_func_t)(void * cancel_baton);
  114. //------------------------------------------------------------------------------
  115. // from svn_ra.h
  116. typedef void (*progress_notify_func_t)(
  117. apr_off_t progress,
  118. apr_off_t total,
  119. void * baton,
  120. apr_pool_t * pool);
  121. typedef error_t (*get_client_string_func_t)(void * baton,
  122. const char ** name,
  123. apr_pool_t * pool);
  124. typedef struct callbacks2_t
  125. {
  126. auth_baton_t * auth_baton;
  127. progress_notify_func_t progress_func;
  128. void * progress_baton;
  129. cancel_func_t cancel_func;
  130. get_client_string_func_t get_client_string;
  131. } callbacks2_t;
  132. typedef struct callback_baton_t
  133. {
  134. client_ctx_t * ctx;
  135. apr_pool_t * pool;
  136. } callback_baton_t;
  137. //------------------------------------------------------------------------------
  138. // from ra_loader.h
  139. typedef error_t (*init_func_t)(const vtable_t ** vtable,
  140. apr_pool_t * pool);
  141. //------------------------------------------------------------------------------
  142. // from svn_string.h
  143. // A simple counted string.
  144. typedef struct string_t
  145. {
  146. const char * data; //< pointer to the bytestring
  147. apr_size_t len; //< length of bytestring
  148. } string_t;
  149. // A buffered string, capable of appending without an allocation and copy
  150. // for each append.
  151. typedef struct stringbuf_t
  152. {
  153. apr_pool_t * pool;
  154. char * data;
  155. apr_size_t len;
  156. apr_size_t blocksize;
  157. } stringbuf_t;
  158. //------------------------------------------------------------------------------
  159. // from ra_neon.h
  160. // Rename these types and constants to abstract from Neon
  161. #define NEON_XML_DECLINE NE_XML_DECLINE
  162. #define NEON_XML_INVALID NE_XML_ABORT
  163. #define NEON_XML_CDATA (1<<1)
  164. #define NEON_XML_COLLECT ((1<<2) | NEON_XML_CDATA)
  165. // Related to anonymous enum below?
  166. typedef int neon_xml_elmid;
  167. typedef struct neon_xml_elm_t
  168. {
  169. const char * nspace;
  170. const char * name;
  171. neon_xml_elmid id;
  172. // Processing flags for this namespace:tag.
  173. // 0 (zero) - regular element, may have children,
  174. // NEON_XML_CDATA - child-less element,
  175. // NEON_XML_COLLECT - complete contents of such element must be
  176. // collected as CDATA, includes *_CDATA flag.
  177. unsigned int flags;
  178. } neon_xml_elm_t;
  179. typedef struct neon_session_t
  180. {
  181. apr_pool_t * pool;
  182. stringbuf_t * url; // original, unparsed session url
  183. ne_uri root; // parsed version of above
  184. const char * webdav_root; // URL for WebDAV resource root
  185. ne_session * ne_sess; // HTTP session to server
  186. const callbacks2_t * callbacks; // callbacks to get auth data
  187. void * callback_baton;
  188. auth_iterstate_t * auth_iterstate; // state of authentication retries
  189. bool auth_used; // Save authorization state after
  190. // successful usage
  191. auth_iterstate_t * p11pin_iterstate; // state of PKCS#11 pin retries
  192. bool compression; // should we use http compression?
  193. progress_notify_func_t progress_func;
  194. void * progress_baton;
  195. apr_off_t total_progress; // Total number of bytes sent in this
  196. // session with a -1 total marker
  197. apr_hash_t * capabilities;
  198. } neon_session_t;
  199. typedef struct neon_request_t
  200. {
  201. ne_request * ne_req; // neon request structure
  202. ne_session * ne_sess; // neon session structure
  203. neon_session_t * sess; // DAV session structure
  204. const char * method;
  205. const char * url;
  206. int rv; // Return value from
  207. // ne_request_dispatch() or -1 if
  208. // not dispatched yet.
  209. int code; // HTTP return code, or 0 if none
  210. const char * code_desc; // Textual description of CODE
  211. error_t err; // error encountered while executing
  212. // the request
  213. bool marshalled_error; // TRUE if the error was server-side
  214. apr_pool_t * pool; // where this struct is allocated
  215. apr_pool_t * iterpool; // iteration pool
  216. // for use within callbacks
  217. } neon_request_t;
  218. // Related to neon_xml_elmid?
  219. // add WEBDAV_NEON_ to these to prefix conflicts with (sys) headers?
  220. enum
  221. {
  222. // Redefine Neon elements
  223. // With the new API, we need to be able to use element id also as a return
  224. // value from the new `startelm' callback, hence all element ids must be
  225. // positive. Root element id is the only id that is not positive, it's zero.
  226. // `Root state' is never returned by a callback, it's only passed into it.
  227. // Therefore, negative element ids are forbidden from now on.
  228. ELEM_unknown = 1, // was (-1), see above why it's (1) now
  229. ELEM_root = NE_XML_STATEROOT, // (0)
  230. ELEM_UNUSED = 100,
  231. ELEM_207_first = ELEM_UNUSED,
  232. ELEM_multistatus = ELEM_207_first,
  233. ELEM_response = ELEM_207_first + 1,
  234. ELEM_responsedescription = ELEM_207_first + 2,
  235. ELEM_href = ELEM_207_first + 3,
  236. ELEM_propstat = ELEM_207_first + 4,
  237. ELEM_prop = ELEM_207_first + 5, // `prop' tag in the DAV namespace
  238. ELEM_status = ELEM_207_first + 6,
  239. ELEM_207_UNUSED = ELEM_UNUSED + 100,
  240. ELEM_PROPS_UNUSED = ELEM_207_UNUSED + 100,
  241. // DAV elements
  242. ELEM_collection = ELEM_207_UNUSED,
  243. ELEM_comment,
  244. ELEM_creationdate,
  245. ELEM_creator_displayname,
  246. ELEM_options_response,
  247. ELEM_set_prop,
  248. ELEM_remove_prop,
  249. ELEM_resourcetype,
  250. ELEM_get_content_length,
  251. ELEM_get_last_modified,
  252. ELEM_updated_set,
  253. ELEM_error,
  254. ELEM_human_readable,
  255. };
  256. // The session object.
  257. struct session_t
  258. {
  259. const vtable_t * vtable;
  260. // Pool used to manage this session.
  261. apr_pool_t * pool;
  262. // Private data for the RA implementation.
  263. void * priv;
  264. };
  265. typedef std::vector<TListDataEntry> listdataentry_vector_t;
  266. // Baton used when listing directory entries.
  267. typedef struct list_func_baton_t
  268. {
  269. bool verbose;
  270. listdataentry_vector_t * entries;
  271. session_t * session;
  272. apr_pool_t * pool;
  273. } list_func_baton_t;
  274. //------------------------------------------------------------------------------
  275. // timeout (in seconds)
  276. #define DEFAULT_HTTP_TIMEOUT 10
  277. #define WEBDAV_ERR_DAV_SOCK_INIT 1000
  278. #define WEBDAV_ERR_XML_MALFORMED 1001
  279. #define WEBDAV_ERR_DAV_OPTIONS_REQ_FAILED 1002
  280. #define WEBDAV_ERR_DAV_REQUEST_FAILED 1003
  281. #define WEBDAV_ERR_INCORRECT_PARAMS 1004
  282. #define WEBDAV_ERR_FS_NOT_FOUND 1005
  283. #define WEBDAV_ERR_FS_PROP_BASEVALUE_MISMATCH 1006
  284. #define WEBDAV_ERR_DAV_FORBIDDEN 1010
  285. #define WEBDAV_ERR_DAV_RELOCATED 1011
  286. #define WEBDAV_ERR_NOT_AUTHORIZED 1012
  287. #define WEBDAV_ERR_ILLEGAL_URL 1013
  288. #define WEBDAV_ERR_DAV_NOT_IMPLEMENTED 1014
  289. #define WEBDAV_ERR_NOT_IMPLEMENTED 1015
  290. #define WEBDAV_ERR_AUTHN_NO_PROVIDER 1020
  291. #define WEBDAV_ERR_CLIENT_CYCLE_DETECTED 1021
  292. #define WEBDAV_ERR_DAV_MALFORMED_DATA 1022
  293. #define WEBDAV_ERR_IO_PIPE_WRITE_ERROR 1023
  294. #define WEBDAV_ERR_BAD_DATE 1024
  295. #define WEBDAV_ERR_CLIENT_UNRELATED_RESOURCES 1025
  296. #define WEBDAV_ERR_ROOT_URL_MISMATCH 1027
  297. #define WEBDAV_ERR_BAD_FILENAME 1028
  298. #define WEBDAV_ERR_ENTRY_MISSING_URL 1029
  299. #define WEBDAV_ERR_FS_NOT_FILE 1030
  300. #define WEBDAV_ERR_ATOMIC_INIT_FAILURE 1033
  301. #define WEBDAV_ERR_IO_UNIQUE_NAMES_EXHAUSTED 1034
  302. #define WEBDAV_ERR_STREAM_SEEK_NOT_SUPPORTED 1035
  303. #define WEBDAV_ERR_BAD_CONFIG_VALUE 1040
  304. #define WEBDAV_ERR_CANCELLED 1050
  305. #define WEBDAV_ERR_DAV_INVALID_CONFIG_VALUE 1051
  306. #define WEBDAV_ERR_DAV_PROPPATCH_FAILED 1060
  307. #define WEBDAV_ERR_CANNOT_PUT_FILE 1061
  308. #define WEBDAV_ERR_CANNOT_DELETE_FILE 1062
  309. #define WEBDAV_ERR_CANNOT_MKCOL 1063
  310. #define WEBDAV_ERR_CANNOT_MOVE 1064
  311. #define WEBDAV_ERR_CANNOT_PROPFIND 1065
  312. #define WEBDAV_ERR_BAD_PARAM 1070
  313. // The application doesn't want any providers to save credentials
  314. // to disk. Property value is irrelevant; only property's existence
  315. // matters.
  316. #define AUTH_PARAM_NO_AUTH_CACHE AUTH_PARAM_PREFIX "no-auth-cache"
  317. // #define HASH_KEY_STRING ""
  318. #define MAX_REDIRECT_ATTEMPTS 3 // TODO: Make configurable.
  319. //---------------------------------------------------------------------------
  320. // #define WEBDAV_ARRAY_IDX(ary,i,type) ((type)(ary)[i])
  321. #define WEBDAV_NO_ERROR 0
  322. #define WEBDAV_UNKNOWN_ERROR 1
  323. #define WEBDAV_ERR(expr) \
  324. do { \
  325. webdav::error_t err__temp = (expr); \
  326. if (err__temp) \
  327. return err__temp; \
  328. } while (0)
  329. // A statement macro, very similar to WEBDAV_ERR.
  330. // This macro will wrap the error with the specified text before
  331. // returning the error.
  332. #define WEBDAV_ERR_W(expr, wrap_msg) \
  333. do { \
  334. webdav::error_t err__temp = (expr); \
  335. if (err__temp) \
  336. return webdav::error_create(err__temp, NULL, wrap_msg); \
  337. } while (0)
  338. #define WEBDAV_ERR_ASSERT(expr) \
  339. do { \
  340. if (!(expr)) \
  341. WEBDAV_ERR(WEBDAV_UNKNOWN_ERROR); \
  342. } while (0)
  343. #define error_trace(expr) (expr)
  344. // Create a pool as a subpool of parent_pool
  345. #define webdav_pool_create(parent_pool) webdav::pool_create_ex(parent_pool, NULL)
  346. #define webdav_pool_clear apr_pool_clear
  347. // Destroy a pool and all of its children.
  348. // This define for webdav_pool_destroy exists for symmetry and
  349. // completeness.
  350. #define webdav_pool_destroy apr_pool_destroy
  351. // Destroy request REQ and any associated resources
  352. #define neon_request_destroy(req) webdav_pool_destroy((req)->pool)
  353. // Statement macro to set the request error,
  354. // making sure we don't leak any in case we encounter more than one error.
  355. // Sets the 'err' field of REQ to the value obtained by evaluating NEW_ERR.
  356. #define NEON_REQ_ERR(req, new_err) \
  357. do { \
  358. error_t err__tmp = (new_err); \
  359. if ((req)->err && !(req)->marshalled_error) \
  360. error_clear(&err__tmp); \
  361. else if (err__tmp) \
  362. { \
  363. error_clear(&(req)->err); \
  364. (req)->err = err__tmp; \
  365. (req)->marshalled_error = false; \
  366. } \
  367. } while (0)
  368. //===========================================================================
  369. //------------------------------------------------------------------------------
  370. // from error.c
  371. static void
  372. error_clear(error_t * err)
  373. {
  374. if (err) *err = 0;
  375. }
  376. static error_t
  377. make_error_internal(
  378. apr_status_t apr_err,
  379. error_t * child)
  380. {
  381. error_t new_error = apr_err;
  382. return new_error;
  383. }
  384. static error_t
  385. error_create(
  386. apr_status_t apr_err,
  387. error_t * child,
  388. const char * message)
  389. {
  390. return apr_err;
  391. }
  392. static error_t
  393. error_createf(
  394. apr_status_t apr_err,
  395. error_t * child,
  396. const char * fmt,
  397. ...)
  398. {
  399. va_list args;
  400. va_start(args, fmt);
  401. AnsiString Message = Format(fmt, args);
  402. va_end(args);
  403. AnsiString Message2 = Format("Error, code: %d, message: %s", apr_err, Message.c_str());
  404. throw ExtException(UnicodeString(Message2), NULL);
  405. }
  406. static error_t
  407. error_wrap_apr(
  408. apr_status_t status,
  409. const char * fmt,
  410. ...)
  411. {
  412. error_t err = 0;
  413. va_list args;
  414. err = make_error_internal(status, NULL);
  415. va_start(args, fmt);
  416. AnsiString Message = Format(fmt, args);
  417. va_end(args);
  418. err = error_create(err, NULL, Message.c_str());
  419. return err;
  420. }
  421. //------------------------------------------------------------------------------
  422. // from utils.c
  423. // a cleanup routine attached to the pool that contains the RA session
  424. // root URI.
  425. static apr_status_t
  426. cleanup_uri(void * uri)
  427. {
  428. ne_uri_free(static_cast<ne_uri *>(uri));
  429. return APR_SUCCESS;
  430. }
  431. static error_t
  432. parse_url(
  433. const char * url, ne_uri * uri)
  434. {
  435. if (ne_uri_parse(url, uri) ||
  436. (uri->host == NULL) || (uri->path == NULL) || (uri->scheme == NULL))
  437. {
  438. ne_uri_free(uri);
  439. return 0;
  440. }
  441. if (uri->port == 0)
  442. uri->port = ne_uri_defaultport(uri->scheme);
  443. return 1;
  444. }
  445. static error_t
  446. parse_ne_uri(
  447. ne_uri ** uri,
  448. const char * webdav_url,
  449. apr_pool_t * pool)
  450. {
  451. // Sanity check the URI
  452. *uri = static_cast<ne_uri *>(apr_pcalloc(pool, sizeof(**uri)));
  453. if (!parse_url(webdav_url, *uri))
  454. {
  455. return error_createf(WEBDAV_ERR_ILLEGAL_URL, NULL,
  456. "URL '%s' is malformed or the "
  457. "scheme or host or path is missing", webdav_url);
  458. }
  459. // make sure we eventually destroy the uri
  460. apr_pool_cleanup_register(pool, *uri, cleanup_uri, apr_pool_cleanup_null);
  461. return WEBDAV_NO_ERROR;
  462. }
  463. //------------------------------------------------------------------------------
  464. // from svn_types.h
  465. #define atoui64(X) ((apr_uint64_t) apr_atoi64(X))
  466. // An indication that you are interested in the kind field
  467. #define WEBDAV_DIRENT_KIND 0x00001
  468. // An indication that you are interested in the size field
  469. #define WEBDAV_DIRENT_SIZE 0x00002
  470. // An indication that you are interested in the time field
  471. #define WEBDAV_DIRENT_TIME 0x00010
  472. // A combination of all the dirent fields
  473. #define WEBDAV_DIRENT_ALL ~((apr_uint32_t ) 0)
  474. // The various types of nodes in filesystem.
  475. typedef enum node_kind_t
  476. {
  477. // absent
  478. node_none,
  479. // regular file
  480. node_file,
  481. // directory
  482. node_dir,
  483. // something's here, but we don't know what
  484. node_unknown
  485. } node_kind_t;
  486. // A general directory entry.
  487. typedef struct dirent_t
  488. {
  489. // node kind
  490. node_kind_t kind;
  491. // length of file text, or 0 for directories
  492. apr_int64_t size;
  493. // time of mod-time
  494. apr_time_t time;
  495. } dirent_t;
  496. typedef enum depth_t
  497. {
  498. // Just the named directory D, no entries. Updates will not pull in
  499. // any files or subdirectories not already present.
  500. depth_empty = 0,
  501. // D + its file children, but not subdirs. Updates will pull in any
  502. // files not already present, but not subdirectories.
  503. depth_files = 1,
  504. // D + immediate children (D and its entries). Updates will pull in
  505. // any files or subdirectories not already present; those
  506. // subdirectories' this_dir entries will have depth-empty.
  507. depth_immediates = 2,
  508. // D + all descendants (full recursion from D). Updates will pull
  509. // in any files or subdirectories not already present; those
  510. // subdirectories' this_dir entries will have depth-infinity.
  511. // Equivalent to the pre-1.5 default update behavior.
  512. depth_infinity = 3
  513. } depth_t;
  514. //------------------------------------------------------------------------------
  515. // from utf.h
  516. static error_t
  517. utf_cstring_to_utf8(
  518. const char ** dest,
  519. const char * src,
  520. apr_pool_t * pool);
  521. static error_t
  522. utf_cstring_from_utf8(
  523. const char ** dest,
  524. const char * src,
  525. apr_pool_t * pool);
  526. // Local wrapper of path_cstring_from_utf8() that does no copying on
  527. // operating systems where APR always uses utf-8 as native path format
  528. static error_t
  529. cstring_from_utf8(
  530. const char ** path_apr,
  531. const char * path_utf8,
  532. apr_pool_t * pool);
  533. //------------------------------------------------------------------------------
  534. // from ra_neon.h
  535. #ifdef WEBDAV_DEBUG
  536. #define DEBUG_CR "\n"
  537. #else
  538. #define DEBUG_CR ""
  539. #endif
  540. #define NEON_DEPTH_ZERO 0
  541. #define NEON_DEPTH_ONE 1
  542. #define NEON_DEPTH_INFINITE -1
  543. // NEON_PROP_*: properties that we fetch from the server
  544. // These are simply symbolic names for some standard properties that we fetch.
  545. #define NEON_PROP_CREATIONDATE "DAV:creationdate"
  546. #define NEON_PROP_GETCONTENTLENGTH "DAV:getcontentlength"
  547. typedef struct neon_resource_t
  548. {
  549. // what is the URL for this resource
  550. const char * url;
  551. // is this resource a collection? (from the DAV:resourcetype element)
  552. int is_collection;
  553. // PROPSET: NAME -> VALUE (const char * -> const string_t *)
  554. apr_hash_t * propset;
  555. // --- only used during response processing ---
  556. // when we see a DAV:href element, what element is the parent?
  557. int href_parent;
  558. apr_pool_t * pool;
  559. } neon_resource_t;
  560. // Our equivalent of ne_xml_startelm_cb, the difference being that it
  561. // returns errors in a error_t, and returns the element type via
  562. // ELEM. To ignore the element *ELEM should be set to
  563. // NEON_XML_DECLINE and WEBDAV_NO_ERROR should be returned.
  564. // *ELEM can be set to NEON_XML_INVALID to indicate invalid XML
  565. // (and abort the parse).
  566. typedef error_t (*neon_startelm_cb_t)(int * elem,
  567. void * baton,
  568. int parent,
  569. const char * nspace,
  570. const char * name,
  571. const char ** atts);
  572. // Our equivalent of ne_xml_cdata_cb, the difference being that it returns
  573. // errors in a error_t.
  574. typedef error_t (*neon_cdata_cb_t)(void * baton,
  575. int state,
  576. const char * cdata,
  577. size_t len);
  578. // Our equivalent of ne_xml_endelm_cb, the difference being that it returns
  579. // errors in a error_t.
  580. typedef error_t (*neon_endelm_cb_t)(void * baton,
  581. int state,
  582. const char * nspace,
  583. const char * name);
  584. static ne_xml_parser *
  585. neon_xml_parser_create(
  586. neon_request_t * req,
  587. ne_accept_response accpt,
  588. neon_startelm_cb_t startelm_cb,
  589. neon_cdata_cb_t cdata_cb,
  590. neon_endelm_cb_t endelm_cb,
  591. void * baton);
  592. static error_t
  593. neon_request_dispatch(
  594. int * code_p,
  595. neon_request_t * req,
  596. apr_hash_t * extra_headers,
  597. const char * body,
  598. int okay_1,
  599. int okay_2,
  600. bool check_errors,
  601. apr_pool_t * pool);
  602. static error_t
  603. neon_check_parse_error(
  604. const char * method,
  605. ne_xml_parser * xml_parser,
  606. const char * url);
  607. static error_t
  608. neon_request_create(
  609. neon_request_t ** request,
  610. neon_session_t * sess,
  611. const char * method, const char * url,
  612. apr_pool_t * pool);
  613. static const neon_xml_elm_t *
  614. neon_lookup_xml_elem(
  615. const neon_xml_elm_t * table,
  616. const char * nspace,
  617. const char * name);
  618. static error_t
  619. neon_xml_collect_cdata(
  620. void * baton, int state,
  621. const char * cdata, size_t len);
  622. static const char *
  623. neon_request_get_location(
  624. neon_request_t * request,
  625. apr_pool_t * pool);
  626. // Our version of ne_block_reader, which returns an
  627. // error_t instead of an int.
  628. typedef error_t (*neon_block_reader)(
  629. void * baton,
  630. const char * data,
  631. size_t len);
  632. //------------------------------------------------------------------------------
  633. // from dirent_uri.h
  634. static bool
  635. dirent_is_root(
  636. const char * dirent,
  637. apr_size_t len);
  638. //------------------------------------------------------------------------------
  639. // from svn_props.h
  640. static error_t
  641. neon_get_props_resource(
  642. neon_resource_t ** rsrc,
  643. neon_session_t * sess,
  644. const char * url,
  645. const ne_propname * which_props,
  646. bool check_errors,
  647. apr_pool_t * pool);
  648. //------------------------------------------------------------------------------
  649. // from ra_loader.h
  650. // The RA layer vtable.
  651. typedef struct vtable_t
  652. {
  653. // Return a short description of the RA implementation, as a localized
  654. // string.
  655. const char * (*get_description)(void);
  656. // Return a list of actual URI schemes supported by this implementation.
  657. // The returned array is NULL-terminated.
  658. const char * const * (*get_schemes)(apr_pool_t * pool);
  659. // Implementations of the public API functions.
  660. // See session_open().
  661. // All fields in SESSION, except priv, have been initialized by the
  662. // time this is called. SESSION->priv may be set by this function.
  663. error_t (*open_session)(session_t * session,
  664. const char ** corrected_url,
  665. const char * session_URL,
  666. const callbacks2_t * callbacks,
  667. void * callback_baton,
  668. apr_pool_t * pool);
  669. // See reparent().
  670. // URL is guaranteed to have what get_webdav_resource_root() returns as a prefix.
  671. error_t (*reparent)(session_t * session,
  672. const char * url,
  673. apr_pool_t * pool);
  674. // See get_session_url().
  675. error_t (*get_session_url)(session_t * session,
  676. const char ** url,
  677. apr_pool_t * pool);
  678. // See get_file().
  679. error_t (*get_file)(session_t * session,
  680. const char * path,
  681. stream_t * stream,
  682. apr_hash_t ** props,
  683. apr_pool_t * pool);
  684. // See get_dir2().
  685. error_t (*get_dir)(session_t * session,
  686. apr_hash_t ** dirents,
  687. const char * path,
  688. apr_uint32_t dirent_fields,
  689. apr_pool_t * pool);
  690. // See check_path().
  691. error_t (*check_path)(session_t * session,
  692. const char * path,
  693. node_kind_t * kind,
  694. apr_pool_t * pool);
  695. // See stat().
  696. error_t (*stat)(session_t * session,
  697. const char * path,
  698. dirent_t ** dirent,
  699. apr_pool_t * pool);
  700. // See get_webdav_resource_root2().
  701. error_t (*get_webdav_resource_root)(session_t * session,
  702. const char ** url,
  703. apr_pool_t * pool);
  704. // See has_capability().
  705. // error_t (*has_capability)(session_t *session,
  706. // bool *has,
  707. // const char *capability,
  708. // apr_pool_t *pool);
  709. } vtable_t;
  710. static error_t
  711. get_path_relative_to_root(
  712. session_t * session,
  713. const char ** rel_path,
  714. const char * url,
  715. apr_pool_t * pool);
  716. static error_t
  717. neon_init(
  718. const vtable_t ** vtable,
  719. apr_pool_t * pool);
  720. //------------------------------------------------------------------------------
  721. // from svn_ctype.h
  722. // Table of flags for character classification.
  723. extern const apr_uint32_t * const ctype_table;
  724. // Check if c is in the character class described by flags.
  725. // The flags is a bitwise-or combination of WEBDAV_CTYPE_*
  726. // constants. Uses #ctype_table.
  727. #define ctype_test(c, flags) \
  728. (0 != (ctype_table[(unsigned char)(c)] & (flags)))
  729. // Basic character classes
  730. #define WEBDAV_CTYPE_CNTRL 0x0001 //< Control character
  731. #define WEBDAV_CTYPE_SPACE 0x0002 //< Whitespace
  732. #define WEBDAV_CTYPE_DIGIT 0x0004 //< Decimal digit
  733. #define WEBDAV_CTYPE_UPPER 0x0008 //< Uppercase letter
  734. #define WEBDAV_CTYPE_LOWER 0x0010 //< Lowercase letter
  735. #define WEBDAV_CTYPE_PUNCT 0x0020 //< Punctuation mark
  736. #define WEBDAV_CTYPE_XALPHA 0x0040 //< Hexadecimal digits A to F
  737. #define WEBDAV_CTYPE_ASCII 0x0080 //< ASCII subset*/
  738. // Derived character classes
  739. // ASCII letter
  740. #define WEBDAV_CTYPE_ALPHA (WEBDAV_CTYPE_LOWER | WEBDAV_CTYPE_UPPER)
  741. // ASCII letter or decimal digit
  742. #define WEBDAV_CTYPE_ALNUM (WEBDAV_CTYPE_ALPHA | WEBDAV_CTYPE_DIGIT)
  743. // ASCII hexadecimal digit
  744. #define WEBDAV_CTYPE_XDIGIT (WEBDAV_CTYPE_DIGIT | WEBDAV_CTYPE_XALPHA)
  745. // Printable ASCII except space
  746. #define WEBDAV_CTYPE_GRAPH (WEBDAV_CTYPE_PUNCT | WEBDAV_CTYPE_ALNUM)
  747. // All printable ASCII
  748. #define WEBDAV_CTYPE_PRINT (WEBDAV_CTYPE_GRAPH | WEBDAV_CTYPE_SPACE)
  749. // Check if c is an ASCII control character.
  750. #define ctype_iscntrl(c) ctype_test((c), WEBDAV_CTYPE_CNTRL)
  751. // Check if c is an ASCII whitespace character.
  752. #define ctype_isspace(c) ctype_test((c), WEBDAV_CTYPE_SPACE)
  753. // Check if c is an ASCII digit.
  754. #define ctype_isdigit(c) ctype_test((c), WEBDAV_CTYPE_DIGIT)
  755. // Check if c is an ASCII uppercase letter.
  756. #define ctype_isupper(c) ctype_test((c), WEBDAV_CTYPE_UPPER)
  757. // Check if c is an ASCII lowercase letter.
  758. #define ctype_islower(c) ctype_test((c), WEBDAV_CTYPE_LOWER)
  759. // Check if c is an ASCII punctuation mark.
  760. #define ctype_ispunct(c) ctype_test((c), WEBDAV_CTYPE_PUNCT)
  761. // Check if c is an ASCII character.
  762. #define ctype_isascii(c) ctype_test((c), WEBDAV_CTYPE_ASCII)
  763. // Check if c is an ASCII letter.
  764. #define ctype_isalpha(c) ctype_test((c), WEBDAV_CTYPE_ALPHA)
  765. // Check if c is an ASCII letter or decimal digit.
  766. #define ctype_isalnum(c) ctype_test((c), WEBDAV_CTYPE_ALNUM)
  767. // Check if c is an ASCII hexadecimal digit.
  768. #define ctype_isxdigit(c) ctype_test((c), WEBDAV_CTYPE_XDIGIT)
  769. // Check if c is an ASCII graphical (visible printable) character.
  770. #define ctype_isgraph(c) ctype_test((c), WEBDAV_CTYPE_GRAPH)
  771. // Check if c is an ASCII printable character.
  772. #define ctype_isprint(c) ctype_test((c), WEBDAV_CTYPE_PRINT)
  773. // Basic extended character classes
  774. #define WEBDAV_CTYPE_UTF8LEAD 0x0100 //< UTF-8 multibyte lead byte
  775. #define WEBDAV_CTYPE_UTF8CONT 0x0200 //< UTF-8 multibyte non-lead byte
  776. #define WEBDAV_CTYPE_XMLNAME 0x0400
  777. #define WEBDAV_CTYPE_URISAFE 0x0800
  778. // Derived extended character classes
  779. // Part of a UTF-8 multibyte character.
  780. #define WEBDAV_CTYPE_UTF8MBC (WEBDAV_CTYPE_UTF8LEAD | WEBDAV_CTYPE_UTF8CONT)
  781. // All valid UTF-8 bytes.
  782. #define WEBDAV_CTYPE_UTF8 (WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UTF8MBC)
  783. // Check if c is a UTF-8 multibyte lead byte.
  784. #define ctype_isutf8lead(c) ctype_test((c), WEBDAV_CTYPE_UTF8LEAD)
  785. // Check if c is a UTF-8 multibyte continuation (non-lead) byte.
  786. #define ctype_isutf8cont(c) ctype_test((c), WEBDAV_CTYLE_UTF8CONT)
  787. // Check if c is part of a UTF-8 multibyte character.
  788. #define ctype_isutf8mbc(c) ctype_test((c), WEBDAV_CTYPE_UTF8MBC)
  789. // Check if c is valid in UTF-8.
  790. #define ctype_isutf8(c) ctype_test((c), WEBDAV_CTYPE_UTF8)
  791. #define WEBDAV_CTYPE_ASCII_MINUS 45 //< ASCII value of '-'
  792. #define WEBDAV_CTYPE_ASCII_DOT 46 //< ASCII value of '.'
  793. #define WEBDAV_CTYPE_ASCII_COLON 58 //< ASCII value of ':'
  794. #define WEBDAV_CTYPE_ASCII_UNDERSCORE 95 //< ASCII value of '_'
  795. #define WEBDAV_CTYPE_ASCII_TAB 9 //< ASCII value of a tab
  796. #define WEBDAV_CTYPE_ASCII_LINEFEED 10 //< ASCII value of a line feed
  797. #define WEBDAV_CTYPE_ASCII_CARRIAGERETURN 13
  798. //< ASCII value of a carriage return
  799. #define WEBDAV_CTYPE_ASCII_DELETE 127
  800. //< ASCII value of a delete character
  801. /*
  802. * Compare two characters a and b, treating case-equivalent
  803. * unaccented Latin (ASCII subset) letters as equal.
  804. *
  805. * Returns in integer greater than, equal to, or less than 0,
  806. * according to whether a is considered greater than, equal to,
  807. * or less than b.
  808. */
  809. static int
  810. ctype_casecmp(int a, int b);
  811. //------------------------------------------------------------------------------
  812. // from svn_string.c
  813. static APR_INLINE bool
  814. string_compare(
  815. const char * str1,
  816. const char * str2,
  817. apr_size_t len1,
  818. apr_size_t len2)
  819. {
  820. // easy way out :)
  821. if (len1 != len2)
  822. return FALSE;
  823. // now the strings must have identical lengths
  824. if ((memcmp(str1, str2, len1)) == 0)
  825. return TRUE;
  826. else
  827. return FALSE;
  828. }
  829. // Our own realloc, since APR doesn't have one. Note: this is a
  830. // generic realloc for memory pools, *not* for strings.
  831. static void *
  832. my_realloc(
  833. char * data,
  834. apr_size_t oldsize,
  835. apr_size_t request,
  836. apr_pool_t * pool)
  837. {
  838. void * new_area = NULL;
  839. // todo: it's a pity APR doesn't give us this -- sometimes it
  840. // could realloc the block merely by extending in place, sparing us
  841. // a memcpy(), but only the pool would know enough to be able to do
  842. // this. We should add a realloc() to APR if someone hasn't
  843. // already.
  844. // malloc new area
  845. new_area = apr_pcalloc(pool, request);
  846. // copy data to new area
  847. memcpy(new_area, data, oldsize);
  848. // I'm NOT freeing old area here -- cuz we're using pools, ugh.
  849. // return new area
  850. return new_area;
  851. }
  852. // string functions
  853. static stringbuf_t *
  854. stringbuf_create_ensure(
  855. apr_size_t blocksize,
  856. apr_pool_t * pool)
  857. {
  858. void * mem = NULL;
  859. stringbuf_t * new_string = NULL;
  860. // apr_pcalloc will allocate multiples of 8.
  861. // Thus, we would waste some of that memory if we stuck to the
  862. // smaller size. Note that this is safe even if apr_pcalloc would
  863. // use some other alignment or none at all.
  864. ++blocksize; // + space for '\0'
  865. blocksize = APR_ALIGN_DEFAULT(blocksize);
  866. // Allocate memory for string_t and data in one chunk.
  867. mem = apr_pcalloc(pool, sizeof(*new_string) + blocksize);
  868. // Initialize header and string
  869. new_string = static_cast<stringbuf_t *>(mem);
  870. new_string->data = (char *)mem + sizeof(*new_string);
  871. new_string->data[0] = '\0';
  872. new_string->len = 0;
  873. new_string->blocksize = blocksize;
  874. new_string->pool = pool;
  875. return new_string;
  876. }
  877. static stringbuf_t *
  878. stringbuf_ncreate(
  879. const char * bytes,
  880. apr_size_t size,
  881. apr_pool_t * pool)
  882. {
  883. stringbuf_t * strbuf = stringbuf_create_ensure(size, pool);
  884. memcpy(strbuf->data, bytes, size);
  885. // Null termination is the convention -- even if we suspect the data
  886. // to be binary, it's not up to us to decide, it's the caller's
  887. // call. Heck, that's why they call it the caller!
  888. strbuf->data[size] = '\0';
  889. strbuf->len = size;
  890. return strbuf;
  891. }
  892. static stringbuf_t *
  893. stringbuf_create(
  894. const char * cstring,
  895. apr_pool_t * pool)
  896. {
  897. return stringbuf_ncreate(cstring, strlen(cstring), pool);
  898. }
  899. static void
  900. stringbuf_ensure(
  901. stringbuf_t * str,
  902. apr_size_t minimum_size)
  903. {
  904. // Keep doubling capacity until have enough.
  905. if (str->blocksize < minimum_size)
  906. {
  907. if (str->blocksize == 0)
  908. // APR will increase odd allocation sizes to the next
  909. // multiple for 8, for instance. Take advantage of that
  910. // knowledge and allow for the extra size to be used.
  911. str->blocksize = APR_ALIGN_DEFAULT(minimum_size);
  912. else
  913. while (str->blocksize < minimum_size)
  914. {
  915. // str->blocksize is aligned;
  916. // doubling it should keep it aligned
  917. apr_size_t prev_size = str->blocksize;
  918. str->blocksize *= 2;
  919. // check for apr_size_t overflow
  920. if (prev_size > str->blocksize)
  921. {
  922. str->blocksize = minimum_size;
  923. break;
  924. }
  925. }
  926. str->data = (char *) my_realloc(str->data,
  927. str->len + 1,
  928. // We need to maintain (and thus copy)
  929. // the trailing null
  930. str->blocksize,
  931. str->pool);
  932. }
  933. }
  934. static void
  935. stringbuf_set(
  936. stringbuf_t * str,
  937. const char * value)
  938. {
  939. apr_size_t amt = strlen(value);
  940. stringbuf_ensure(str, amt + 1);
  941. memcpy(str->data, value, amt + 1);
  942. str->len = amt;
  943. }
  944. static void
  945. stringbuf_setempty(
  946. stringbuf_t * str)
  947. {
  948. if (str->len > 0)
  949. str->data[0] = '\0';
  950. str->len = 0;
  951. }
  952. static bool
  953. stringbuf_isempty(
  954. const stringbuf_t * str)
  955. {
  956. return (str->len == 0);
  957. }
  958. // Return a new string_t object, allocated in POOL, initialized with
  959. // DATA and SIZE. Do not copy the contents of DATA, just store the pointer.
  960. // SIZE is the length in bytes of DATA, excluding the required NUL
  961. // terminator.
  962. static string_t *
  963. create_string(
  964. const char * data,
  965. apr_size_t size,
  966. apr_pool_t * pool)
  967. {
  968. string_t * new_string;
  969. new_string = static_cast<string_t *>(apr_pcalloc(pool, sizeof(*new_string)));
  970. new_string->data = data;
  971. new_string->len = size;
  972. return new_string;
  973. }
  974. static string_t *
  975. string_ncreate(
  976. const char * bytes,
  977. apr_size_t size,
  978. apr_pool_t * pool)
  979. {
  980. void * mem = NULL;
  981. char * data = NULL;
  982. string_t * new_string;
  983. // Allocate memory for string_t and data in one chunk.
  984. mem = apr_pcalloc(pool, sizeof(*new_string) + size + 1);
  985. data = (char *)mem + sizeof(*new_string);
  986. new_string = static_cast<string_t *>(mem);
  987. new_string->data = data;
  988. new_string->len = size;
  989. memcpy(data, bytes, size);
  990. // Null termination is the convention -- even if we suspect the data
  991. // to be binary, it's not up to us to decide, it's the caller's
  992. // call. Heck, that's why they call it the caller!
  993. data[size] = '\0';
  994. return new_string;
  995. }
  996. static string_t *
  997. string_create(
  998. const char * cstring,
  999. apr_pool_t * pool)
  1000. {
  1001. return string_ncreate(cstring, strlen(cstring), pool);
  1002. }
  1003. static string_t *
  1004. string_createv(
  1005. apr_pool_t * pool,
  1006. const char * fmt,
  1007. va_list ap)
  1008. {
  1009. char * data = apr_pvsprintf(pool, fmt, ap);
  1010. // wrap an string_t around the new data
  1011. return create_string(data, strlen(data), pool);
  1012. }
  1013. static string_t *
  1014. string_createf(
  1015. apr_pool_t * pool,
  1016. const char * fmt,
  1017. ...)
  1018. {
  1019. string_t * str = NULL;
  1020. va_list ap;
  1021. va_start(ap, fmt);
  1022. str = string_createv(pool, fmt, ap);
  1023. va_end(ap);
  1024. return str;
  1025. }
  1026. static bool
  1027. string_compare(
  1028. const string_t * str1,
  1029. const string_t * str2)
  1030. {
  1031. return
  1032. string_compare(str1->data, str2->data, str1->len, str2->len);
  1033. }
  1034. static void
  1035. stringbuf_appendbytes(
  1036. stringbuf_t * str,
  1037. const char * bytes,
  1038. apr_size_t count)
  1039. {
  1040. apr_size_t total_len = 0;
  1041. void * start_address = NULL;
  1042. total_len = str->len + count; // total size needed
  1043. // +1 for null terminator.
  1044. stringbuf_ensure(str, (total_len + 1));
  1045. // get address 1 byte beyond end of original bytestring
  1046. start_address = (str->data + str->len);
  1047. memcpy(start_address, bytes, count);
  1048. str->len = total_len;
  1049. str->data[str->len] = '\0'; // We don't know if this is binary
  1050. // data or not, but convention is
  1051. // to null-terminate.
  1052. }
  1053. static void
  1054. stringbuf_appendstr(
  1055. stringbuf_t * targetstr,
  1056. const stringbuf_t * appendstr)
  1057. {
  1058. stringbuf_appendbytes(targetstr, appendstr->data, appendstr->len);
  1059. }
  1060. static void
  1061. stringbuf_appendcstr(
  1062. stringbuf_t * targetstr,
  1063. const char * cstr)
  1064. {
  1065. stringbuf_appendbytes(targetstr, cstr, strlen(cstr));
  1066. }
  1067. static error_t
  1068. cstring_strtoi64(
  1069. apr_int64_t * n,
  1070. const char * str,
  1071. apr_int64_t minval,
  1072. apr_int64_t maxval,
  1073. int base)
  1074. {
  1075. apr_int64_t val = 0;
  1076. char * endptr = NULL;
  1077. // We assume errno is thread-safe.
  1078. errno = 0; // APR-0.9 doesn't always set errno
  1079. val = apr_strtoi64(str, &endptr, base);
  1080. if (errno == EINVAL || endptr == str || str[0] == '\0' || *endptr != '\0')
  1081. return error_createf(WEBDAV_ERR_INCORRECT_PARAMS, NULL,
  1082. "Could not convert '%s' into a number",
  1083. str);
  1084. if ((errno == ERANGE && (val == APR_INT64_MIN || val == APR_INT64_MAX)) ||
  1085. val < minval || val > maxval)
  1086. // Mark this for translation when gettext doesn't choke on macros.
  1087. return error_createf(WEBDAV_ERR_INCORRECT_PARAMS, NULL,
  1088. "Number '%s' is out of range "
  1089. "'[%" APR_INT64_T_FMT ", %" APR_INT64_T_FMT "]'",
  1090. str, minval, maxval);
  1091. *n = val;
  1092. return WEBDAV_NO_ERROR;
  1093. }
  1094. static error_t
  1095. cstring_atoi64(
  1096. apr_int64_t * n,
  1097. const char * str)
  1098. {
  1099. return error_trace(cstring_strtoi64(n, str, APR_INT64_MIN,
  1100. APR_INT64_MAX, 10));
  1101. }
  1102. static int
  1103. cstring_casecmp(
  1104. const char * str1,
  1105. const char * str2)
  1106. {
  1107. for (;;)
  1108. {
  1109. const int a = *str1++;
  1110. const int b = *str2++;
  1111. const int cmp = ctype_casecmp(a, b);
  1112. if (cmp || !a || !b)
  1113. return cmp;
  1114. }
  1115. }
  1116. static stringbuf_t *
  1117. create_stringbuf(
  1118. char * data,
  1119. apr_size_t size,
  1120. apr_size_t blocksize,
  1121. apr_pool_t * pool)
  1122. {
  1123. stringbuf_t * new_string;
  1124. new_string = static_cast<stringbuf_t *>(apr_pcalloc(pool, sizeof(*new_string)));
  1125. new_string->data = data;
  1126. new_string->len = size;
  1127. new_string->blocksize = blocksize;
  1128. new_string->pool = pool;
  1129. return new_string;
  1130. }
  1131. static stringbuf_t *
  1132. stringbuf_createv(
  1133. apr_pool_t * pool,
  1134. const char * fmt,
  1135. va_list ap)
  1136. {
  1137. char * data = apr_pvsprintf(pool, fmt, ap);
  1138. apr_size_t size = strlen(data);
  1139. // wrap an stringbuf_t around the new data
  1140. return create_stringbuf(data, size, size + 1, pool);
  1141. }
  1142. static stringbuf_t *
  1143. stringbuf_createf(
  1144. apr_pool_t * pool,
  1145. const char * fmt,
  1146. ...)
  1147. {
  1148. stringbuf_t * str = NULL;
  1149. va_list ap;
  1150. va_start(ap, fmt);
  1151. str = stringbuf_createv(pool, fmt, ap);
  1152. va_end(ap);
  1153. return str;
  1154. }
  1155. static void
  1156. cstring_split_append(
  1157. apr_array_header_t * array,
  1158. const char * input,
  1159. const char * sep_chars,
  1160. bool chop_whitespace,
  1161. apr_pool_t * pool)
  1162. {
  1163. char * last = NULL;
  1164. char * pats = apr_pstrdup(pool, input); // strtok wants non-const data
  1165. char * p = apr_strtok(pats, sep_chars, &last);
  1166. while (p)
  1167. {
  1168. if (chop_whitespace)
  1169. {
  1170. while (ctype_isspace(*p))
  1171. p++;
  1172. {
  1173. char * e = p + (strlen(p) - 1);
  1174. while ((e >= p) && (ctype_isspace(*e)))
  1175. e--;
  1176. *(++e) = '\0';
  1177. }
  1178. }
  1179. if (p[0] != '\0')
  1180. APR_ARRAY_PUSH(array, const char *) = p;
  1181. p = apr_strtok(NULL, sep_chars, &last);
  1182. }
  1183. return;
  1184. }
  1185. static apr_array_header_t *
  1186. cstring_split(
  1187. const char * input,
  1188. const char * sep_chars,
  1189. bool chop_whitespace,
  1190. apr_pool_t * pool)
  1191. {
  1192. apr_array_header_t * a = apr_array_make(pool, 5, sizeof(input));
  1193. cstring_split_append(a, input, sep_chars, chop_whitespace, pool);
  1194. return a;
  1195. }
  1196. //------------------------------------------------------------------------------
  1197. // from ctype.c
  1198. static const apr_uint32_t ctype_table_internal[256] =
  1199. {
  1200. // **** DO NOT EDIT! ****
  1201. // This table was generated by genctype.py, make changes there.
  1202. /* nul */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1203. /* soh */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1204. /* stx */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1205. /* etx */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1206. /* eot */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1207. /* enq */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1208. /* ack */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1209. /* bel */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1210. /* bs */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1211. /* ht */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL | WEBDAV_CTYPE_SPACE,
  1212. /* nl */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL | WEBDAV_CTYPE_SPACE,
  1213. /* vt */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL | WEBDAV_CTYPE_SPACE,
  1214. /* np */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL | WEBDAV_CTYPE_SPACE,
  1215. /* cr */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL | WEBDAV_CTYPE_SPACE,
  1216. /* so */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1217. /* si */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1218. /* dle */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1219. /* dc1 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1220. /* dc2 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1221. /* dc3 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1222. /* dc4 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1223. /* nak */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1224. /* syn */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1225. /* etb */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1226. /* can */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1227. /* em */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1228. /* sub */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1229. /* esc */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1230. /* fs */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1231. /* gs */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1232. /* rs */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1233. /* us */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1234. /* sp */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_SPACE,
  1235. /* ! */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1236. /* " */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1237. /* # */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1238. /* $ */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1239. /* % */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1240. /* & */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1241. /* ' */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1242. /* ( */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1243. /* ) */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1244. /* * */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1245. /* + */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1246. /* , */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1247. /* - */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1248. /* . */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1249. /* / */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1250. /* 0 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
  1251. /* 1 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
  1252. /* 2 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
  1253. /* 3 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
  1254. /* 4 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
  1255. /* 5 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
  1256. /* 6 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
  1257. /* 7 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
  1258. /* 8 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
  1259. /* 9 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
  1260. /* : */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1261. /* ; */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1262. /* < */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1263. /* = */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1264. /* > */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1265. /* ? */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1266. /* @ */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1267. /* A */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER | WEBDAV_CTYPE_XALPHA,
  1268. /* B */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER | WEBDAV_CTYPE_XALPHA,
  1269. /* C */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER | WEBDAV_CTYPE_XALPHA,
  1270. /* D */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER | WEBDAV_CTYPE_XALPHA,
  1271. /* E */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER | WEBDAV_CTYPE_XALPHA,
  1272. /* F */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER | WEBDAV_CTYPE_XALPHA,
  1273. /* G */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1274. /* H */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1275. /* I */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1276. /* J */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1277. /* K */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1278. /* L */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1279. /* M */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1280. /* N */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1281. /* O */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1282. /* P */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1283. /* Q */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1284. /* R */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1285. /* S */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1286. /* T */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1287. /* U */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1288. /* V */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1289. /* W */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1290. /* X */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1291. /* Y */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1292. /* Z */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1293. /* [ */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1294. /* \ */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1295. /* ] */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1296. /* ^ */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1297. /* _ */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1298. /* ` */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1299. /* a */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER | WEBDAV_CTYPE_XALPHA,
  1300. /* b */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER | WEBDAV_CTYPE_XALPHA,
  1301. /* c */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER | WEBDAV_CTYPE_XALPHA,
  1302. /* d */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER | WEBDAV_CTYPE_XALPHA,
  1303. /* e */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER | WEBDAV_CTYPE_XALPHA,
  1304. /* f */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER | WEBDAV_CTYPE_XALPHA,
  1305. /* g */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1306. /* h */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1307. /* i */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1308. /* j */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1309. /* k */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1310. /* l */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1311. /* m */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1312. /* n */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1313. /* o */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1314. /* p */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1315. /* q */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1316. /* r */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1317. /* s */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1318. /* t */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1319. /* u */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1320. /* v */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1321. /* w */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1322. /* x */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1323. /* y */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1324. /* z */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1325. /* { */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1326. /* | */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1327. /* } */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1328. /* ~ */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1329. /* del */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1330. /* x80 */ WEBDAV_CTYPE_UTF8CONT,
  1331. /* x81 */ WEBDAV_CTYPE_UTF8CONT,
  1332. /* x82 */ WEBDAV_CTYPE_UTF8CONT,
  1333. /* x83 */ WEBDAV_CTYPE_UTF8CONT,
  1334. /* x84 */ WEBDAV_CTYPE_UTF8CONT,
  1335. /* x85 */ WEBDAV_CTYPE_UTF8CONT,
  1336. /* x86 */ WEBDAV_CTYPE_UTF8CONT,
  1337. /* x87 */ WEBDAV_CTYPE_UTF8CONT,
  1338. /* x88 */ WEBDAV_CTYPE_UTF8CONT,
  1339. /* x89 */ WEBDAV_CTYPE_UTF8CONT,
  1340. /* x8a */ WEBDAV_CTYPE_UTF8CONT,
  1341. /* x8b */ WEBDAV_CTYPE_UTF8CONT,
  1342. /* x8c */ WEBDAV_CTYPE_UTF8CONT,
  1343. /* x8d */ WEBDAV_CTYPE_UTF8CONT,
  1344. /* x8e */ WEBDAV_CTYPE_UTF8CONT,
  1345. /* x8f */ WEBDAV_CTYPE_UTF8CONT,
  1346. /* x90 */ WEBDAV_CTYPE_UTF8CONT,
  1347. /* x91 */ WEBDAV_CTYPE_UTF8CONT,
  1348. /* x92 */ WEBDAV_CTYPE_UTF8CONT,
  1349. /* x93 */ WEBDAV_CTYPE_UTF8CONT,
  1350. /* x94 */ WEBDAV_CTYPE_UTF8CONT,
  1351. /* x95 */ WEBDAV_CTYPE_UTF8CONT,
  1352. /* x96 */ WEBDAV_CTYPE_UTF8CONT,
  1353. /* x97 */ WEBDAV_CTYPE_UTF8CONT,
  1354. /* x98 */ WEBDAV_CTYPE_UTF8CONT,
  1355. /* x99 */ WEBDAV_CTYPE_UTF8CONT,
  1356. /* x9a */ WEBDAV_CTYPE_UTF8CONT,
  1357. /* x9b */ WEBDAV_CTYPE_UTF8CONT,
  1358. /* x9c */ WEBDAV_CTYPE_UTF8CONT,
  1359. /* x9d */ WEBDAV_CTYPE_UTF8CONT,
  1360. /* x9e */ WEBDAV_CTYPE_UTF8CONT,
  1361. /* x9f */ WEBDAV_CTYPE_UTF8CONT,
  1362. /* xa0 */ WEBDAV_CTYPE_UTF8CONT,
  1363. /* xa1 */ WEBDAV_CTYPE_UTF8CONT,
  1364. /* xa2 */ WEBDAV_CTYPE_UTF8CONT,
  1365. /* xa3 */ WEBDAV_CTYPE_UTF8CONT,
  1366. /* xa4 */ WEBDAV_CTYPE_UTF8CONT,
  1367. /* xa5 */ WEBDAV_CTYPE_UTF8CONT,
  1368. /* xa6 */ WEBDAV_CTYPE_UTF8CONT,
  1369. /* xa7 */ WEBDAV_CTYPE_UTF8CONT,
  1370. /* xa8 */ WEBDAV_CTYPE_UTF8CONT,
  1371. /* xa9 */ WEBDAV_CTYPE_UTF8CONT,
  1372. /* xaa */ WEBDAV_CTYPE_UTF8CONT,
  1373. /* xab */ WEBDAV_CTYPE_UTF8CONT,
  1374. /* xac */ WEBDAV_CTYPE_UTF8CONT,
  1375. /* xad */ WEBDAV_CTYPE_UTF8CONT,
  1376. /* xae */ WEBDAV_CTYPE_UTF8CONT,
  1377. /* xaf */ WEBDAV_CTYPE_UTF8CONT,
  1378. /* xb0 */ WEBDAV_CTYPE_UTF8CONT,
  1379. /* xb1 */ WEBDAV_CTYPE_UTF8CONT,
  1380. /* xb2 */ WEBDAV_CTYPE_UTF8CONT,
  1381. /* xb3 */ WEBDAV_CTYPE_UTF8CONT,
  1382. /* xb4 */ WEBDAV_CTYPE_UTF8CONT,
  1383. /* xb5 */ WEBDAV_CTYPE_UTF8CONT,
  1384. /* xb6 */ WEBDAV_CTYPE_UTF8CONT,
  1385. /* xb7 */ WEBDAV_CTYPE_UTF8CONT,
  1386. /* xb8 */ WEBDAV_CTYPE_UTF8CONT,
  1387. /* xb9 */ WEBDAV_CTYPE_UTF8CONT,
  1388. /* xba */ WEBDAV_CTYPE_UTF8CONT,
  1389. /* xbb */ WEBDAV_CTYPE_UTF8CONT,
  1390. /* xbc */ WEBDAV_CTYPE_UTF8CONT,
  1391. /* xbd */ WEBDAV_CTYPE_UTF8CONT,
  1392. /* xbe */ WEBDAV_CTYPE_UTF8CONT,
  1393. /* xbf */ WEBDAV_CTYPE_UTF8CONT,
  1394. /* xc0 */ 0,
  1395. /* xc1 */ WEBDAV_CTYPE_UTF8LEAD,
  1396. /* xc2 */ WEBDAV_CTYPE_UTF8LEAD,
  1397. /* xc3 */ WEBDAV_CTYPE_UTF8LEAD,
  1398. /* xc4 */ WEBDAV_CTYPE_UTF8LEAD,
  1399. /* xc5 */ WEBDAV_CTYPE_UTF8LEAD,
  1400. /* xc6 */ WEBDAV_CTYPE_UTF8LEAD,
  1401. /* xc7 */ WEBDAV_CTYPE_UTF8LEAD,
  1402. /* xc8 */ WEBDAV_CTYPE_UTF8LEAD,
  1403. /* xc9 */ WEBDAV_CTYPE_UTF8LEAD,
  1404. /* xca */ WEBDAV_CTYPE_UTF8LEAD,
  1405. /* xcb */ WEBDAV_CTYPE_UTF8LEAD,
  1406. /* xcc */ WEBDAV_CTYPE_UTF8LEAD,
  1407. /* xcd */ WEBDAV_CTYPE_UTF8LEAD,
  1408. /* xce */ WEBDAV_CTYPE_UTF8LEAD,
  1409. /* xcf */ WEBDAV_CTYPE_UTF8LEAD,
  1410. /* xd0 */ WEBDAV_CTYPE_UTF8LEAD,
  1411. /* xd1 */ WEBDAV_CTYPE_UTF8LEAD,
  1412. /* xd2 */ WEBDAV_CTYPE_UTF8LEAD,
  1413. /* xd3 */ WEBDAV_CTYPE_UTF8LEAD,
  1414. /* xd4 */ WEBDAV_CTYPE_UTF8LEAD,
  1415. /* xd5 */ WEBDAV_CTYPE_UTF8LEAD,
  1416. /* xd6 */ WEBDAV_CTYPE_UTF8LEAD,
  1417. /* xd7 */ WEBDAV_CTYPE_UTF8LEAD,
  1418. /* xd8 */ WEBDAV_CTYPE_UTF8LEAD,
  1419. /* xd9 */ WEBDAV_CTYPE_UTF8LEAD,
  1420. /* xda */ WEBDAV_CTYPE_UTF8LEAD,
  1421. /* xdb */ WEBDAV_CTYPE_UTF8LEAD,
  1422. /* xdc */ WEBDAV_CTYPE_UTF8LEAD,
  1423. /* xdd */ WEBDAV_CTYPE_UTF8LEAD,
  1424. /* xde */ WEBDAV_CTYPE_UTF8LEAD,
  1425. /* xdf */ WEBDAV_CTYPE_UTF8LEAD,
  1426. /* xe0 */ 0,
  1427. /* xe1 */ WEBDAV_CTYPE_UTF8LEAD,
  1428. /* xe2 */ WEBDAV_CTYPE_UTF8LEAD,
  1429. /* xe3 */ WEBDAV_CTYPE_UTF8LEAD,
  1430. /* xe4 */ WEBDAV_CTYPE_UTF8LEAD,
  1431. /* xe5 */ WEBDAV_CTYPE_UTF8LEAD,
  1432. /* xe6 */ WEBDAV_CTYPE_UTF8LEAD,
  1433. /* xe7 */ WEBDAV_CTYPE_UTF8LEAD,
  1434. /* xe8 */ WEBDAV_CTYPE_UTF8LEAD,
  1435. /* xe9 */ WEBDAV_CTYPE_UTF8LEAD,
  1436. /* xea */ WEBDAV_CTYPE_UTF8LEAD,
  1437. /* xeb */ WEBDAV_CTYPE_UTF8LEAD,
  1438. /* xec */ WEBDAV_CTYPE_UTF8LEAD,
  1439. /* xed */ WEBDAV_CTYPE_UTF8LEAD,
  1440. /* xee */ WEBDAV_CTYPE_UTF8LEAD,
  1441. /* xef */ WEBDAV_CTYPE_UTF8LEAD,
  1442. /* xf0 */ 0,
  1443. /* xf1 */ WEBDAV_CTYPE_UTF8LEAD,
  1444. /* xf2 */ WEBDAV_CTYPE_UTF8LEAD,
  1445. /* xf3 */ WEBDAV_CTYPE_UTF8LEAD,
  1446. /* xf4 */ WEBDAV_CTYPE_UTF8LEAD,
  1447. /* xf5 */ WEBDAV_CTYPE_UTF8LEAD,
  1448. /* xf6 */ WEBDAV_CTYPE_UTF8LEAD,
  1449. /* xf7 */ WEBDAV_CTYPE_UTF8LEAD,
  1450. /* xf8 */ 0,
  1451. /* xf9 */ WEBDAV_CTYPE_UTF8LEAD,
  1452. /* xfa */ WEBDAV_CTYPE_UTF8LEAD,
  1453. /* xfb */ WEBDAV_CTYPE_UTF8LEAD,
  1454. /* xfc */ 0,
  1455. /* xfd */ WEBDAV_CTYPE_UTF8LEAD,
  1456. /* xfe */ 0,
  1457. /* xff */ 0
  1458. };
  1459. const apr_uint32_t * const ctype_table = ctype_table_internal;
  1460. static const unsigned char casefold_table[256] =
  1461. {
  1462. // Identity, except {97:122} => {65:90}
  1463. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
  1464. 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
  1465. 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
  1466. 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
  1467. 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
  1468. 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
  1469. 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
  1470. 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,123,124,125,126,127,
  1471. 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
  1472. 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
  1473. 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
  1474. 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
  1475. 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
  1476. 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
  1477. 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
  1478. 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
  1479. };
  1480. static int
  1481. ctype_casecmp(int a, int b)
  1482. {
  1483. const int A = casefold_table[(unsigned char)a];
  1484. const int B = casefold_table[(unsigned char)b];
  1485. return A - B;
  1486. }
  1487. //------------------------------------------------------------------------------
  1488. // from svn_pool.c
  1489. // Pool allocation handler which just aborts, since we aren't generally
  1490. // prepared to deal with out-of-memory errors.
  1491. static int
  1492. abort_on_pool_failure(int retcode)
  1493. {
  1494. // Don't translate this string! It requires memory allocation to do so!
  1495. // And we don't have any of it...
  1496. printf("Out of memory - terminating application.\n");
  1497. abort();
  1498. }
  1499. static apr_pool_t *
  1500. pool_create_ex(
  1501. apr_pool_t * parent_pool,
  1502. apr_allocator_t * allocator)
  1503. {
  1504. apr_pool_t * pool;
  1505. apr_pool_create_ex(&pool, parent_pool, abort_on_pool_failure, allocator);
  1506. return pool;
  1507. }
  1508. //------------------------------------------------------------------------------
  1509. // from time.c
  1510. #define OLD_TIMESTAMP_FORMAT \
  1511. "%3s %d %3s %d %02d:%02d:%02d.%06d (day %03d, dst %d, gmt_off %06d)"
  1512. static apr_size_t
  1513. find_matching_string(
  1514. char * str,
  1515. apr_size_t size,
  1516. const char strings[][4])
  1517. {
  1518. for (apr_size_t i = 0; i < size; i++)
  1519. if (strings[i] && (strcmp(str, strings[i]) == 0))
  1520. return i;
  1521. return (apr_size_t)-1;
  1522. }
  1523. static error_t
  1524. time_from_cstring(
  1525. apr_time_t * when,
  1526. const char * data,
  1527. apr_pool_t * pool)
  1528. {
  1529. apr_time_exp_t exploded_time;
  1530. apr_status_t apr_err = 0;
  1531. char wday[4] = {0}, month[4] = {0};
  1532. char * c = NULL;
  1533. // Open-code parsing of the new timestamp format, as this
  1534. // is a hot path for reading the entries file. This format looks
  1535. // like: "2001-08-31T04:24:14.966996Z"
  1536. exploded_time.tm_year = strtol(data, &c, 10);
  1537. if (*c++ != '-') goto fail;
  1538. exploded_time.tm_mon = strtol(c, &c, 10);
  1539. if (*c++ != '-') goto fail;
  1540. exploded_time.tm_mday = strtol(c, &c, 10);
  1541. if (*c++ != 'T') goto fail;
  1542. exploded_time.tm_hour = strtol(c, &c, 10);
  1543. if (*c++ != ':') goto fail;
  1544. exploded_time.tm_min = strtol(c, &c, 10);
  1545. if (*c++ != ':') goto fail;
  1546. exploded_time.tm_sec = strtol(c, &c, 10);
  1547. if (*c != 'Z')
  1548. {
  1549. if (*c++ != '.') goto fail;
  1550. exploded_time.tm_usec = strtol(c, &c, 10);
  1551. if (*c++ != 'Z') goto fail;
  1552. }
  1553. exploded_time.tm_year -= 1900;
  1554. exploded_time.tm_mon -= 1;
  1555. exploded_time.tm_wday = 0;
  1556. exploded_time.tm_yday = 0;
  1557. exploded_time.tm_isdst = 0;
  1558. exploded_time.tm_gmtoff = 0;
  1559. apr_err = apr_time_exp_gmt_get(when, &exploded_time);
  1560. if (apr_err == APR_SUCCESS)
  1561. return WEBDAV_NO_ERROR;
  1562. return error_createf(WEBDAV_ERR_BAD_DATE, NULL, "error parsing date: %s", data);
  1563. fail:
  1564. // 2012-09-11T14:18:40+07:00
  1565. char gmt_shift = 0;
  1566. int gmt_hour = 0;
  1567. int gmt_min = 0;
  1568. if (sscanf(data,
  1569. "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
  1570. &exploded_time.tm_year,
  1571. &exploded_time.tm_mon,
  1572. &exploded_time.tm_mday,
  1573. &exploded_time.tm_hour,
  1574. &exploded_time.tm_min,
  1575. &exploded_time.tm_sec,
  1576. &gmt_shift,
  1577. &gmt_hour,
  1578. &gmt_min) == 9)
  1579. {
  1580. exploded_time.tm_year -= 1900;
  1581. exploded_time.tm_mon -= 1;
  1582. exploded_time.tm_wday = 0;
  1583. exploded_time.tm_yday = 0;
  1584. exploded_time.tm_isdst = 0;
  1585. exploded_time.tm_gmtoff = (gmt_shift == '-' ? -1 : 1) * gmt_hour * SecsPerHour + gmt_min * SecsPerMin;
  1586. exploded_time.tm_usec = 0;
  1587. apr_err = apr_time_exp_gmt_get(when, &exploded_time);
  1588. if (apr_err != APR_SUCCESS)
  1589. return error_createf(WEBDAV_ERR_BAD_DATE, NULL, "error parsing date: %s", data);
  1590. return WEBDAV_NO_ERROR;
  1591. }
  1592. // 2012-09-11T03:56:20
  1593. if (sscanf(data,
  1594. "%04d-%02d-%02dT%02d:%02d:%02d",
  1595. &exploded_time.tm_year,
  1596. &exploded_time.tm_mon,
  1597. &exploded_time.tm_mday,
  1598. &exploded_time.tm_hour,
  1599. &exploded_time.tm_min,
  1600. &exploded_time.tm_sec) == 6)
  1601. {
  1602. exploded_time.tm_year -= 1900;
  1603. exploded_time.tm_mon -= 1;
  1604. exploded_time.tm_wday = 0;
  1605. exploded_time.tm_yday = 0;
  1606. exploded_time.tm_isdst = 0;
  1607. exploded_time.tm_gmtoff = 0;
  1608. exploded_time.tm_usec = 0;
  1609. apr_err = apr_time_exp_gmt_get(when, &exploded_time);
  1610. if (apr_err != APR_SUCCESS)
  1611. return error_createf(WEBDAV_ERR_BAD_DATE, NULL, "error parsing date: %s", data);
  1612. return WEBDAV_NO_ERROR;
  1613. }
  1614. // Try the compatibility option. This does not need to be fast,
  1615. // as this format is no longer generated and the client will convert
  1616. // an old-format entries file the first time it reads it.
  1617. if (sscanf(data,
  1618. OLD_TIMESTAMP_FORMAT,
  1619. wday,
  1620. &exploded_time.tm_mday,
  1621. month,
  1622. &exploded_time.tm_year,
  1623. &exploded_time.tm_hour,
  1624. &exploded_time.tm_min,
  1625. &exploded_time.tm_sec,
  1626. &exploded_time.tm_usec,
  1627. &exploded_time.tm_yday,
  1628. &exploded_time.tm_isdst,
  1629. &exploded_time.tm_gmtoff) == 11)
  1630. {
  1631. exploded_time.tm_year -= 1900;
  1632. exploded_time.tm_yday -= 1;
  1633. // Using hard coded limits for the arrays - they are going away
  1634. // soon in any case.
  1635. exploded_time.tm_wday = (apr_int32_t)find_matching_string(wday, 7, apr_day_snames);
  1636. exploded_time.tm_mon = (apr_int32_t)find_matching_string(month, 12, apr_month_snames);
  1637. apr_err = apr_time_exp_gmt_get(when, &exploded_time);
  1638. if (apr_err != APR_SUCCESS)
  1639. return error_createf(WEBDAV_ERR_BAD_DATE, NULL, "error parsing date: %s", data);
  1640. return WEBDAV_NO_ERROR;
  1641. }
  1642. // Timestamp is something we do not recognize.
  1643. // return error_createf(WEBDAV_ERR_BAD_DATE, NULL, "error parsing date: %s", data);
  1644. *when = apr_time_now();
  1645. return WEBDAV_NO_ERROR;
  1646. }
  1647. //------------------------------------------------------------------------------
  1648. // from path.c
  1649. // TRUE if s is the canonical empty path, FALSE otherwise
  1650. #define WEBDAV_PATH_IS_EMPTY(s) ((s)[0] == '\0')
  1651. // TRUE if s,n is the platform's empty path ("."), FALSE otherwise. Can
  1652. // this be changed? Well, the path library will work, not so sure about
  1653. // the OS!
  1654. #define WEBDAV_PATH_IS_PLATFORM_EMPTY(s,n) ((n) == 1 && (s)[0] == '.')
  1655. /* Here is the BNF for path components in a URI. "pchar" is a
  1656. character in a path component.
  1657. pchar = unreserved | escaped |
  1658. ":" | "@" | "&" | "=" | "+" | "$" | ","
  1659. unreserved = alphanum | mark
  1660. mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
  1661. Note that "escaped" doesn't really apply to what users can put in
  1662. their paths, so that really means the set of characters is:
  1663. alphanum | mark | ":" | "@" | "&" | "=" | "+" | "$" | ","
  1664. */
  1665. static const char uri_char_validity[256] =
  1666. {
  1667. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1668. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1669. 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  1670. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0,
  1671. // 64
  1672. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  1673. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
  1674. 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  1675. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0,
  1676. // 128
  1677. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1678. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1679. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1680. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1681. // 192
  1682. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1683. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1684. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1685. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1686. };
  1687. // URI-encode each character c in PATH for which TABLE[c] is 0.
  1688. // If no encoding was needed, return PATH, else return a new string allocated
  1689. // in POOL.
  1690. static const char *
  1691. uri_escape(
  1692. const char * path,
  1693. const char table[],
  1694. apr_pool_t * pool)
  1695. {
  1696. stringbuf_t * retstr = NULL;
  1697. size_t i = 0, copied = 0;
  1698. int c = 0;
  1699. retstr = stringbuf_create_ensure(strlen(path), pool);
  1700. for (i = 0; path[i]; i++)
  1701. {
  1702. c = (unsigned char)path[i];
  1703. if (table[c])
  1704. continue;
  1705. // If we got here, we're looking at a character that isn't
  1706. // supported by the (or at least, our) URI encoding scheme. We
  1707. // need to escape this character.
  1708. // First things first, copy all the good stuff that we haven't
  1709. // yet copied into our output buffer.
  1710. if (i - copied)
  1711. stringbuf_appendbytes(retstr, path + copied,
  1712. i - copied);
  1713. // Now, write in our escaped character, consisting of the
  1714. // '%' and two digits. We cast the C to unsigned char here because
  1715. // the 'X' format character will be tempted to treat it as an unsigned
  1716. // int...which causes problem when messing with 0x80-0xFF chars.
  1717. // We also need space for a null as apr_snprintf will write one.
  1718. stringbuf_ensure(retstr, retstr->len + 4);
  1719. apr_snprintf(retstr->data + retstr->len, 4, "%%%02X", (unsigned char)c);
  1720. retstr->len += 3;
  1721. // Finally, update our copy counter.
  1722. copied = i + 1;
  1723. }
  1724. // If we didn't encode anything, we don't need to duplicate the string.
  1725. if (retstr->len == 0)
  1726. return path;
  1727. // Anything left to copy?
  1728. if (i - copied)
  1729. stringbuf_appendbytes(retstr, path + copied, i - copied);
  1730. // retstr is null-terminated either by apr_snprintf or the stringbuf
  1731. // functions.
  1732. return retstr->data;
  1733. }
  1734. static const char *
  1735. path_uri_decode(
  1736. const char * path,
  1737. apr_pool_t * pool)
  1738. {
  1739. stringbuf_t * retstr = NULL;
  1740. size_t i = 0;
  1741. bool query_start = FALSE;
  1742. // avoid repeated realloc
  1743. retstr = stringbuf_create_ensure(strlen(path) + 1, pool);
  1744. retstr->len = 0;
  1745. for (i = 0; path[i]; i++)
  1746. {
  1747. char c = path[i];
  1748. if (c == '?')
  1749. {
  1750. // Mark the start of the query string, if it exists.
  1751. query_start = TRUE;
  1752. }
  1753. else if (c == '+' && query_start)
  1754. {
  1755. // Only do this if we are into the query string.
  1756. // RFC 2396, section 3.3
  1757. c = ' ';
  1758. }
  1759. else if (c == '%' && ctype_isxdigit(path[i + 1]) && ctype_isxdigit(path[i+2]))
  1760. {
  1761. char digitz[3];
  1762. digitz[0] = path[++i];
  1763. digitz[1] = path[++i];
  1764. digitz[2] = '\0';
  1765. c = (char)(strtol(digitz, NULL, 16));
  1766. }
  1767. retstr->data[retstr->len++] = c;
  1768. }
  1769. // Null-terminate this bad-boy.
  1770. retstr->data[retstr->len] = 0;
  1771. return retstr->data;
  1772. }
  1773. static const char *
  1774. path_uri_encode(
  1775. const char * path,
  1776. apr_pool_t * pool)
  1777. {
  1778. const char * ret = uri_escape(path, uri_char_validity, pool);
  1779. // Our interface guarantees a copy.
  1780. if (ret == path)
  1781. return apr_pstrdup(pool, path);
  1782. else
  1783. return ret;
  1784. }
  1785. static char *
  1786. path_join(
  1787. const char * base,
  1788. const char * component,
  1789. apr_pool_t * pool)
  1790. {
  1791. apr_size_t blen = strlen(base);
  1792. apr_size_t clen = strlen(component);
  1793. char * path = NULL;
  1794. // assert(path_is_canonical(base, pool));
  1795. // assert(path_is_canonical(component, pool));
  1796. // If the component is absolute, then return it.
  1797. if (*component == '/')
  1798. return (char *)apr_pmemdup(pool, component, clen + 1);
  1799. // If either is empty return the other
  1800. if (WEBDAV_PATH_IS_EMPTY(base))
  1801. return (char *)apr_pmemdup(pool, component, clen + 1);
  1802. if (WEBDAV_PATH_IS_EMPTY(component))
  1803. return (char *)apr_pmemdup(pool, base, blen + 1);
  1804. if ((blen == 1) && (base[0] == '/'))
  1805. blen = 0; // Ignore base, just return separator + component
  1806. // Construct the new, combined path.
  1807. path = (char *)apr_pcalloc(pool, blen + 1 + clen + 1);
  1808. memcpy(path, base, blen);
  1809. path[blen] = '/';
  1810. memcpy(path + blen + 1, component, clen + 1);
  1811. return path;
  1812. }
  1813. static const char *
  1814. path_url_add_component2(
  1815. const char * url,
  1816. const char * component,
  1817. apr_pool_t * pool)
  1818. {
  1819. // = path_uri_encode() but without always copying
  1820. component = uri_escape(component, uri_char_validity, pool);
  1821. return path_join(url, component, pool);
  1822. }
  1823. // Get APR's internal path encoding.
  1824. static error_t
  1825. get_path_encoding(
  1826. bool * path_is_utf8,
  1827. apr_pool_t * pool)
  1828. {
  1829. apr_status_t apr_err = 0;
  1830. int encoding_style = 0;
  1831. apr_err = apr_filepath_encoding(&encoding_style, pool);
  1832. if (apr_err)
  1833. return error_wrap_apr(apr_err,
  1834. "Can't determine the native path encoding");
  1835. // What to do about APR_FILEPATH_ENCODING_UNKNOWN?
  1836. // Well, for now we'll just punt to the utf_ functions;
  1837. // those will at least do the ASCII-subset check.
  1838. *path_is_utf8 = (encoding_style == APR_FILEPATH_ENCODING_UTF8);
  1839. return WEBDAV_NO_ERROR;
  1840. }
  1841. static error_t
  1842. path_cstring_to_utf8(
  1843. const char ** path_utf8,
  1844. const char * path_apr,
  1845. apr_pool_t * pool)
  1846. {
  1847. bool path_is_utf8 = FALSE;
  1848. WEBDAV_ERR(get_path_encoding(&path_is_utf8, pool));
  1849. if (path_is_utf8)
  1850. {
  1851. *path_utf8 = apr_pstrdup(pool, path_apr);
  1852. return WEBDAV_NO_ERROR;
  1853. }
  1854. else
  1855. return utf_cstring_to_utf8(path_utf8, path_apr, pool);
  1856. }
  1857. static apr_size_t
  1858. path_component_count(
  1859. const char * path)
  1860. {
  1861. if (!path) return 0;
  1862. apr_size_t count = 0;
  1863. while (*path)
  1864. {
  1865. const char * start;
  1866. while (*path == '/')
  1867. ++path;
  1868. start = path;
  1869. while (*path && (*path != '/'))
  1870. ++path;
  1871. if (path != start)
  1872. ++count;
  1873. }
  1874. return count;
  1875. }
  1876. // Return the length of substring necessary to encompass the entire
  1877. // previous path segment in PATH, which should be a LEN byte string.
  1878. // A trailing slash will not be included in the returned length except
  1879. // in the case in which PATH is absolute and there are no more
  1880. // previous segments.
  1881. static apr_size_t
  1882. previous_segment(
  1883. const char * path,
  1884. apr_size_t len)
  1885. {
  1886. if (len == 0)
  1887. return 0;
  1888. while ((len > 0) && (path[--len] != '/'))
  1889. ;
  1890. if ((len == 0) && (path[0] == '/'))
  1891. return 1;
  1892. else
  1893. return len;
  1894. }
  1895. static void
  1896. path_remove_component(
  1897. stringbuf_t * path)
  1898. {
  1899. path->len = previous_segment(path->data, path->len);
  1900. path->data[path->len] = '\0';
  1901. }
  1902. static void
  1903. path_remove_components(
  1904. stringbuf_t * path,
  1905. apr_size_t n)
  1906. {
  1907. while (n > 0)
  1908. {
  1909. path_remove_component(path);
  1910. n--;
  1911. }
  1912. }
  1913. static error_t
  1914. path_cstring_from_utf8(
  1915. const char ** path_apr,
  1916. const char * path_utf8,
  1917. apr_pool_t * pool)
  1918. {
  1919. bool path_is_utf8 = FALSE;
  1920. WEBDAV_ERR(get_path_encoding(&path_is_utf8, pool));
  1921. if (path_is_utf8)
  1922. {
  1923. *path_apr = apr_pstrdup(pool, path_utf8);
  1924. return WEBDAV_NO_ERROR;
  1925. }
  1926. else
  1927. return utf_cstring_from_utf8(path_apr, path_utf8, pool);
  1928. }
  1929. static bool
  1930. path_is_backpath_present(
  1931. const char * path)
  1932. {
  1933. size_t len;
  1934. // 0 and 1-length paths do not have a backpath
  1935. if ((path[0] == '\0') || (path[1] == '\0'))
  1936. return FALSE;
  1937. // Handle ".." or a leading "../"
  1938. if ((path[0] == '.') && (path[1] == '.') && ((path[2] == '\0') || (path[2] == '/')))
  1939. return TRUE;
  1940. // Paths of length 2 (at this point) have no backpath present.
  1941. if (path[2] == '\0')
  1942. return FALSE;
  1943. // If any segment is "..", then a backpath is present.
  1944. if (strstr(path, "/../") != NULL)
  1945. return TRUE;
  1946. // Does the path end in "/.." ?
  1947. len = strlen(path);
  1948. return (path[len - 3] == '/') && (path[len - 2] == '.') && (path[len - 1] == '.');
  1949. }
  1950. //------------------------------------------------------------------------------
  1951. // from svn_client.h
  1952. typedef error_t (*client_list_func_t)(
  1953. void * baton,
  1954. const char * path,
  1955. const dirent_t * dirent,
  1956. const char * abs_path,
  1957. apr_pool_t * pool);
  1958. typedef struct client_ctx_t
  1959. {
  1960. auth_baton_t * auth_baton;
  1961. cancel_func_t cancel_func;
  1962. void * cancel_baton;
  1963. progress_notify_func_t progress_func;
  1964. void * progress_baton;
  1965. const char * client_name;
  1966. } client_ctx_t;
  1967. //------------------------------------------------------------------------------
  1968. // from win32_xlate.c
  1969. static apr_status_t
  1970. subr_win32_xlate_to_stringbuf(// win32_xlate_t *handle,
  1971. const char * src_data,
  1972. apr_size_t src_length,
  1973. stringbuf_t ** dest,
  1974. apr_pool_t * pool)
  1975. {
  1976. WCHAR * wide_str = NULL;
  1977. int retval = 0, wide_size = 0;
  1978. if (src_length == 0)
  1979. {
  1980. *dest = stringbuf_create("", pool);
  1981. return APR_SUCCESS;
  1982. }
  1983. int from_page_id = CP_ACP;
  1984. retval = MultiByteToWideChar(from_page_id, // CP_UTF8, // handle->from_page_id,
  1985. 0, src_data, (int)src_length, NULL, 0);
  1986. if (retval == 0)
  1987. return apr_get_os_error();
  1988. wide_size = retval;
  1989. // Allocate temporary buffer for small strings on stack instead of heap.
  1990. if (wide_size <= MAX_PATH)
  1991. {
  1992. wide_str = static_cast<WCHAR *>(alloca(wide_size * sizeof(WCHAR)));
  1993. }
  1994. else
  1995. {
  1996. wide_str = static_cast<WCHAR *>(apr_pcalloc(pool, wide_size * sizeof(WCHAR)));
  1997. }
  1998. retval = MultiByteToWideChar(from_page_id, // handle->from_page_id,
  1999. 0, src_data, (int)src_length, wide_str, wide_size);
  2000. if (retval == 0)
  2001. return apr_get_os_error();
  2002. int to_page_id = CP_UTF8;
  2003. retval = WideCharToMultiByte(to_page_id, // handle->to_page_id,
  2004. 0, wide_str, wide_size, NULL, 0, NULL, NULL);
  2005. if (retval == 0)
  2006. return apr_get_os_error();
  2007. // Ensure that buffer is enough to hold result string and termination
  2008. // character.
  2009. *dest = stringbuf_create_ensure(retval + 1, pool);
  2010. (*dest)->len = retval;
  2011. retval = WideCharToMultiByte(to_page_id, // handle->to_page_id,
  2012. 0, wide_str, wide_size, (*dest)->data, (int)(*dest)->len, NULL, NULL);
  2013. if (retval == 0)
  2014. return apr_get_os_error();
  2015. (*dest)->len = retval;
  2016. return APR_SUCCESS;
  2017. }
  2018. static apr_status_t
  2019. utf8_to_unicode(
  2020. WCHAR ** retstr,
  2021. const char * srcstr,
  2022. apr_pool_t * pool)
  2023. {
  2024. /*apr_size_t retlen = 0;
  2025. apr_size_t srcremains = strlen(srcstr) + 1;
  2026. *retstr = static_cast<WCHAR *>(apr_pcalloc(pool, srcremains * 4));
  2027. apr_status_t rv;
  2028. if (rv = apr_conv_utf8_to_ucs2(srcstr, &srcremains, *retstr, &retlen)) {
  2029. return (rv == APR_INCOMPLETE) ? APR_EINVAL : rv;
  2030. }
  2031. if (srcremains) {
  2032. return APR_ENAMETOOLONG;
  2033. }*/
  2034. WCHAR * wide_str = NULL;
  2035. int retval = 0, wide_size = 0;
  2036. apr_size_t src_length = strlen(srcstr);
  2037. if (src_length == 0)
  2038. {
  2039. *retstr = L"";
  2040. return APR_SUCCESS;
  2041. }
  2042. retval = MultiByteToWideChar(CP_UTF8, // handle->from_page_id,
  2043. 0, srcstr, (int)src_length, NULL, 0);
  2044. if (retval == 0)
  2045. return apr_get_os_error();
  2046. wide_size = retval;
  2047. wide_str = static_cast<WCHAR *>(apr_pcalloc(pool, (wide_size + 1) * sizeof(WCHAR)));
  2048. retval = MultiByteToWideChar(CP_UTF8, // handle->from_page_id,
  2049. 0, srcstr, (int)src_length, wide_str, wide_size);
  2050. if (retval == 0)
  2051. return apr_get_os_error();
  2052. *retstr = wide_str;
  2053. (*retstr)[wide_size] = L'\0';
  2054. return APR_SUCCESS;
  2055. }
  2056. //------------------------------------------------------------------------------
  2057. // from utf.c
  2058. // Verify that the sequence DATA of length LEN is valid UTF-8.
  2059. // If it is not, return an error with code APR_EINVAL.
  2060. static error_t
  2061. check_utf8(
  2062. const char * data,
  2063. apr_size_t len,
  2064. apr_pool_t * pool)
  2065. {
  2066. // TODO: if (!utf_is_valid(data, len)))
  2067. // return invalid_utf8(data, len, pool);
  2068. return WEBDAV_NO_ERROR;
  2069. }
  2070. // Convert SRC_LENGTH bytes of SRC_DATA in NODE->handle, store the result
  2071. // in *DEST, which is allocated in POOL.
  2072. static error_t
  2073. convert_to_stringbuf(// xlate_handle_node_t *node,
  2074. const char * src_data,
  2075. apr_size_t src_length,
  2076. stringbuf_t ** dest,
  2077. apr_pool_t * pool)
  2078. {
  2079. apr_status_t apr_err = 0;
  2080. apr_err = subr_win32_xlate_to_stringbuf(// (win32_xlate_t *) node->handle,
  2081. src_data, src_length,
  2082. dest, pool);
  2083. // If we exited the loop with an error, return the error.
  2084. if (apr_err)
  2085. {
  2086. const char * errstr = NULL;
  2087. error_t err = 0;
  2088. // Can't use error_wrap_apr here because it calls functions in
  2089. // this file, leading to infinite recursion.
  2090. errstr = apr_psprintf(pool, "Can't convert string"); // from native encoding to '%s':"),
  2091. err = error_create(apr_err, NULL, "");
  2092. return error_create(apr_err, &err, errstr);
  2093. }
  2094. // Else, exited due to success. Trim the result buffer down to the
  2095. // right length.
  2096. (*dest)->data[(*dest)->len] = '\0';
  2097. return WEBDAV_NO_ERROR;
  2098. }
  2099. // Common implementation for utf_cstring_to_utf8,
  2100. // utf_cstring_to_utf8_ex, utf_cstring_from_utf8 and
  2101. // utf_cstring_from_utf8_ex. Convert SRC to DEST using NODE->handle as
  2102. // the translator and allocating from POOL.
  2103. static error_t
  2104. convert_cstring(
  2105. const char ** dest,
  2106. const char * src,
  2107. apr_pool_t * pool)
  2108. {
  2109. stringbuf_t * destbuf;
  2110. WEBDAV_ERR(convert_to_stringbuf(// node,
  2111. src, strlen(src), &destbuf, pool));
  2112. *dest = destbuf->data;
  2113. return WEBDAV_NO_ERROR;
  2114. }
  2115. // Verify that the NULL terminated sequence DATA is valid UTF-8.
  2116. // If it is not, return an error with code APR_EINVAL.
  2117. static error_t
  2118. check_cstring_utf8(
  2119. const char * data,
  2120. apr_pool_t * pool)
  2121. {
  2122. // TODO: if (!utf_cstring_is_valid(data))
  2123. // return invalid_utf8(data, strlen(data), pool);
  2124. return WEBDAV_NO_ERROR;
  2125. }
  2126. static error_t
  2127. utf_cstring_to_utf8(
  2128. const char ** dest,
  2129. const char * src,
  2130. apr_pool_t * pool)
  2131. {
  2132. // TODO: implement
  2133. error_t err = convert_cstring(dest, src, // node,
  2134. pool);
  2135. WEBDAV_ERR(err);
  2136. return check_cstring_utf8(*dest, pool);
  2137. }
  2138. static error_t
  2139. utf_cstring_from_utf8(
  2140. const char ** dest,
  2141. const char * src,
  2142. apr_pool_t * pool)
  2143. {
  2144. WEBDAV_ERR(check_utf8(src, strlen(src), pool));
  2145. error_t err = convert_cstring(dest, src, pool);
  2146. return err;
  2147. }
  2148. //------------------------------------------------------------------------------
  2149. // from xml.c
  2150. static const char *
  2151. xml_get_attr_value(
  2152. const char * name,
  2153. const char ** atts)
  2154. {
  2155. while (atts && (*atts))
  2156. {
  2157. if (strcmp(atts[0], name) == 0)
  2158. return atts[1];
  2159. else
  2160. atts += 2; // continue looping
  2161. }
  2162. // Else no such attribute name seen.
  2163. return NULL;
  2164. }
  2165. //------------------------------------------------------------------------------
  2166. // from apr_base64.c
  2167. static const char basis_64[] =
  2168. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  2169. // This is the same as apr_base64_encode() except on EBCDIC machines, where
  2170. // the conversion of the input to ascii is left out.
  2171. static int
  2172. apr_base64_encode_binary(
  2173. char * encoded,
  2174. const unsigned char * string,
  2175. int len)
  2176. {
  2177. int i;
  2178. char * p;
  2179. p = encoded;
  2180. for (i = 0; i < len - 2; i += 3)
  2181. {
  2182. *p++ = basis_64[(string[i] >> 2) & 0x3F];
  2183. *p++ = basis_64[((string[i] & 0x3) << 4) |
  2184. ((int)(string[i + 1] & 0xF0) >> 4)];
  2185. *p++ = basis_64[((string[i + 1] & 0xF) << 2) |
  2186. ((int)(string[i + 2] & 0xC0) >> 6)];
  2187. *p++ = basis_64[string[i + 2] & 0x3F];
  2188. }
  2189. if (i < len)
  2190. {
  2191. *p++ = basis_64[(string[i] >> 2) & 0x3F];
  2192. if (i == (len - 1))
  2193. {
  2194. *p++ = basis_64[((string[i] & 0x3) << 4)];
  2195. *p++ = '=';
  2196. }
  2197. else
  2198. {
  2199. *p++ = basis_64[((string[i] & 0x3) << 4) |
  2200. ((int)(string[i + 1] & 0xF0) >> 4)];
  2201. *p++ = basis_64[((string[i + 1] & 0xF) << 2)];
  2202. }
  2203. *p++ = '=';
  2204. }
  2205. *p++ = '\0';
  2206. return (int)(p - encoded);
  2207. }
  2208. static int
  2209. apr_base64_encode(
  2210. char * encoded,
  2211. const char * string,
  2212. int len)
  2213. {
  2214. return apr_base64_encode_binary(encoded, (const unsigned char *) string, len);
  2215. }
  2216. static int
  2217. apr_base64_encode_len(int len)
  2218. {
  2219. return ((len + 2) / 3 * 4) + 1;
  2220. }
  2221. // aaaack but it's fast and const should make it shared text page.
  2222. static const unsigned char pr2six[256] =
  2223. {
  2224. // ASCII table
  2225. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  2226. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  2227. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
  2228. 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
  2229. 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
  2230. 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
  2231. 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
  2232. 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
  2233. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  2234. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  2235. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  2236. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  2237. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  2238. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  2239. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  2240. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
  2241. };
  2242. static int
  2243. apr_base64_decode_len(
  2244. const char * bufcoded)
  2245. {
  2246. int nbytesdecoded;
  2247. register const unsigned char * bufin;
  2248. register apr_size_t nprbytes;
  2249. bufin = (const unsigned char *) bufcoded;
  2250. while (pr2six[*(bufin++)] <= 63);
  2251. nprbytes = (bufin - (const unsigned char *) bufcoded) - 1;
  2252. nbytesdecoded = (((int)nprbytes + 3) / 4) * 3;
  2253. return nbytesdecoded + 1;
  2254. }
  2255. // This is the same as apr_base64_decode() except on EBCDIC machines, where
  2256. // the conversion of the output to ebcdic is left out.
  2257. static int
  2258. apr_base64_decode_binary(
  2259. unsigned char * bufplain,
  2260. const char * bufcoded)
  2261. {
  2262. int nbytesdecoded;
  2263. register const unsigned char * bufin;
  2264. register unsigned char * bufout;
  2265. register apr_size_t nprbytes;
  2266. bufin = (const unsigned char *) bufcoded;
  2267. while (pr2six[*(bufin++)] <= 63);
  2268. nprbytes = (bufin - (const unsigned char *) bufcoded) - 1;
  2269. nbytesdecoded = (((int)nprbytes + 3) / 4) * 3;
  2270. bufout = (unsigned char *) bufplain;
  2271. bufin = (const unsigned char *) bufcoded;
  2272. while (nprbytes > 4)
  2273. {
  2274. *(bufout++) =
  2275. (unsigned char)((pr2six[*bufin] << 2) | (pr2six[bufin[1]] >> 4));
  2276. *(bufout++) =
  2277. (unsigned char)((pr2six[bufin[1]] << 4) | (pr2six[bufin[2]] >> 2));
  2278. *(bufout++) =
  2279. (unsigned char)((pr2six[bufin[2]] << 6) | pr2six[bufin[3]]);
  2280. bufin += 4;
  2281. nprbytes -= 4;
  2282. }
  2283. // Note: (nprbytes == 1) would be an error, so just ignore that case
  2284. if (nprbytes > 1)
  2285. {
  2286. *(bufout++) =
  2287. (unsigned char)((pr2six[*bufin] << 2) | (pr2six[bufin[1]] >> 4));
  2288. }
  2289. if (nprbytes > 2)
  2290. {
  2291. *(bufout++) =
  2292. (unsigned char)((pr2six[bufin[1]] << 4) | (pr2six[bufin[2]] >> 2));
  2293. }
  2294. if (nprbytes > 3)
  2295. {
  2296. *(bufout++) =
  2297. (unsigned char)((pr2six[bufin[2]] << 6) | pr2six[bufin[3]]);
  2298. }
  2299. nbytesdecoded -= (4 - (int)nprbytes) & 3;
  2300. return nbytesdecoded;
  2301. }
  2302. static int
  2303. apr_base64_decode(
  2304. char * bufplain,
  2305. const char * bufcoded)
  2306. {
  2307. int len = apr_base64_decode_binary((unsigned char *) bufplain, bufcoded);
  2308. bufplain[len] = '\0';
  2309. return len;
  2310. }
  2311. //---------------------------------------------------------------------------
  2312. // from user.c
  2313. // Get the current user's name from the OS
  2314. static const char *
  2315. get_os_username(
  2316. apr_pool_t * pool)
  2317. {
  2318. #if APR_HAS_USER
  2319. char * username;
  2320. apr_uid_t uid;
  2321. apr_gid_t gid;
  2322. if (apr_uid_current(&uid, &gid, pool) == APR_SUCCESS &&
  2323. apr_uid_name_get(&username, uid, pool) == APR_SUCCESS)
  2324. return username;
  2325. #endif
  2326. return NULL;
  2327. }
  2328. // Return a UTF8 version of STR, or NULL on error.
  2329. // Use POOL for any necessary allocation.
  2330. static const char *
  2331. utf8_or_nothing(
  2332. const char * str,
  2333. apr_pool_t * pool)
  2334. {
  2335. if (str)
  2336. {
  2337. const char * utf8_str;
  2338. error_t err = utf_cstring_to_utf8(&utf8_str, str, pool);
  2339. if (!err)
  2340. return utf8_str;
  2341. error_clear(&err);
  2342. }
  2343. return NULL;
  2344. }
  2345. static const char *
  2346. user_get_name(
  2347. apr_pool_t * pool)
  2348. {
  2349. const char * username = get_os_username(pool);
  2350. return utf8_or_nothing(username, pool);
  2351. }
  2352. //---------------------------------------------------------------------------
  2353. // from sorts.c
  2354. typedef struct sort_item_t
  2355. {
  2356. const void * key;
  2357. apr_ssize_t klen;
  2358. void * value;
  2359. } sort_item_t;
  2360. static int
  2361. sort_compare_items_lexically(
  2362. const sort_item_t * a,
  2363. const sort_item_t * b)
  2364. {
  2365. // Compare bytes of a's key and b's key up to the common length.
  2366. apr_size_t len = (a->klen < b->klen) ? a->klen : b->klen;
  2367. int val = memcmp(a->key, b->key, len);
  2368. if (val != 0)
  2369. return val;
  2370. // They match up until one of them ends; whichever is longer is greater.
  2371. return (a->klen < b->klen) ? -1 : (a->klen > b->klen) ? 1 : 0;
  2372. }
  2373. static apr_array_header_t *
  2374. sort_hash(apr_hash_t * ht,
  2375. int (*comparison_func)(const sort_item_t *,
  2376. const sort_item_t *),
  2377. apr_pool_t * pool)
  2378. {
  2379. apr_array_header_t * ary = NULL;
  2380. bool sorted = FALSE;
  2381. sort_item_t * prev_item = NULL;
  2382. // allocate an array with enough elements to hold all the keys.
  2383. ary = apr_array_make(pool, apr_hash_count(ht), sizeof(sort_item_t));
  2384. // loop over hash table and push all keys into the array
  2385. sorted = TRUE;
  2386. prev_item = NULL;
  2387. for (apr_hash_index_t * hi = apr_hash_first(pool, ht); hi;
  2388. hi = apr_hash_next(hi))
  2389. {
  2390. sort_item_t * item = static_cast<sort_item_t *>(apr_array_push(ary));
  2391. apr_hash_this(hi, &item->key, &item->klen, &item->value);
  2392. if (prev_item == NULL)
  2393. {
  2394. prev_item = item;
  2395. continue;
  2396. }
  2397. if (sorted)
  2398. {
  2399. sorted = (comparison_func(prev_item, item) < 0);
  2400. prev_item = item;
  2401. }
  2402. }
  2403. // quicksort the array if it isn't already sorted.
  2404. if (!sorted)
  2405. qsort(ary->elts, ary->nelts, ary->elt_size,
  2406. (int ( *)(const void *, const void *))comparison_func);
  2407. return ary;
  2408. }
  2409. //---------------------------------------------------------------------------
  2410. // from svn_config.h
  2411. #define WEBDAV_CONFIG_TRUE "TRUE"
  2412. #define WEBDAV_CONFIG_FALSE "FALSE"
  2413. #define WEBDAV_CONFIG_ASK "ASK"
  2414. // Default values for some options. Should be passed as default values
  2415. // to config_get and friends, instead of hard-coding the defaults in
  2416. // multiple places.
  2417. #define WEBDAV_CONFIG_DEFAULT_OPTION_STORE_PASSWORDS TRUE
  2418. #define WEBDAV_CONFIG_DEFAULT_OPTION_STORE_PLAINTEXT_PASSWORDS WEBDAV_CONFIG_ASK
  2419. #define WEBDAV_CONFIG_DEFAULT_OPTION_STORE_AUTH_CREDS TRUE
  2420. #define WEBDAV_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP TRUE
  2421. #define WEBDAV_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT \
  2422. WEBDAV_CONFIG_ASK
  2423. //---------------------------------------------------------------------------
  2424. // from svn_auth.h
  2425. // Certificate is not yet valid.
  2426. #define WEBDAV_AUTH_SSL_NOTYETVALID 0x00000001
  2427. // Certificate has expired.
  2428. #define WEBDAV_AUTH_SSL_EXPIRED 0x00000002
  2429. // Certificate's CN (hostname) does not match the remote hostname.
  2430. #define WEBDAV_AUTH_SSL_CNMISMATCH 0x00000004
  2431. // Certificate authority is unknown (i.e. not trusted)
  2432. #define WEBDAV_AUTH_SSL_UNKNOWNCA 0x00000008
  2433. // Other failure. This can happen if neon has introduced a new
  2434. // failure bit that we do not handle yet.
  2435. #define WEBDAV_AUTH_SSL_OTHER 0x40000000
  2436. #define AUTH_CRED_SSL_CLIENT_CERT_PW "ssl.client-passphrase"
  2437. #define AUTH_CRED_SSL_CLIENT_CERT "ssl.client-cert"
  2438. // The auth-hash prefix indicating that the parameter is global.
  2439. #define AUTH_PARAM_PREFIX "webdav:auth:"
  2440. // The following property is for SSL server cert providers. This
  2441. // provides a pointer to an apr_uint32_t containing the failures
  2442. // detected by the certificate validator.
  2443. #define AUTH_PARAM_SSL_SERVER_FAILURES AUTH_PARAM_PREFIX \
  2444. "ssl:failures"
  2445. // The following property is for SSL server cert providers. This
  2446. // provides the cert info (auth_ssl_server_cert_info_t).
  2447. #define AUTH_PARAM_SSL_SERVER_CERT_INFO AUTH_PARAM_PREFIX \
  2448. "ssl:cert-info"
  2449. #define AUTH_CRED_SSL_SERVER_TRUST "webdav.ssl.server"
  2450. #define AUTH_CRED_SIMPLE "webdav.simple"
  2451. #define WEBDAV_AUTH_CRED_USERNAME "webdav.username"
  2452. #define WEBDAV_AUTH_PARAM_DEFAULT_USERNAME AUTH_PARAM_PREFIX "username"
  2453. #define WEBDAV_AUTH_PARAM_DEFAULT_PASSWORD AUTH_PARAM_PREFIX "password"
  2454. #define WEBDAV_AUTH_PARAM_NON_INTERACTIVE AUTH_PARAM_PREFIX "non-interactive"
  2455. #define WEBDAV_AUTH_PARAM_DONT_STORE_PASSWORDS AUTH_PARAM_PREFIX \
  2456. "dont-store-passwords"
  2457. #define WEBDAV_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS AUTH_PARAM_PREFIX \
  2458. "store-plaintext-passwords"
  2459. #define WEBDAV_AUTH_PARAM_DONT_STORE_SSL_CLIENT_CERT_PP \
  2460. AUTH_PARAM_PREFIX "dont-store-ssl-client-cert-pp"
  2461. #define WEBDAV_AUTH_PARAM_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT \
  2462. AUTH_PARAM_PREFIX "store-ssl-client-cert-pp-plaintext"
  2463. #define WEBDAV_AUTH_PARAM_NO_AUTH_CACHE AUTH_PARAM_PREFIX "no-auth-cache"
  2464. #define WEBDAV_AUTH_SIMPLE_PASSWORD_TYPE "simple"
  2465. #define WEBDAV_AUTH_WINCRYPT_PASSWORD_TYPE "wincrypt"
  2466. // This effectively defines a single table. Every provider in this
  2467. // array returns the same kind of credentials.
  2468. typedef struct provider_set_t
  2469. {
  2470. // ordered array of auth_provider_object_t
  2471. apr_array_header_t * providers;
  2472. } provider_set_t;
  2473. // Abstracted iteration baton
  2474. struct auth_iterstate_t
  2475. {
  2476. provider_set_t * table; // the table being searched
  2477. int provider_idx; // the current provider (row)
  2478. bool got_first; // did we get the provider's first creds?
  2479. void * provider_iter_baton; // the provider's own iteration context
  2480. const char * realmstring; // The original realmstring passed in
  2481. const char * cache_key; // key to use in auth_baton's creds_cache
  2482. auth_baton_t * auth_baton; // the original auth_baton.
  2483. };
  2484. // The main auth baton.
  2485. typedef struct auth_baton_t
  2486. {
  2487. // a collection of tables. maps cred_kind -> provider_set
  2488. apr_hash_t * tables;
  2489. // the pool I'm allocated in.
  2490. apr_pool_t * pool;
  2491. // run-time parameters needed by providers.
  2492. apr_hash_t * parameters;
  2493. // run-time credentials cache.
  2494. apr_hash_t * creds_cache;
  2495. } auth_baton_t;
  2496. // The main authentication "provider" vtable.
  2497. typedef struct auth_provider_t
  2498. {
  2499. // The kind of credentials this provider knows how to retrieve.
  2500. const char * cred_kind;
  2501. error_t (*first_credentials)(void ** credentials,
  2502. void ** iter_baton,
  2503. void * provider_baton,
  2504. apr_hash_t * parameters,
  2505. const char * realmstring,
  2506. apr_pool_t * pool);
  2507. error_t (*next_credentials)(void ** credentials,
  2508. void * iter_baton,
  2509. void * provider_baton,
  2510. apr_hash_t * parameters,
  2511. const char * realmstring,
  2512. apr_pool_t * pool);
  2513. error_t (*save_credentials)(bool * saved,
  2514. void * credentials,
  2515. void * provider_baton,
  2516. apr_hash_t * parameters,
  2517. const char * realmstring,
  2518. apr_pool_t * pool);
  2519. } auth_provider_t;
  2520. // A provider object, ready to be put into an array and given to
  2521. // create_baton_open().
  2522. typedef struct auth_provider_object_t
  2523. {
  2524. const auth_provider_t * vtable;
  2525. void * provider_baton;
  2526. } auth_provider_object_t;
  2527. typedef error_t (*auth_plaintext_prompt_func_t)(
  2528. bool * may_save_plaintext,
  2529. const char * realmstring,
  2530. void * baton,
  2531. apr_pool_t * pool);
  2532. typedef error_t (*auth_password_get_t)(
  2533. bool * done,
  2534. const char ** password,
  2535. apr_hash_t * creds,
  2536. const char * realmstring,
  2537. const char * username,
  2538. apr_hash_t * parameters,
  2539. bool non_interactive,
  2540. apr_pool_t * pool);
  2541. typedef struct auth_cred_simple_t
  2542. {
  2543. // Username
  2544. const char * username;
  2545. // Password
  2546. const char * password;
  2547. bool may_save;
  2548. } auth_cred_simple_t;
  2549. typedef struct auth_cred_username_t
  2550. {
  2551. // Username
  2552. const char * username;
  2553. bool may_save;
  2554. } auth_cred_username_t;
  2555. typedef error_t (*auth_password_set_t)(
  2556. bool * done,
  2557. apr_hash_t * creds,
  2558. const char * realmstring,
  2559. const char * username,
  2560. const char * password,
  2561. apr_hash_t * parameters,
  2562. bool non_interactive,
  2563. apr_pool_t * pool);
  2564. // AUTH_CRED_SSL_CLIENT_CERT credentials.
  2565. typedef struct auth_cred_ssl_client_cert_t
  2566. {
  2567. // Absolute path to the certificate file
  2568. const char * cert_file;
  2569. bool may_save;
  2570. } auth_cred_ssl_client_cert_t;
  2571. typedef error_t (*auth_ssl_client_cert_prompt_func_t)(
  2572. auth_cred_ssl_client_cert_t ** cred,
  2573. void * baton,
  2574. const char * realm,
  2575. bool may_save,
  2576. apr_pool_t * pool);
  2577. typedef error_t (*auth_plaintext_passphrase_prompt_func_t)(
  2578. bool * may_save_plaintext,
  2579. const char * realmstring,
  2580. void * baton,
  2581. apr_pool_t * pool);
  2582. // AUTH_CRED_SSL_CLIENT_CERT_PW credentials.
  2583. typedef struct auth_cred_ssl_client_cert_pw_t
  2584. {
  2585. // Certificate password
  2586. const char * password;
  2587. bool may_save;
  2588. } auth_cred_ssl_client_cert_pw_t;
  2589. // AUTH_CRED_SSL_SERVER_TRUST credentials.
  2590. typedef struct auth_cred_ssl_server_trust_t
  2591. {
  2592. bool may_save;
  2593. // Bit mask of the accepted failures
  2594. apr_uint32_t accepted_failures;
  2595. } auth_cred_ssl_server_trust_t;
  2596. // SSL server certificate information used by
  2597. // AUTH_CRED_SSL_SERVER_TRUST providers.
  2598. typedef struct auth_ssl_server_cert_info_t
  2599. {
  2600. // Primary CN
  2601. const char * hostname;
  2602. // ASCII fingerprint
  2603. const char * fingerprint;
  2604. // ASCII date from which the certificate is valid
  2605. const char * valid_from;
  2606. // ASCII date until which the certificate is valid
  2607. const char * valid_until;
  2608. // DN of the certificate issuer
  2609. const char * issuer_dname;
  2610. // Base-64 encoded DER certificate representation
  2611. const char * ascii_cert;
  2612. } auth_ssl_server_cert_info_t;
  2613. typedef error_t (*auth_ssl_client_cert_pw_prompt_func_t)(
  2614. auth_cred_ssl_client_cert_pw_t ** cred,
  2615. void * baton,
  2616. const char * realm,
  2617. bool may_save,
  2618. apr_pool_t * pool);
  2619. typedef error_t (*auth_ssl_server_trust_prompt_func_t)(
  2620. auth_cred_ssl_server_trust_t ** cred,
  2621. void * baton,
  2622. const char * realm,
  2623. apr_uint32_t failures,
  2624. const auth_ssl_server_cert_info_t * cert_info,
  2625. bool may_save,
  2626. apr_pool_t * pool);
  2627. typedef error_t (*auth_simple_prompt_func_t)(
  2628. auth_cred_simple_t ** cred,
  2629. void * baton,
  2630. const char * realm,
  2631. const char * username,
  2632. bool may_save,
  2633. apr_pool_t * pool);
  2634. typedef error_t (*auth_username_prompt_func_t)(
  2635. auth_cred_username_t ** cred,
  2636. void * baton,
  2637. const char * realm,
  2638. bool may_save,
  2639. apr_pool_t * pool);
  2640. //---------------------------------------------------------------------------
  2641. // from config_auth.c
  2642. #define CONST_FS_KEY "fs"
  2643. #define CONST_FINGERPRINT_KEY "fingerprint"
  2644. // The keys that will be stored on disk. These serve the same role as
  2645. // similar constants in other providers.
  2646. #define AUTHN_ASCII_CERT_KEY "ascii_cert"
  2647. #define AUTHN_FAILURES_KEY "failures"
  2648. static const char CertificateStorageKey[] = "HttpsCertificates";
  2649. static error_t
  2650. config_read_auth_data(
  2651. apr_hash_t ** hash,
  2652. const char * cred_kind,
  2653. const char * realmstring,
  2654. TWebDAVFileSystem * fs,
  2655. apr_pool_t * pool)
  2656. {
  2657. const char * subkey = CertificateStorageKey;
  2658. THierarchicalStorage * Storage = NULL;
  2659. WEBDAV_ERR(fs->CreateStorage(Storage));
  2660. assert(Storage);
  2661. std::auto_ptr<THierarchicalStorage> StoragePtr;
  2662. StoragePtr.reset(Storage);
  2663. Storage->AccessMode = smRead;
  2664. if (!Storage->OpenSubKey(UnicodeString(subkey), false))
  2665. return WEBDAV_ERR_BAD_PARAM;
  2666. *hash = apr_hash_make(pool);
  2667. TStrings * Keys = new TStringList();
  2668. try
  2669. {
  2670. Storage->GetValueNames(Keys);
  2671. for (int Index = 0; Index < Keys->Count; ++Index)
  2672. {
  2673. UnicodeString Key = Keys->Strings[Index];
  2674. UnicodeString Value = Storage->ReadStringRaw(Key, L"");
  2675. apr_hash_set(*hash, AUTHN_ASCII_CERT_KEY, APR_HASH_KEY_STRING,
  2676. string_create(AnsiString(Key).c_str(), pool));
  2677. apr_hash_set(*hash, AUTHN_FAILURES_KEY, APR_HASH_KEY_STRING,
  2678. string_createf(pool, "%lu", (unsigned long)
  2679. StrToIntDef(Value, 0)));
  2680. }
  2681. }
  2682. __finally
  2683. {
  2684. delete Keys;
  2685. }
  2686. return WEBDAV_NO_ERROR;
  2687. }
  2688. static error_t
  2689. config_write_auth_data(
  2690. apr_hash_t * hash,
  2691. const char * cred_kind,
  2692. const char * realmstring,
  2693. TWebDAVFileSystem * fs,
  2694. apr_pool_t * pool)
  2695. {
  2696. const char * subkey = CertificateStorageKey;
  2697. assert(fs);
  2698. THierarchicalStorage * Storage = NULL;
  2699. WEBDAV_ERR(fs->CreateStorage(Storage));
  2700. assert(Storage);
  2701. std::auto_ptr<THierarchicalStorage> StoragePtr;
  2702. StoragePtr.reset(Storage);
  2703. Storage->AccessMode = smReadWrite;
  2704. if (!Storage->OpenSubKey(UnicodeString(subkey), true))
  2705. return WEBDAV_ERR_BAD_PARAM;
  2706. string_t * trusted_cert = static_cast<string_t *>(apr_hash_get(hash, AUTHN_ASCII_CERT_KEY,
  2707. APR_HASH_KEY_STRING));
  2708. string_t * failstr = static_cast<string_t *>(apr_hash_get(hash, AUTHN_FAILURES_KEY,
  2709. APR_HASH_KEY_STRING));
  2710. if (trusted_cert && failstr)
  2711. Storage->WriteString(UnicodeString(trusted_cert->data), UnicodeString(failstr->data));
  2712. return WEBDAV_NO_ERROR;
  2713. }
  2714. //---------------------------------------------------------------------------
  2715. // from simple_providers.c
  2716. // The keys that will be stored on disk. These serve the same role as
  2717. // similar constants in other providers.
  2718. #define AUTHN_USERNAME_KEY "username"
  2719. #define AUTHN_PASSWORD_KEY "password"
  2720. #define AUTHN_PASSTYPE_KEY "passtype"
  2721. // Baton type for the simple provider.
  2722. typedef struct simple_provider_baton_t
  2723. {
  2724. auth_plaintext_prompt_func_t plaintext_prompt_func;
  2725. void * prompt_baton;
  2726. // We cache the user's answer to the plaintext prompt, keyed
  2727. // by realm, in case we'll be called multiple times for the
  2728. // same realm.
  2729. apr_hash_t * plaintext_answers;
  2730. } simple_provider_baton_t;
  2731. // Implementation of auth_password_get_t that retrieves
  2732. // the plaintext password from CREDS.
  2733. static error_t
  2734. auth_simple_password_get(
  2735. bool * done,
  2736. const char ** password,
  2737. apr_hash_t * creds,
  2738. const char * realmstring,
  2739. const char * username,
  2740. apr_hash_t * parameters,
  2741. bool non_interactive,
  2742. apr_pool_t * pool)
  2743. {
  2744. *done = FALSE;
  2745. string_t * str = static_cast<string_t *>(apr_hash_get(creds, AUTHN_USERNAME_KEY, APR_HASH_KEY_STRING));
  2746. if (str && username && strcmp(str->data, username) == 0)
  2747. {
  2748. str = static_cast<string_t *>(apr_hash_get(creds, AUTHN_PASSWORD_KEY, APR_HASH_KEY_STRING));
  2749. if (str && str->data)
  2750. {
  2751. *password = str->data;
  2752. *done = TRUE;
  2753. }
  2754. }
  2755. return WEBDAV_NO_ERROR;
  2756. }
  2757. // Implementation of auth_password_set_t that stores
  2758. // the plaintext password in CREDS.
  2759. static error_t
  2760. auth_simple_password_set(
  2761. bool * done,
  2762. apr_hash_t * creds,
  2763. const char * realmstring,
  2764. const char * username,
  2765. const char * password,
  2766. apr_hash_t * parameters,
  2767. bool non_interactive,
  2768. apr_pool_t * pool)
  2769. {
  2770. apr_hash_set(creds, AUTHN_PASSWORD_KEY, APR_HASH_KEY_STRING,
  2771. string_create(password, pool));
  2772. *done = TRUE;
  2773. return WEBDAV_NO_ERROR;
  2774. }
  2775. // Set **USERNAME to the username retrieved from CREDS; ignore
  2776. // other parameters. *USERNAME will have the same lifetime as CREDS.
  2777. static bool
  2778. simple_username_get(
  2779. const char ** username,
  2780. apr_hash_t * creds,
  2781. const char * realmstring,
  2782. bool non_interactive)
  2783. {
  2784. string_t * str = static_cast<string_t *>(apr_hash_get(creds, AUTHN_USERNAME_KEY, APR_HASH_KEY_STRING));
  2785. if (str && str->data)
  2786. {
  2787. *username = str->data;
  2788. return TRUE;
  2789. }
  2790. return FALSE;
  2791. }
  2792. // Common implementation for simple_first_creds. Uses PARAMETERS, REALMSTRING
  2793. // and the simple auth provider's username and password cache to fill a set of
  2794. // CREDENTIALS. PASSWORD_GET is used to obtain the password value.
  2795. // PASSTYPE identifies the type of the cached password. CREDENTIALS are
  2796. // allocated from POOL.
  2797. static error_t
  2798. auth_simple_first_creds_helper(
  2799. void ** credentials,
  2800. void ** iter_baton,
  2801. void * provider_baton,
  2802. apr_hash_t * parameters,
  2803. const char * realmstring,
  2804. auth_password_get_t password_get,
  2805. const char * passtype,
  2806. apr_pool_t * pool)
  2807. {
  2808. const char * username = static_cast<const char *>(apr_hash_get(parameters,
  2809. WEBDAV_AUTH_PARAM_DEFAULT_USERNAME,
  2810. APR_HASH_KEY_STRING));
  2811. const char * password = static_cast<const char *>(apr_hash_get(parameters,
  2812. WEBDAV_AUTH_PARAM_DEFAULT_PASSWORD,
  2813. APR_HASH_KEY_STRING));
  2814. bool non_interactive = apr_hash_get(parameters,
  2815. WEBDAV_AUTH_PARAM_NON_INTERACTIVE,
  2816. APR_HASH_KEY_STRING) != NULL;
  2817. const char * default_username = NULL; // Default username from cache.
  2818. const char * default_password = NULL; // Default password from cache.
  2819. // This checks if we should save the CREDS, if saving the credentials is
  2820. // allowed by the run-time configuration.
  2821. bool need_to_save = FALSE;
  2822. apr_hash_t * creds_hash = NULL;
  2823. error_t err = 0;
  2824. // Try to load credentials from a file on disk, based on the
  2825. // realmstring. Don't throw an error, though: if something went
  2826. // wrong reading the file, no big deal. What really matters is that
  2827. // we failed to get the creds, so allow the auth system to try the
  2828. // next provider.
  2829. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
  2830. CONST_FS_KEY,
  2831. APR_HASH_KEY_STRING));
  2832. assert(fs);
  2833. err = config_read_auth_data(&creds_hash, AUTH_CRED_SIMPLE,
  2834. realmstring, fs, pool);
  2835. if (err)
  2836. {
  2837. error_clear(&err);
  2838. err = NULL;
  2839. }
  2840. else if (creds_hash)
  2841. {
  2842. // We have something in the auth cache for this realm.
  2843. bool have_passtype = FALSE;
  2844. // The password type in the auth data must match the
  2845. // mangler's type, otherwise the password must be
  2846. // interpreted by another provider.
  2847. string_t * str = static_cast<string_t *>(apr_hash_get(creds_hash, AUTHN_PASSTYPE_KEY, APR_HASH_KEY_STRING));
  2848. if (str && str->data)
  2849. if (passtype && (0 == strcmp(str->data, passtype)))
  2850. have_passtype = TRUE;
  2851. // See if we need to save this username if it is not present in
  2852. // auth cache.
  2853. if (username)
  2854. {
  2855. if (!simple_username_get(&default_username, creds_hash, realmstring,
  2856. non_interactive))
  2857. {
  2858. need_to_save = TRUE;
  2859. }
  2860. else
  2861. {
  2862. if (0 == strcmp(default_username, username))
  2863. need_to_save = FALSE;
  2864. else
  2865. need_to_save = TRUE;
  2866. }
  2867. }
  2868. // See if we need to save this password if it is not present in
  2869. // auth cache.
  2870. if (password)
  2871. {
  2872. if (have_passtype)
  2873. {
  2874. bool done;
  2875. WEBDAV_ERR(password_get(&done, &default_password, creds_hash, realmstring,
  2876. username, parameters, non_interactive, pool));
  2877. if (!done)
  2878. {
  2879. need_to_save = TRUE;
  2880. }
  2881. else
  2882. {
  2883. if (0 == strcmp(default_password, password))
  2884. need_to_save = FALSE;
  2885. else
  2886. need_to_save = TRUE;
  2887. }
  2888. }
  2889. }
  2890. // If we don't have a username and a password yet, we try the
  2891. // auth cache
  2892. if (!(username && password))
  2893. {
  2894. if (!username)
  2895. if (!simple_username_get(&username, creds_hash, realmstring,
  2896. non_interactive))
  2897. username = NULL;
  2898. if (username && !password)
  2899. {
  2900. if (!have_passtype)
  2901. password = NULL;
  2902. else
  2903. {
  2904. bool done;
  2905. WEBDAV_ERR(password_get(&done, &password, creds_hash, realmstring,
  2906. username, parameters, non_interactive,
  2907. pool));
  2908. if (!done)
  2909. password = NULL;
  2910. // If the auth data didn't contain a password type,
  2911. // force a write to upgrade the format of the auth
  2912. // data file.
  2913. if (password && !have_passtype)
  2914. need_to_save = TRUE;
  2915. }
  2916. }
  2917. }
  2918. }
  2919. else
  2920. {
  2921. // Nothing was present in the auth cache, so indicate that these
  2922. // credentials should be saved.
  2923. need_to_save = TRUE;
  2924. }
  2925. // Ask the OS for the username if we have a password but no username.
  2926. if (password && !username)
  2927. username = user_get_name(pool);
  2928. if (username && password)
  2929. {
  2930. auth_cred_simple_t * creds = static_cast<auth_cred_simple_t *>(apr_pcalloc(pool, sizeof(*creds)));
  2931. creds->username = username;
  2932. creds->password = password;
  2933. creds->may_save = need_to_save;
  2934. *credentials = creds;
  2935. }
  2936. else
  2937. *credentials = NULL;
  2938. *iter_baton = NULL;
  2939. return WEBDAV_NO_ERROR;
  2940. }
  2941. // Common implementation for simple_save_creds. Uses PARAMETERS and
  2942. // REALMSTRING to save a set of CREDENTIALS to the simple auth provider's
  2943. // username and password cache. PASSWORD_SET is used to store the password.
  2944. // PASSTYPE identifies the type of the cached password. Allocates from POOL.
  2945. static error_t
  2946. auth_simple_save_creds_helper(
  2947. bool * saved,
  2948. void * credentials,
  2949. void * provider_baton,
  2950. apr_hash_t * parameters,
  2951. const char * realmstring,
  2952. auth_password_set_t password_set,
  2953. const char * passtype,
  2954. apr_pool_t * pool)
  2955. {
  2956. auth_cred_simple_t * creds = static_cast<auth_cred_simple_t *>(credentials);
  2957. apr_hash_t * creds_hash = NULL;
  2958. error_t err = 0;
  2959. bool dont_store_passwords =
  2960. apr_hash_get(parameters,
  2961. WEBDAV_AUTH_PARAM_DONT_STORE_PASSWORDS,
  2962. APR_HASH_KEY_STRING) != NULL;
  2963. const char * store_plaintext_passwords = static_cast<const char *>(
  2964. apr_hash_get(parameters,
  2965. WEBDAV_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS,
  2966. APR_HASH_KEY_STRING));
  2967. bool non_interactive = apr_hash_get(parameters,
  2968. WEBDAV_AUTH_PARAM_NON_INTERACTIVE,
  2969. APR_HASH_KEY_STRING) != NULL;
  2970. simple_provider_baton_t * b = (simple_provider_baton_t *)provider_baton;
  2971. bool no_auth_cache = (!creds->may_save) ||
  2972. (apr_hash_get(parameters,
  2973. WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
  2974. APR_HASH_KEY_STRING) != NULL);
  2975. // Make sure we've been passed a passtype.
  2976. WEBDAV_ERR_ASSERT(passtype != NULL);
  2977. *saved = FALSE;
  2978. if (no_auth_cache)
  2979. return WEBDAV_NO_ERROR;
  2980. // Put the username into the credentials hash.
  2981. creds_hash = apr_hash_make(pool);
  2982. apr_hash_set(creds_hash, AUTHN_USERNAME_KEY, APR_HASH_KEY_STRING,
  2983. string_create(creds->username, pool));
  2984. // Don't store passwords in any form if the user has told
  2985. // us not to do so.
  2986. if (!dont_store_passwords)
  2987. {
  2988. bool may_save_password = FALSE;
  2989. // If the password is going to be stored encrypted, go right
  2990. // ahead and store it to disk. Else determine whether saving
  2991. // in plaintext is OK.
  2992. if (passtype &&
  2993. (strcmp(passtype, WEBDAV_AUTH_WINCRYPT_PASSWORD_TYPE) == 0))
  2994. {
  2995. may_save_password = TRUE;
  2996. }
  2997. else
  2998. {
  2999. if (store_plaintext_passwords && cstring_casecmp(store_plaintext_passwords,
  3000. WEBDAV_CONFIG_ASK) == 0)
  3001. {
  3002. if (non_interactive)
  3003. // In non-interactive mode, the default behaviour is
  3004. // to not store the password, because it is usually
  3005. // passed on the command line.
  3006. may_save_password = FALSE;
  3007. else if (b && b->plaintext_prompt_func)
  3008. {
  3009. // We're interactive, and the client provided a
  3010. // prompt callback. So we can ask the user.
  3011. // Check for a cached answer before prompting.
  3012. bool * cached_answer;
  3013. cached_answer = static_cast<bool *>(apr_hash_get(b->plaintext_answers,
  3014. realmstring,
  3015. APR_HASH_KEY_STRING));
  3016. if (cached_answer != NULL)
  3017. may_save_password = *cached_answer;
  3018. else
  3019. {
  3020. apr_pool_t * cached_answer_pool;
  3021. // Nothing cached for this realm, prompt the user.
  3022. WEBDAV_ERR((*b->plaintext_prompt_func)(&may_save_password,
  3023. realmstring,
  3024. b->prompt_baton,
  3025. pool));
  3026. cached_answer_pool = apr_hash_pool_get(b->plaintext_answers);
  3027. cached_answer = static_cast<bool *>(apr_pcalloc(cached_answer_pool,
  3028. sizeof(bool)));
  3029. *cached_answer = may_save_password;
  3030. apr_hash_set(b->plaintext_answers, realmstring,
  3031. APR_HASH_KEY_STRING, cached_answer);
  3032. }
  3033. }
  3034. else
  3035. {
  3036. may_save_password = TRUE;
  3037. }
  3038. }
  3039. else if (store_plaintext_passwords && cstring_casecmp(store_plaintext_passwords,
  3040. WEBDAV_CONFIG_FALSE) == 0)
  3041. {
  3042. may_save_password = FALSE;
  3043. }
  3044. else if (store_plaintext_passwords && cstring_casecmp(store_plaintext_passwords,
  3045. WEBDAV_CONFIG_TRUE) == 0)
  3046. {
  3047. may_save_password = TRUE;
  3048. }
  3049. else
  3050. {
  3051. /*return error_createf
  3052. (WEBDAV_ERR_BAD_CONFIG_VALUE, NULL,
  3053. "Config error: invalid value '%s' for option '%s'",
  3054. store_plaintext_passwords,
  3055. WEBDAV_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS);*/
  3056. may_save_password = FALSE;
  3057. }
  3058. }
  3059. if (may_save_password)
  3060. {
  3061. WEBDAV_ERR(password_set(saved, creds_hash, realmstring,
  3062. creds->username, creds->password,
  3063. parameters, non_interactive, pool));
  3064. if (*saved && passtype)
  3065. // Store the password type with the auth data, so that we
  3066. // know which provider owns the password.
  3067. apr_hash_set(creds_hash, AUTHN_PASSTYPE_KEY, APR_HASH_KEY_STRING,
  3068. string_create(passtype, pool));
  3069. }
  3070. }
  3071. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
  3072. CONST_FS_KEY,
  3073. APR_HASH_KEY_STRING));
  3074. assert(fs);
  3075. // Save credentials to disk.
  3076. err = config_write_auth_data(creds_hash, AUTH_CRED_SIMPLE,
  3077. realmstring, fs, pool);
  3078. error_clear(&err);
  3079. return WEBDAV_NO_ERROR;
  3080. }
  3081. // Get cached (unencrypted) credentials from the simple provider's cache.
  3082. static error_t
  3083. simple_first_creds(
  3084. void ** credentials,
  3085. void ** iter_baton,
  3086. void * provider_baton,
  3087. apr_hash_t * parameters,
  3088. const char * realmstring,
  3089. apr_pool_t * pool)
  3090. {
  3091. return auth_simple_first_creds_helper(credentials,
  3092. iter_baton,
  3093. provider_baton,
  3094. parameters,
  3095. realmstring,
  3096. auth_simple_password_get,
  3097. WEBDAV_AUTH_SIMPLE_PASSWORD_TYPE,
  3098. pool);
  3099. }
  3100. // Save (unencrypted) credentials to the simple provider's cache.
  3101. static error_t
  3102. simple_save_creds(
  3103. bool * saved,
  3104. void * credentials,
  3105. void * provider_baton,
  3106. apr_hash_t * parameters,
  3107. const char * realmstring,
  3108. apr_pool_t * pool)
  3109. {
  3110. return auth_simple_save_creds_helper(saved, credentials,
  3111. provider_baton,
  3112. parameters,
  3113. realmstring,
  3114. auth_simple_password_set,
  3115. WEBDAV_AUTH_SIMPLE_PASSWORD_TYPE,
  3116. pool);
  3117. }
  3118. static const auth_provider_t simple_provider =
  3119. {
  3120. AUTH_CRED_SIMPLE,
  3121. simple_first_creds,
  3122. NULL,
  3123. simple_save_creds
  3124. };
  3125. // Public API
  3126. static void
  3127. auth_get_simple_provider2(
  3128. auth_provider_object_t ** provider,
  3129. auth_plaintext_prompt_func_t plaintext_prompt_func,
  3130. void * prompt_baton,
  3131. apr_pool_t * pool)
  3132. {
  3133. auth_provider_object_t * po = static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
  3134. simple_provider_baton_t * pb = static_cast<simple_provider_baton_t *>(apr_pcalloc(pool, sizeof(*pb)));
  3135. pb->plaintext_prompt_func = plaintext_prompt_func;
  3136. pb->prompt_baton = prompt_baton;
  3137. pb->plaintext_answers = apr_hash_make(pool);
  3138. po->vtable = &simple_provider;
  3139. po->provider_baton = pb;
  3140. *provider = po;
  3141. }
  3142. // Baton type for username/password prompting.
  3143. typedef struct simple_prompt_provider_baton_t
  3144. {
  3145. auth_simple_prompt_func_t prompt_func;
  3146. void * prompt_baton;
  3147. // how many times to re-prompt after the first one fails
  3148. int retry_limit;
  3149. } simple_prompt_provider_baton_t;
  3150. // Iteration baton type for username/password prompting.
  3151. typedef struct simple_prompt_iter_baton_t
  3152. {
  3153. // how many times we've reprompted
  3154. int retries;
  3155. } simple_prompt_iter_baton_t;
  3156. // Helper Functions
  3157. static error_t
  3158. prompt_for_simple_creds(
  3159. auth_cred_simple_t ** cred_p,
  3160. simple_prompt_provider_baton_t * pb,
  3161. apr_hash_t * parameters,
  3162. const char * realmstring,
  3163. bool first_time,
  3164. bool may_save,
  3165. apr_pool_t * pool)
  3166. {
  3167. const char * default_username = NULL;
  3168. const char * default_password = NULL;
  3169. *cred_p = NULL;
  3170. // If we're allowed to check for default usernames and passwords, do so.
  3171. if (first_time)
  3172. {
  3173. default_username = static_cast<const char *>(apr_hash_get(parameters,
  3174. WEBDAV_AUTH_PARAM_DEFAULT_USERNAME,
  3175. APR_HASH_KEY_STRING));
  3176. // No default username? Try the auth cache.
  3177. if (!default_username)
  3178. {
  3179. apr_hash_t * creds_hash = NULL;
  3180. string_t * str;
  3181. error_t err;
  3182. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
  3183. CONST_FS_KEY,
  3184. APR_HASH_KEY_STRING));
  3185. assert(fs);
  3186. err = config_read_auth_data(&creds_hash, AUTH_CRED_SIMPLE,
  3187. realmstring, fs, pool);
  3188. error_clear(&err);
  3189. if (!err && creds_hash)
  3190. {
  3191. str = static_cast<string_t *>(apr_hash_get(creds_hash, AUTHN_USERNAME_KEY,
  3192. APR_HASH_KEY_STRING));
  3193. if (str && str->data)
  3194. default_username = str->data;
  3195. }
  3196. }
  3197. // Still no default username? Try the 'servers' file.
  3198. if (!default_username)
  3199. {
  3200. default_username = NULL;
  3201. }
  3202. // Still no default username? Try the UID.
  3203. if (!default_username)
  3204. default_username = user_get_name(pool);
  3205. default_password = static_cast<const char *>(apr_hash_get(parameters,
  3206. WEBDAV_AUTH_PARAM_DEFAULT_PASSWORD,
  3207. APR_HASH_KEY_STRING));
  3208. }
  3209. // If we have defaults, just build the cred here and return it.
  3210. // I do wonder why this is here instead of in a separate
  3211. // 'defaults' provider that would run before the prompt
  3212. // provider... Hmmm.
  3213. if (default_username && default_password)
  3214. {
  3215. *cred_p = static_cast<auth_cred_simple_t *>(apr_pcalloc(pool, sizeof(**cred_p)));
  3216. (*cred_p)->username = apr_pstrdup(pool, default_username);
  3217. (*cred_p)->password = apr_pstrdup(pool, default_password);
  3218. (*cred_p)->may_save = TRUE;
  3219. }
  3220. else
  3221. {
  3222. WEBDAV_ERR(pb->prompt_func(cred_p, pb->prompt_baton, realmstring,
  3223. default_username, may_save, pool));
  3224. }
  3225. return WEBDAV_NO_ERROR;
  3226. }
  3227. // Our first attempt will use any default username/password passed
  3228. // in, and prompt for the remaining stuff.
  3229. static error_t
  3230. simple_prompt_first_creds(
  3231. void ** credentials_p,
  3232. void ** iter_baton,
  3233. void * provider_baton,
  3234. apr_hash_t * parameters,
  3235. const char * realmstring,
  3236. apr_pool_t * pool)
  3237. {
  3238. simple_prompt_provider_baton_t * pb =
  3239. static_cast<simple_prompt_provider_baton_t *>(provider_baton);
  3240. simple_prompt_iter_baton_t * ibaton =
  3241. static_cast<simple_prompt_iter_baton_t *>(apr_pcalloc(pool, sizeof(*ibaton)));
  3242. const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
  3243. WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
  3244. APR_HASH_KEY_STRING));
  3245. WEBDAV_ERR(prompt_for_simple_creds((auth_cred_simple_t **) credentials_p,
  3246. pb, parameters, realmstring, TRUE,
  3247. !no_auth_cache, pool));
  3248. ibaton->retries = 0;
  3249. *iter_baton = ibaton;
  3250. return WEBDAV_NO_ERROR;
  3251. }
  3252. // Subsequent attempts to fetch will ignore the default values, and
  3253. // simply re-prompt for both, up to a maximum of ib->pb->retry_limit.
  3254. static error_t
  3255. simple_prompt_next_creds(
  3256. void ** credentials_p,
  3257. void * iter_baton,
  3258. void * provider_baton,
  3259. apr_hash_t * parameters,
  3260. const char * realmstring,
  3261. apr_pool_t * pool)
  3262. {
  3263. simple_prompt_iter_baton_t * ib =
  3264. static_cast<simple_prompt_iter_baton_t *>(iter_baton);
  3265. simple_prompt_provider_baton_t * pb =
  3266. static_cast<simple_prompt_provider_baton_t *>(provider_baton);
  3267. const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
  3268. WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
  3269. APR_HASH_KEY_STRING));
  3270. if ((pb->retry_limit >= 0) && (ib->retries >= pb->retry_limit))
  3271. {
  3272. // give up, go on to next provider.
  3273. *credentials_p = NULL;
  3274. return WEBDAV_NO_ERROR;
  3275. }
  3276. ib->retries++;
  3277. return prompt_for_simple_creds((auth_cred_simple_t **) credentials_p,
  3278. pb, parameters, realmstring, FALSE,
  3279. !no_auth_cache, pool);
  3280. }
  3281. static const auth_provider_t simple_prompt_provider =
  3282. {
  3283. AUTH_CRED_SIMPLE,
  3284. simple_prompt_first_creds,
  3285. simple_prompt_next_creds,
  3286. NULL,
  3287. };
  3288. // Public API
  3289. static void
  3290. auth_get_simple_prompt_provider(
  3291. auth_provider_object_t ** provider,
  3292. auth_simple_prompt_func_t prompt_func,
  3293. void * prompt_baton,
  3294. int retry_limit,
  3295. apr_pool_t * pool)
  3296. {
  3297. auth_provider_object_t * po =
  3298. static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
  3299. simple_prompt_provider_baton_t * pb =
  3300. static_cast<simple_prompt_provider_baton_t *>(apr_pcalloc(pool, sizeof(*pb)));
  3301. pb->prompt_func = prompt_func;
  3302. pb->prompt_baton = prompt_baton;
  3303. pb->retry_limit = retry_limit;
  3304. po->vtable = &simple_prompt_provider;
  3305. po->provider_baton = pb;
  3306. *provider = po;
  3307. }
  3308. //---------------------------------------------------------------------------
  3309. // from ssl_client_cert_pw_providers.c
  3310. // The keys that will be stored on disk. These serve the same role as
  3311. // similar constants in other providers.
  3312. // AUTHN_PASSTYPE_KEY just records the passphrase type next to the
  3313. // passphrase, so that anyone who is manually editing their authn
  3314. // files can know which provider owns the password.
  3315. #define AUTHN_PASSPHRASE_KEY "passphrase"
  3316. #define AUTHN_PASSTYPE_KEY "passtype"
  3317. // Baton type for the ssl client cert passphrase provider.
  3318. typedef struct ssl_client_cert_pw_file_provider_baton_t
  3319. {
  3320. auth_plaintext_passphrase_prompt_func_t plaintext_passphrase_prompt_func;
  3321. void * prompt_baton;
  3322. // We cache the user's answer to the plaintext prompt, keyed
  3323. // by realm, in case we'll be called multiple times for the
  3324. // same realm. So: keys are 'const char *' realm strings, and
  3325. // values are 'bool *'.
  3326. apr_hash_t * plaintext_answers;
  3327. } ssl_client_cert_pw_file_provider_baton_t;
  3328. // This implements the auth_password_get_t interface.
  3329. // Set **PASSPHRASE to the plaintext passphrase retrieved from CREDS;
  3330. // ignore other parameters.
  3331. static error_t
  3332. auth_ssl_client_cert_pw_get(
  3333. bool * done,
  3334. const char ** passphrase,
  3335. apr_hash_t * creds,
  3336. const char * realmstring,
  3337. const char * username,
  3338. apr_hash_t * parameters,
  3339. bool non_interactive,
  3340. apr_pool_t * pool)
  3341. {
  3342. string_t * str = static_cast<string_t *>(apr_hash_get(creds, AUTHN_PASSPHRASE_KEY, APR_HASH_KEY_STRING));
  3343. if (str && str->data)
  3344. {
  3345. *passphrase = str->data;
  3346. *done = TRUE;
  3347. return WEBDAV_NO_ERROR;
  3348. }
  3349. *done = FALSE;
  3350. return WEBDAV_NO_ERROR;
  3351. }
  3352. // This implements the auth_password_set_t interface.
  3353. // Store PASSPHRASE in CREDS; ignore other parameters.
  3354. static error_t
  3355. auth_ssl_client_cert_pw_set(
  3356. bool * done,
  3357. apr_hash_t * creds,
  3358. const char * realmstring,
  3359. const char * username,
  3360. const char * passphrase,
  3361. apr_hash_t * parameters,
  3362. bool non_interactive,
  3363. apr_pool_t * pool)
  3364. {
  3365. apr_hash_set(creds, AUTHN_PASSPHRASE_KEY, APR_HASH_KEY_STRING,
  3366. string_create(passphrase, pool));
  3367. *done = TRUE;
  3368. return WEBDAV_NO_ERROR;
  3369. }
  3370. static error_t
  3371. auth_ssl_client_cert_pw_file_first_creds_helper(
  3372. void ** credentials_p,
  3373. void ** iter_baton,
  3374. void * provider_baton,
  3375. apr_hash_t * parameters,
  3376. const char * realmstring,
  3377. auth_password_get_t passphrase_get,
  3378. const char * passtype,
  3379. apr_pool_t * pool)
  3380. {
  3381. bool non_interactive = apr_hash_get(parameters,
  3382. WEBDAV_AUTH_PARAM_NON_INTERACTIVE,
  3383. APR_HASH_KEY_STRING) != NULL;
  3384. const char * password = NULL;
  3385. if (!password)
  3386. {
  3387. error_t err;
  3388. apr_hash_t * creds_hash = NULL;
  3389. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
  3390. CONST_FS_KEY,
  3391. APR_HASH_KEY_STRING));
  3392. assert(fs);
  3393. // Try to load passphrase from the auth/ cache.
  3394. err = config_read_auth_data(&creds_hash,
  3395. AUTH_CRED_SSL_CLIENT_CERT_PW,
  3396. realmstring, fs, pool);
  3397. error_clear(&err);
  3398. if (!err && creds_hash)
  3399. {
  3400. bool done;
  3401. WEBDAV_ERR(passphrase_get(&done, &password, creds_hash, realmstring,
  3402. NULL, parameters, non_interactive, pool));
  3403. if (!done)
  3404. password = NULL;
  3405. }
  3406. }
  3407. if (password)
  3408. {
  3409. auth_cred_ssl_client_cert_pw_t * cred =
  3410. static_cast<auth_cred_ssl_client_cert_pw_t *>(apr_pcalloc(pool, sizeof(*cred)));
  3411. cred->password = password;
  3412. cred->may_save = FALSE;
  3413. *credentials_p = cred;
  3414. }
  3415. else *credentials_p = NULL;
  3416. *iter_baton = NULL;
  3417. return WEBDAV_NO_ERROR;
  3418. }
  3419. static error_t
  3420. auth_ssl_client_cert_pw_file_save_creds_helper(
  3421. bool * saved,
  3422. void * credentials,
  3423. void * provider_baton,
  3424. apr_hash_t * parameters,
  3425. const char * realmstring,
  3426. auth_password_set_t passphrase_set,
  3427. const char * passtype,
  3428. apr_pool_t * pool)
  3429. {
  3430. auth_cred_ssl_client_cert_pw_t * creds =
  3431. static_cast<auth_cred_ssl_client_cert_pw_t *>(credentials);
  3432. apr_hash_t * creds_hash = NULL;
  3433. error_t err = 0;
  3434. bool dont_store_passphrase =
  3435. apr_hash_get(parameters,
  3436. WEBDAV_AUTH_PARAM_DONT_STORE_SSL_CLIENT_CERT_PP,
  3437. APR_HASH_KEY_STRING) != NULL;
  3438. const char * store_ssl_client_cert_pp_plaintext =
  3439. static_cast<const char *>(apr_hash_get(parameters,
  3440. WEBDAV_AUTH_PARAM_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT,
  3441. APR_HASH_KEY_STRING));
  3442. bool non_interactive = apr_hash_get(parameters,
  3443. WEBDAV_AUTH_PARAM_NON_INTERACTIVE,
  3444. APR_HASH_KEY_STRING) != NULL;
  3445. ssl_client_cert_pw_file_provider_baton_t * b =
  3446. (ssl_client_cert_pw_file_provider_baton_t *)provider_baton;
  3447. bool no_auth_cache = (!creds->may_save) ||
  3448. (apr_hash_get(parameters,
  3449. WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
  3450. APR_HASH_KEY_STRING) != NULL);
  3451. *saved = FALSE;
  3452. if (no_auth_cache)
  3453. return WEBDAV_NO_ERROR;
  3454. creds_hash = apr_hash_make(pool);
  3455. // Don't store passphrase in any form if the user has told
  3456. // us not to do so.
  3457. if (!dont_store_passphrase)
  3458. {
  3459. bool may_save_passphrase = FALSE;
  3460. // If the passphrase is going to be stored encrypted, go right
  3461. // ahead and store it to disk. Else determine whether saving
  3462. // in plaintext is OK.
  3463. if (strcmp(passtype, WEBDAV_AUTH_WINCRYPT_PASSWORD_TYPE) == 0)
  3464. {
  3465. may_save_passphrase = TRUE;
  3466. }
  3467. else
  3468. {
  3469. if (cstring_casecmp(store_ssl_client_cert_pp_plaintext,
  3470. WEBDAV_CONFIG_ASK) == 0)
  3471. {
  3472. if (non_interactive)
  3473. {
  3474. // In non-interactive mode, the default behaviour is
  3475. // to not store the passphrase
  3476. may_save_passphrase = FALSE;
  3477. }
  3478. else if (b->plaintext_passphrase_prompt_func)
  3479. {
  3480. bool * cached_answer =
  3481. static_cast<bool *>(apr_hash_get(b->plaintext_answers, realmstring,
  3482. APR_HASH_KEY_STRING));
  3483. if (cached_answer != NULL)
  3484. {
  3485. may_save_passphrase = *cached_answer;
  3486. }
  3487. else
  3488. {
  3489. apr_pool_t * cached_answer_pool;
  3490. // Nothing cached for this realm, prompt the user.
  3491. WEBDAV_ERR((*b->plaintext_passphrase_prompt_func)(
  3492. &may_save_passphrase,
  3493. realmstring,
  3494. b->prompt_baton,
  3495. pool));
  3496. cached_answer_pool = apr_hash_pool_get(b->plaintext_answers);
  3497. cached_answer = static_cast<bool *>(apr_pcalloc(cached_answer_pool,
  3498. sizeof(*cached_answer)));
  3499. *cached_answer = may_save_passphrase;
  3500. apr_hash_set(b->plaintext_answers, realmstring,
  3501. APR_HASH_KEY_STRING, cached_answer);
  3502. }
  3503. }
  3504. else
  3505. {
  3506. may_save_passphrase = FALSE;
  3507. }
  3508. }
  3509. else if (cstring_casecmp(store_ssl_client_cert_pp_plaintext,
  3510. WEBDAV_CONFIG_FALSE) == 0)
  3511. {
  3512. may_save_passphrase = FALSE;
  3513. }
  3514. else if (cstring_casecmp(store_ssl_client_cert_pp_plaintext,
  3515. WEBDAV_CONFIG_TRUE) == 0)
  3516. {
  3517. may_save_passphrase = TRUE;
  3518. }
  3519. else
  3520. {
  3521. return error_createf(WEBDAV_ERR_DAV_INVALID_CONFIG_VALUE, NULL,
  3522. "Config error: invalid value '%s' for option '%s'",
  3523. store_ssl_client_cert_pp_plaintext,
  3524. WEBDAV_AUTH_PARAM_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT);
  3525. }
  3526. }
  3527. if (may_save_passphrase)
  3528. {
  3529. WEBDAV_ERR(passphrase_set(saved, creds_hash, realmstring,
  3530. NULL, creds->password, parameters,
  3531. non_interactive, pool));
  3532. if (*saved && passtype)
  3533. {
  3534. apr_hash_set(creds_hash, AUTHN_PASSTYPE_KEY,
  3535. APR_HASH_KEY_STRING,
  3536. string_create(passtype, pool));
  3537. }
  3538. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
  3539. CONST_FS_KEY,
  3540. APR_HASH_KEY_STRING));
  3541. assert(fs);
  3542. // Save credentials to disk.
  3543. err = config_write_auth_data(creds_hash,
  3544. AUTH_CRED_SSL_CLIENT_CERT_PW,
  3545. realmstring, fs, pool);
  3546. error_clear(&err);
  3547. *saved = !err;
  3548. }
  3549. }
  3550. return WEBDAV_NO_ERROR;
  3551. }
  3552. // This implements the auth_provider_t.first_credentials API.
  3553. // It gets cached (unencrypted) credentials from the ssl client cert
  3554. // password provider's cache.
  3555. static error_t
  3556. ssl_client_cert_pw_file_first_credentials(
  3557. void ** credentials_p,
  3558. void ** iter_baton,
  3559. void * provider_baton,
  3560. apr_hash_t * parameters,
  3561. const char * realmstring,
  3562. apr_pool_t * pool)
  3563. {
  3564. return auth_ssl_client_cert_pw_file_first_creds_helper(
  3565. credentials_p,
  3566. iter_baton,
  3567. provider_baton,
  3568. parameters,
  3569. realmstring,
  3570. auth_ssl_client_cert_pw_get,
  3571. WEBDAV_AUTH_SIMPLE_PASSWORD_TYPE,
  3572. pool);
  3573. }
  3574. // This implements the auth_provider_t.save_credentials API.
  3575. // It saves the credentials unencrypted.
  3576. static error_t
  3577. ssl_client_cert_pw_file_save_credentials(
  3578. bool * saved,
  3579. void * credentials,
  3580. void * provider_baton,
  3581. apr_hash_t * parameters,
  3582. const char * realmstring,
  3583. apr_pool_t * pool)
  3584. {
  3585. return auth_ssl_client_cert_pw_file_save_creds_helper(
  3586. saved, credentials,
  3587. provider_baton,
  3588. parameters,
  3589. realmstring,
  3590. auth_ssl_client_cert_pw_set,
  3591. WEBDAV_AUTH_SIMPLE_PASSWORD_TYPE,
  3592. pool);
  3593. }
  3594. static const auth_provider_t ssl_client_cert_pw_file_provider =
  3595. {
  3596. AUTH_CRED_SSL_CLIENT_CERT_PW,
  3597. ssl_client_cert_pw_file_first_credentials,
  3598. NULL,
  3599. ssl_client_cert_pw_file_save_credentials
  3600. };
  3601. // Public API to SSL file providers.
  3602. static void
  3603. auth_get_ssl_client_cert_pw_file_provider2(
  3604. auth_provider_object_t ** provider,
  3605. auth_plaintext_passphrase_prompt_func_t plaintext_passphrase_prompt_func,
  3606. void * prompt_baton,
  3607. apr_pool_t * pool)
  3608. {
  3609. auth_provider_object_t * po =
  3610. static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
  3611. ssl_client_cert_pw_file_provider_baton_t * pb =
  3612. static_cast<ssl_client_cert_pw_file_provider_baton_t *>(apr_pcalloc(pool,
  3613. sizeof(*pb)));
  3614. pb->plaintext_passphrase_prompt_func = plaintext_passphrase_prompt_func;
  3615. pb->prompt_baton = prompt_baton;
  3616. pb->plaintext_answers = apr_hash_make(pool);
  3617. po->vtable = &ssl_client_cert_pw_file_provider;
  3618. po->provider_baton = pb;
  3619. *provider = po;
  3620. }
  3621. /*-----------------------------------------------------------------------*/
  3622. // Prompt provider
  3623. /*-----------------------------------------------------------------------*/
  3624. // Baton type for client passphrase prompting.
  3625. // There is no iteration baton type.
  3626. typedef struct ssl_client_cert_pw_prompt_provider_baton_t
  3627. {
  3628. auth_ssl_client_cert_pw_prompt_func_t prompt_func;
  3629. void * prompt_baton;
  3630. // how many times to re-prompt after the first one fails
  3631. int retry_limit;
  3632. } ssl_client_cert_pw_prompt_provider_baton_t;
  3633. // Iteration baton.
  3634. typedef struct ssl_client_cert_pw_prompt_iter_baton_t
  3635. {
  3636. // The original provider baton
  3637. ssl_client_cert_pw_prompt_provider_baton_t * pb;
  3638. // The original realmstring
  3639. const char * realmstring;
  3640. // how many times we've reprompted
  3641. int retries;
  3642. } ssl_client_cert_pw_prompt_iter_baton_t;
  3643. static error_t
  3644. ssl_client_cert_pw_prompt_first_cred(
  3645. void ** credentials_p,
  3646. void ** iter_baton,
  3647. void * provider_baton,
  3648. apr_hash_t * parameters,
  3649. const char * realmstring,
  3650. apr_pool_t * pool)
  3651. {
  3652. ssl_client_cert_pw_prompt_provider_baton_t * pb =
  3653. static_cast<ssl_client_cert_pw_prompt_provider_baton_t *>(provider_baton);
  3654. ssl_client_cert_pw_prompt_iter_baton_t * ib =
  3655. static_cast<ssl_client_cert_pw_prompt_iter_baton_t *>(apr_pcalloc(pool, sizeof(*ib)));
  3656. const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
  3657. WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
  3658. APR_HASH_KEY_STRING));
  3659. WEBDAV_ERR(pb->prompt_func((auth_cred_ssl_client_cert_pw_t **)
  3660. credentials_p, pb->prompt_baton, realmstring,
  3661. !no_auth_cache, pool));
  3662. ib->pb = pb;
  3663. ib->realmstring = apr_pstrdup(pool, realmstring);
  3664. ib->retries = 0;
  3665. *iter_baton = ib;
  3666. return WEBDAV_NO_ERROR;
  3667. }
  3668. static error_t
  3669. ssl_client_cert_pw_prompt_next_cred(
  3670. void ** credentials_p,
  3671. void * iter_baton,
  3672. void * provider_baton,
  3673. apr_hash_t * parameters,
  3674. const char * realmstring,
  3675. apr_pool_t * pool)
  3676. {
  3677. ssl_client_cert_pw_prompt_iter_baton_t * ib =
  3678. static_cast<ssl_client_cert_pw_prompt_iter_baton_t *>(iter_baton);
  3679. const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
  3680. WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
  3681. APR_HASH_KEY_STRING));
  3682. if ((ib->pb->retry_limit >= 0) && (ib->retries >= ib->pb->retry_limit))
  3683. {
  3684. // give up, go on to next provider.
  3685. *credentials_p = NULL;
  3686. return WEBDAV_NO_ERROR;
  3687. }
  3688. ib->retries++;
  3689. return ib->pb->prompt_func((auth_cred_ssl_client_cert_pw_t **)
  3690. credentials_p, ib->pb->prompt_baton,
  3691. ib->realmstring, !no_auth_cache, pool);
  3692. }
  3693. static const auth_provider_t client_cert_pw_prompt_provider =
  3694. {
  3695. AUTH_CRED_SSL_CLIENT_CERT_PW,
  3696. ssl_client_cert_pw_prompt_first_cred,
  3697. ssl_client_cert_pw_prompt_next_cred,
  3698. NULL
  3699. };
  3700. static void
  3701. auth_get_ssl_client_cert_pw_prompt_provider(
  3702. auth_provider_object_t ** provider,
  3703. auth_ssl_client_cert_pw_prompt_func_t prompt_func,
  3704. void * prompt_baton,
  3705. int retry_limit,
  3706. apr_pool_t * pool)
  3707. {
  3708. auth_provider_object_t * po =
  3709. static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
  3710. ssl_client_cert_pw_prompt_provider_baton_t * pb =
  3711. static_cast<ssl_client_cert_pw_prompt_provider_baton_t *>(apr_pcalloc(pool, sizeof(*pb)));
  3712. pb->prompt_func = prompt_func;
  3713. pb->prompt_baton = prompt_baton;
  3714. pb->retry_limit = retry_limit;
  3715. po->vtable = &client_cert_pw_prompt_provider;
  3716. po->provider_baton = pb;
  3717. *provider = po;
  3718. }
  3719. //------------------------------------------------------------------------------
  3720. // from win32_crypto.c
  3721. // The description string that's combined with unencrypted data by the
  3722. // Windows CryptoAPI. Used during decryption to verify that the
  3723. // encrypted data were valid.
  3724. static const WCHAR description[] = L"auth.simple.wincrypt";
  3725. // Implementation of auth_password_set_t that encrypts
  3726. // the incoming password using the Windows CryptoAPI.
  3727. static error_t
  3728. windows_password_encrypter(
  3729. bool * done,
  3730. apr_hash_t * creds,
  3731. const char * realmstring,
  3732. const char * username,
  3733. const char * in,
  3734. apr_hash_t * parameters,
  3735. bool non_interactive,
  3736. apr_pool_t * pool)
  3737. {
  3738. DATA_BLOB blobin;
  3739. DATA_BLOB blobout;
  3740. BOOL crypted = FALSE;
  3741. blobin.cbData = (DWORD)strlen(in);
  3742. blobin.pbData = (BYTE *) in;
  3743. crypted = CryptProtectData(&blobin, description, NULL, NULL, NULL,
  3744. CRYPTPROTECT_UI_FORBIDDEN, &blobout);
  3745. if (crypted)
  3746. {
  3747. char * coded = static_cast<char *>(apr_pcalloc(pool, apr_base64_encode_len(blobout.cbData)));
  3748. apr_base64_encode(coded, (const char *)blobout.pbData, blobout.cbData);
  3749. WEBDAV_ERR(auth_simple_password_set(done, creds, realmstring, username,
  3750. coded, parameters,
  3751. non_interactive, pool));
  3752. LocalFree(blobout.pbData);
  3753. }
  3754. return WEBDAV_NO_ERROR;
  3755. }
  3756. // Implementation of auth_password_get_t that decrypts
  3757. // the incoming password using the Windows CryptoAPI and verifies its
  3758. // validity.
  3759. static error_t
  3760. windows_password_decrypter(
  3761. bool * done,
  3762. const char ** out,
  3763. apr_hash_t * creds,
  3764. const char * realmstring,
  3765. const char * username,
  3766. apr_hash_t * parameters,
  3767. bool non_interactive,
  3768. apr_pool_t * pool)
  3769. {
  3770. DATA_BLOB blobin;
  3771. DATA_BLOB blobout;
  3772. LPWSTR descr;
  3773. BOOL decrypted = FALSE;
  3774. const char * in = NULL;
  3775. WEBDAV_ERR(auth_simple_password_get(done, &in, creds, realmstring, username,
  3776. parameters, non_interactive, pool));
  3777. if (!*done)
  3778. return WEBDAV_NO_ERROR;
  3779. blobin.cbData = (DWORD)strlen(in);
  3780. blobin.pbData = static_cast<BYTE *>(apr_pcalloc(pool, apr_base64_decode_len(in)));
  3781. apr_base64_decode((char *)blobin.pbData, in);
  3782. decrypted = CryptUnprotectData(&blobin, &descr, NULL, NULL, NULL,
  3783. CRYPTPROTECT_UI_FORBIDDEN, &blobout);
  3784. if (decrypted)
  3785. {
  3786. if (0 == lstrcmpW(descr, description))
  3787. *out = apr_pstrndup(pool, (const char *)blobout.pbData, blobout.cbData);
  3788. else
  3789. decrypted = FALSE;
  3790. LocalFree(blobout.pbData);
  3791. LocalFree(descr);
  3792. }
  3793. *done = decrypted != 0;
  3794. return WEBDAV_NO_ERROR;
  3795. }
  3796. // Get cached encrypted credentials from the simple provider's cache.
  3797. static error_t
  3798. windows_simple_first_creds(
  3799. void ** credentials,
  3800. void ** iter_baton,
  3801. void * provider_baton,
  3802. apr_hash_t * parameters,
  3803. const char * realmstring,
  3804. apr_pool_t * pool)
  3805. {
  3806. return auth_simple_first_creds_helper(credentials,
  3807. iter_baton,
  3808. provider_baton,
  3809. parameters,
  3810. realmstring,
  3811. windows_password_decrypter,
  3812. WEBDAV_AUTH_WINCRYPT_PASSWORD_TYPE,
  3813. pool);
  3814. }
  3815. // Save encrypted credentials to the simple provider's cache.
  3816. static error_t
  3817. windows_simple_save_creds(
  3818. bool * saved,
  3819. void * credentials,
  3820. void * provider_baton,
  3821. apr_hash_t * parameters,
  3822. const char * realmstring,
  3823. apr_pool_t * pool)
  3824. {
  3825. return auth_simple_save_creds_helper(saved, credentials,
  3826. provider_baton,
  3827. parameters,
  3828. realmstring,
  3829. windows_password_encrypter,
  3830. WEBDAV_AUTH_WINCRYPT_PASSWORD_TYPE,
  3831. pool);
  3832. }
  3833. static const auth_provider_t windows_simple_provider =
  3834. {
  3835. AUTH_CRED_SIMPLE,
  3836. windows_simple_first_creds,
  3837. NULL,
  3838. windows_simple_save_creds
  3839. };
  3840. // Public API
  3841. static void
  3842. auth_get_windows_simple_provider(
  3843. auth_provider_object_t ** provider,
  3844. apr_pool_t * pool)
  3845. {
  3846. auth_provider_object_t * po =
  3847. static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
  3848. po->vtable = &windows_simple_provider;
  3849. *provider = po;
  3850. }
  3851. /*-----------------------------------------------------------------------*/
  3852. // Windows SSL server trust provider, validates ssl certificate using
  3853. // CryptoApi.
  3854. /*-----------------------------------------------------------------------*/
  3855. // Implementation of auth_password_set_t that encrypts
  3856. // the incoming password using the Windows CryptoAPI.
  3857. static error_t
  3858. windows_ssl_client_cert_pw_encrypter(
  3859. bool * done,
  3860. apr_hash_t * creds,
  3861. const char * realmstring,
  3862. const char * username,
  3863. const char * in,
  3864. apr_hash_t * parameters,
  3865. bool non_interactive,
  3866. apr_pool_t * pool)
  3867. {
  3868. DATA_BLOB blobin;
  3869. DATA_BLOB blobout;
  3870. BOOL crypted;
  3871. blobin.cbData = (DWORD)strlen(in);
  3872. blobin.pbData = (BYTE *) in;
  3873. crypted = CryptProtectData(&blobin, description, NULL, NULL, NULL,
  3874. CRYPTPROTECT_UI_FORBIDDEN, &blobout);
  3875. if (crypted)
  3876. {
  3877. char * coded = static_cast<char *>(apr_pcalloc(pool, apr_base64_encode_len(blobout.cbData)));
  3878. apr_base64_encode(coded, (const char *)blobout.pbData, blobout.cbData);
  3879. WEBDAV_ERR(auth_ssl_client_cert_pw_set(done, creds, realmstring, username,
  3880. coded, parameters,
  3881. non_interactive, pool));
  3882. LocalFree(blobout.pbData);
  3883. }
  3884. return WEBDAV_NO_ERROR;
  3885. }
  3886. // Implementation of auth_password_get_t that decrypts
  3887. // the incoming password using the Windows CryptoAPI and verifies its
  3888. // validity.
  3889. static error_t
  3890. windows_ssl_client_cert_pw_decrypter(
  3891. bool * done,
  3892. const char ** out,
  3893. apr_hash_t * creds,
  3894. const char * realmstring,
  3895. const char * username,
  3896. apr_hash_t * parameters,
  3897. bool non_interactive,
  3898. apr_pool_t * pool)
  3899. {
  3900. DATA_BLOB blobin;
  3901. DATA_BLOB blobout;
  3902. LPWSTR descr;
  3903. BOOL decrypted;
  3904. const char * in = NULL;
  3905. WEBDAV_ERR(auth_ssl_client_cert_pw_get(done, &in, creds, realmstring, username,
  3906. parameters, non_interactive, pool));
  3907. if (!*done)
  3908. return WEBDAV_NO_ERROR;
  3909. blobin.cbData = (DWORD)strlen(in);
  3910. blobin.pbData = static_cast<BYTE *>(apr_pcalloc(pool, apr_base64_decode_len(in)));
  3911. apr_base64_decode((char *)blobin.pbData, in);
  3912. decrypted = CryptUnprotectData(&blobin, &descr, NULL, NULL, NULL,
  3913. CRYPTPROTECT_UI_FORBIDDEN, &blobout);
  3914. if (decrypted)
  3915. {
  3916. if (0 == lstrcmpW(descr, description))
  3917. *out = apr_pstrndup(pool, (const char *)blobout.pbData, blobout.cbData);
  3918. else
  3919. decrypted = FALSE;
  3920. LocalFree(blobout.pbData);
  3921. LocalFree(descr);
  3922. }
  3923. *done = decrypted != 0;
  3924. return WEBDAV_NO_ERROR;
  3925. }
  3926. // Get cached encrypted credentials from the simple provider's cache.
  3927. static error_t
  3928. windows_ssl_client_cert_pw_first_creds(
  3929. void ** credentials,
  3930. void ** iter_baton,
  3931. void * provider_baton,
  3932. apr_hash_t * parameters,
  3933. const char * realmstring,
  3934. apr_pool_t * pool)
  3935. {
  3936. return auth_ssl_client_cert_pw_file_first_creds_helper(
  3937. credentials,
  3938. iter_baton,
  3939. provider_baton,
  3940. parameters,
  3941. realmstring,
  3942. windows_ssl_client_cert_pw_decrypter,
  3943. WEBDAV_AUTH_WINCRYPT_PASSWORD_TYPE,
  3944. pool);
  3945. }
  3946. // Save encrypted credentials to the simple provider's cache.
  3947. static error_t
  3948. windows_ssl_client_cert_pw_save_creds(
  3949. bool * saved,
  3950. void * credentials,
  3951. void * provider_baton,
  3952. apr_hash_t * parameters,
  3953. const char * realmstring,
  3954. apr_pool_t * pool)
  3955. {
  3956. return auth_ssl_client_cert_pw_file_save_creds_helper(
  3957. saved,
  3958. credentials,
  3959. provider_baton,
  3960. parameters,
  3961. realmstring,
  3962. windows_ssl_client_cert_pw_encrypter,
  3963. WEBDAV_AUTH_WINCRYPT_PASSWORD_TYPE,
  3964. pool);
  3965. }
  3966. static const auth_provider_t windows_ssl_client_cert_pw_provider =
  3967. {
  3968. AUTH_CRED_SSL_CLIENT_CERT_PW,
  3969. windows_ssl_client_cert_pw_first_creds,
  3970. NULL,
  3971. windows_ssl_client_cert_pw_save_creds
  3972. };
  3973. // Public API
  3974. static void
  3975. auth_get_windows_ssl_client_cert_pw_provider(
  3976. auth_provider_object_t ** provider,
  3977. apr_pool_t * pool)
  3978. {
  3979. auth_provider_object_t * po =
  3980. static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
  3981. po->vtable = &windows_ssl_client_cert_pw_provider;
  3982. *provider = po;
  3983. }
  3984. /*-----------------------------------------------------------------------*/
  3985. // Windows SSL server trust provider, validates ssl certificate using
  3986. // CryptoApi.
  3987. /*-----------------------------------------------------------------------*/
  3988. // Helper to create CryptoAPI CERT_CONTEXT from base64 encoded BASE64_CERT.
  3989. // Returns NULL on error.
  3990. static PCCERT_CONTEXT
  3991. certcontext_from_base64(
  3992. const char * base64_cert,
  3993. apr_pool_t * pool)
  3994. {
  3995. PCCERT_CONTEXT cert_context = NULL;
  3996. int cert_len = 0;
  3997. BYTE * binary_cert = NULL;
  3998. // Use apr-util as CryptStringToBinaryA is available only on XP+.
  3999. binary_cert = static_cast<BYTE *>(apr_pcalloc(pool,
  4000. apr_base64_decode_len(base64_cert)));
  4001. cert_len = apr_base64_decode((char *)binary_cert, base64_cert);
  4002. // Parse the certificate into a context.
  4003. cert_context = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  4004. binary_cert, cert_len);
  4005. return cert_context;
  4006. }
  4007. // Helper for windows_ssl_server_trust_first_credentials for validating
  4008. // certificate using CryptoApi. Sets *OK_P to TRUE if base64 encoded ASCII_CERT
  4009. // certificate considered as valid.
  4010. static error_t
  4011. windows_validate_certificate(
  4012. bool * ok_p,
  4013. const char * ascii_cert,
  4014. apr_pool_t * pool)
  4015. {
  4016. PCCERT_CONTEXT cert_context = NULL;
  4017. CERT_CHAIN_PARA chain_para;
  4018. PCCERT_CHAIN_CONTEXT chain_context = NULL;
  4019. *ok_p = FALSE;
  4020. // Parse the certificate into a context.
  4021. cert_context = certcontext_from_base64(ascii_cert, pool);
  4022. if (cert_context)
  4023. {
  4024. // Retrieve the certificate chain of the certificate
  4025. // (a certificate without a valid root does not have a chain).
  4026. memset(&chain_para, 0, sizeof(chain_para));
  4027. chain_para.cbSize = sizeof(chain_para);
  4028. HCERTCHAINENGINE chain_engine;
  4029. CERT_CHAIN_ENGINE_CONFIG chain_config;
  4030. chain_config.cbSize = sizeof(CERT_CHAIN_ENGINE_CONFIG);
  4031. chain_config.hRestrictedRoot = NULL;
  4032. chain_config.hRestrictedTrust = NULL;
  4033. chain_config.hRestrictedOther = NULL;
  4034. chain_config.cAdditionalStore = 0;
  4035. chain_config.rghAdditionalStore = NULL;
  4036. chain_config.dwFlags = CERT_CHAIN_CACHE_END_CERT;
  4037. chain_config.dwUrlRetrievalTimeout = 0;
  4038. chain_config.MaximumCachedCertificates =0;
  4039. chain_config.CycleDetectionModulus = 0;
  4040. CertCreateCertificateChainEngine(
  4041. &chain_config,
  4042. &chain_engine);
  4043. if (CertGetCertificateChain(chain_engine, cert_context, NULL, NULL, &chain_para,
  4044. CERT_CHAIN_CACHE_END_CERT |
  4045. CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
  4046. NULL, &chain_context))
  4047. {
  4048. CERT_CHAIN_POLICY_PARA policy_para;
  4049. CERT_CHAIN_POLICY_STATUS policy_status;
  4050. policy_para.cbSize = sizeof(policy_para);
  4051. policy_para.dwFlags = 0;
  4052. policy_para.pvExtraPolicyPara = NULL;
  4053. policy_status.cbSize = sizeof(policy_status);
  4054. if (CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL,
  4055. chain_context, &policy_para,
  4056. &policy_status))
  4057. {
  4058. if (policy_status.dwError == S_OK)
  4059. {
  4060. // Windows thinks the certificate is valid.
  4061. *ok_p = TRUE;
  4062. }
  4063. }
  4064. CertFreeCertificateChain(chain_context);
  4065. }
  4066. CertFreeCertificateContext(cert_context);
  4067. CertFreeCertificateChainEngine(chain_engine);
  4068. }
  4069. return WEBDAV_NO_ERROR;
  4070. }
  4071. // Retrieve ssl server CA failure overrides (if any) from CryptoApi.
  4072. static error_t
  4073. windows_ssl_server_trust_first_credentials(
  4074. void ** credentials,
  4075. void ** iter_baton,
  4076. void * provider_baton,
  4077. apr_hash_t * parameters,
  4078. const char * realmstring,
  4079. apr_pool_t * pool)
  4080. {
  4081. apr_uint32_t * failures = static_cast<apr_uint32_t *>(apr_hash_get(parameters,
  4082. AUTH_PARAM_SSL_SERVER_FAILURES,
  4083. APR_HASH_KEY_STRING));
  4084. const auth_ssl_server_cert_info_t * cert_info =
  4085. static_cast<const auth_ssl_server_cert_info_t *>(apr_hash_get(parameters,
  4086. AUTH_PARAM_SSL_SERVER_CERT_INFO,
  4087. APR_HASH_KEY_STRING));
  4088. *credentials = NULL;
  4089. *iter_baton = NULL;
  4090. // We can accept only unknown certificate authority.
  4091. if (*failures & WEBDAV_AUTH_SSL_UNKNOWNCA)
  4092. {
  4093. bool ok;
  4094. WEBDAV_ERR(windows_validate_certificate(&ok, cert_info->ascii_cert, pool));
  4095. // Windows thinks that certificate is ok.
  4096. if (ok)
  4097. {
  4098. // Clear failure flag.
  4099. *failures &= ~WEBDAV_AUTH_SSL_UNKNOWNCA;
  4100. }
  4101. }
  4102. // If all failures are cleared now, we return the creds
  4103. if (!*failures)
  4104. {
  4105. auth_cred_ssl_server_trust_t * creds =
  4106. static_cast<auth_cred_ssl_server_trust_t *>(apr_pcalloc(pool, sizeof(*creds)));
  4107. creds->may_save = FALSE; // No need to save it.
  4108. *credentials = creds;
  4109. }
  4110. return WEBDAV_NO_ERROR;
  4111. }
  4112. static const auth_provider_t windows_server_trust_provider =
  4113. {
  4114. AUTH_CRED_SSL_SERVER_TRUST,
  4115. windows_ssl_server_trust_first_credentials,
  4116. NULL,
  4117. NULL,
  4118. };
  4119. // Public API
  4120. static void
  4121. auth_get_windows_ssl_server_trust_provider(
  4122. auth_provider_object_t ** provider,
  4123. apr_pool_t * pool)
  4124. {
  4125. auth_provider_object_t * po =
  4126. static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
  4127. po->vtable = &windows_server_trust_provider;
  4128. *provider = po;
  4129. }
  4130. //------------------------------------------------------------------------------
  4131. // from username_providers.c
  4132. // Username-only Provider
  4133. static error_t
  4134. username_first_creds(
  4135. void ** credentials,
  4136. void ** iter_baton,
  4137. void * provider_baton,
  4138. apr_hash_t * parameters,
  4139. const char * realmstring,
  4140. apr_pool_t * pool)
  4141. {
  4142. const char * username = static_cast<const char *>(apr_hash_get(parameters,
  4143. WEBDAV_AUTH_PARAM_DEFAULT_USERNAME,
  4144. APR_HASH_KEY_STRING));
  4145. bool may_save = !!username;
  4146. error_t err = 0;
  4147. // If we don't have a usename yet, try the auth cache
  4148. if (!username)
  4149. {
  4150. apr_hash_t * creds_hash = NULL;
  4151. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
  4152. CONST_FS_KEY,
  4153. APR_HASH_KEY_STRING));
  4154. assert(fs);
  4155. // Try to load credentials from a file on disk, based on the
  4156. // realmstring. Don't throw an error, though: if something went
  4157. // wrong reading the file, no big deal. What really matters is that
  4158. // we failed to get the creds, so allow the auth system to try the
  4159. // next provider.
  4160. err = config_read_auth_data(&creds_hash, WEBDAV_AUTH_CRED_USERNAME,
  4161. realmstring, fs,
  4162. pool);
  4163. error_clear(&err);
  4164. if (!err && creds_hash)
  4165. {
  4166. string_t * str = static_cast<string_t *>(apr_hash_get(creds_hash, AUTHN_USERNAME_KEY,
  4167. APR_HASH_KEY_STRING));
  4168. if (str && str->data)
  4169. username = str->data;
  4170. }
  4171. }
  4172. // If that failed, ask the OS for the username
  4173. if (!username)
  4174. username = user_get_name(pool);
  4175. if (username)
  4176. {
  4177. auth_cred_simple_t * creds =
  4178. static_cast<auth_cred_simple_t *>(apr_pcalloc(pool, sizeof(*creds)));
  4179. creds->username = username;
  4180. creds->may_save = may_save;
  4181. *credentials = creds;
  4182. }
  4183. else
  4184. *credentials = NULL;
  4185. *iter_baton = NULL;
  4186. return WEBDAV_NO_ERROR;
  4187. }
  4188. static error_t
  4189. username_save_creds(
  4190. bool * saved,
  4191. void * credentials,
  4192. void * provider_baton,
  4193. apr_hash_t * parameters,
  4194. const char * realmstring,
  4195. apr_pool_t * pool)
  4196. {
  4197. auth_cred_simple_t * creds =
  4198. static_cast<auth_cred_simple_t *>(credentials);
  4199. apr_hash_t * creds_hash = NULL;
  4200. error_t err;
  4201. *saved = FALSE;
  4202. if (!creds->may_save)
  4203. return WEBDAV_NO_ERROR;
  4204. // Put the credentials in a hash and save it to disk
  4205. creds_hash = apr_hash_make(pool);
  4206. apr_hash_set(creds_hash, AUTHN_USERNAME_KEY, APR_HASH_KEY_STRING,
  4207. string_create(creds->username, pool));
  4208. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
  4209. CONST_FS_KEY,
  4210. APR_HASH_KEY_STRING));
  4211. assert(fs);
  4212. err = config_write_auth_data(creds_hash, WEBDAV_AUTH_CRED_USERNAME,
  4213. realmstring,
  4214. fs,
  4215. pool);
  4216. error_clear(&err);
  4217. *saved = !err;
  4218. return WEBDAV_NO_ERROR;
  4219. }
  4220. static const auth_provider_t username_provider =
  4221. {
  4222. WEBDAV_AUTH_CRED_USERNAME,
  4223. username_first_creds,
  4224. NULL,
  4225. username_save_creds
  4226. };
  4227. // Public API
  4228. static void
  4229. auth_get_username_provider(
  4230. auth_provider_object_t ** provider,
  4231. apr_pool_t * pool)
  4232. {
  4233. auth_provider_object_t * po =
  4234. static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
  4235. po->vtable = &username_provider;
  4236. *provider = po;
  4237. }
  4238. // Baton type for username-only prompting.
  4239. typedef struct username_prompt_provider_baton_t
  4240. {
  4241. auth_username_prompt_func_t prompt_func;
  4242. void * prompt_baton;
  4243. // how many times to re-prompt after the first one fails
  4244. int retry_limit;
  4245. } username_prompt_provider_baton_t;
  4246. // Iteration baton type for username-only prompting.
  4247. typedef struct username_prompt_iter_baton_t
  4248. {
  4249. // how many times we've reprompted
  4250. int retries;
  4251. } username_prompt_iter_baton_t;
  4252. // Helper Functions
  4253. static error_t
  4254. prompt_for_username_creds(
  4255. auth_cred_username_t ** cred_p,
  4256. username_prompt_provider_baton_t * pb,
  4257. apr_hash_t * parameters,
  4258. const char * realmstring,
  4259. bool first_time,
  4260. bool may_save,
  4261. apr_pool_t * pool)
  4262. {
  4263. const char * def_username = NULL;
  4264. *cred_p = NULL;
  4265. // If we're allowed to check for default usernames, do so.
  4266. if (first_time)
  4267. def_username = static_cast<const char *>(apr_hash_get(parameters,
  4268. WEBDAV_AUTH_PARAM_DEFAULT_USERNAME,
  4269. APR_HASH_KEY_STRING));
  4270. // If we have defaults, just build the cred here and return it.
  4271. // I do wonder why this is here instead of in a separate
  4272. // 'defaults' provider that would run before the prompt
  4273. // provider... Hmmm.
  4274. if (def_username)
  4275. {
  4276. *cred_p = static_cast<auth_cred_username_t *>(apr_pcalloc(pool, sizeof(**cred_p)));
  4277. (*cred_p)->username = apr_pstrdup(pool, def_username);
  4278. (*cred_p)->may_save = TRUE;
  4279. }
  4280. else
  4281. {
  4282. WEBDAV_ERR(pb->prompt_func(cred_p, pb->prompt_baton, realmstring,
  4283. may_save, pool));
  4284. }
  4285. return WEBDAV_NO_ERROR;
  4286. }
  4287. // Our first attempt will use any default username passed
  4288. // in, and prompt for the remaining stuff.
  4289. static error_t
  4290. username_prompt_first_creds(
  4291. void ** credentials_p,
  4292. void ** iter_baton,
  4293. void * provider_baton,
  4294. apr_hash_t * parameters,
  4295. const char * realmstring,
  4296. apr_pool_t * pool)
  4297. {
  4298. username_prompt_provider_baton_t * pb =
  4299. static_cast<username_prompt_provider_baton_t *>(provider_baton);
  4300. username_prompt_iter_baton_t * ibaton =
  4301. static_cast<username_prompt_iter_baton_t *>(apr_pcalloc(pool, sizeof(*ibaton)));
  4302. const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
  4303. WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
  4304. APR_HASH_KEY_STRING));
  4305. WEBDAV_ERR(prompt_for_username_creds((auth_cred_username_t **) credentials_p, pb,
  4306. parameters, realmstring, TRUE, !no_auth_cache, pool));
  4307. ibaton->retries = 0;
  4308. *iter_baton = ibaton;
  4309. return WEBDAV_NO_ERROR;
  4310. }
  4311. // Subsequent attempts to fetch will ignore the default username
  4312. // value, and simply re-prompt for the username, up to a maximum of
  4313. // ib->pb->retry_limit.
  4314. static error_t
  4315. username_prompt_next_creds(
  4316. void ** credentials_p,
  4317. void * iter_baton,
  4318. void * provider_baton,
  4319. apr_hash_t * parameters,
  4320. const char * realmstring,
  4321. apr_pool_t * pool)
  4322. {
  4323. username_prompt_iter_baton_t * ib =
  4324. static_cast<username_prompt_iter_baton_t *>(iter_baton);
  4325. username_prompt_provider_baton_t * pb =
  4326. static_cast<username_prompt_provider_baton_t *>(provider_baton);
  4327. const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
  4328. WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
  4329. APR_HASH_KEY_STRING));
  4330. if ((pb->retry_limit >= 0) && (ib->retries >= pb->retry_limit))
  4331. {
  4332. // give up, go on to next provider.
  4333. *credentials_p = NULL;
  4334. return WEBDAV_NO_ERROR;
  4335. }
  4336. ib->retries++;
  4337. return prompt_for_username_creds((auth_cred_username_t **) credentials_p, pb,
  4338. parameters, realmstring, FALSE, !no_auth_cache, pool);
  4339. }
  4340. static const auth_provider_t username_prompt_provider =
  4341. {
  4342. WEBDAV_AUTH_CRED_USERNAME,
  4343. username_prompt_first_creds,
  4344. username_prompt_next_creds,
  4345. NULL,
  4346. };
  4347. // Public API
  4348. static void
  4349. auth_get_username_prompt_provider(
  4350. auth_provider_object_t ** provider,
  4351. auth_username_prompt_func_t prompt_func,
  4352. void * prompt_baton,
  4353. int retry_limit,
  4354. apr_pool_t * pool)
  4355. {
  4356. auth_provider_object_t * po =
  4357. static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
  4358. username_prompt_provider_baton_t * pb =
  4359. static_cast<username_prompt_provider_baton_t *>(apr_pcalloc(pool, sizeof(*pb)));
  4360. pb->prompt_func = prompt_func;
  4361. pb->prompt_baton = prompt_baton;
  4362. pb->retry_limit = retry_limit;
  4363. po->vtable = &username_prompt_provider;
  4364. po->provider_baton = pb;
  4365. *provider = po;
  4366. }
  4367. //------------------------------------------------------------------------------
  4368. // from auth.c
  4369. static void
  4370. auth_baton_set_parameter(
  4371. auth_baton_t * auth_baton,
  4372. const char * name,
  4373. const void * value)
  4374. {
  4375. apr_hash_set(auth_baton->parameters, name, APR_HASH_KEY_STRING, value);
  4376. }
  4377. static const void *
  4378. auth_baton_get_parameter(
  4379. auth_baton_t * auth_baton,
  4380. const char * name)
  4381. {
  4382. return apr_hash_get(auth_baton->parameters, name, APR_HASH_KEY_STRING);
  4383. }
  4384. static error_t
  4385. auth_first_credentials(
  4386. void ** credentials,
  4387. auth_iterstate_t ** state,
  4388. const char * cred_kind,
  4389. const char * realmstring,
  4390. auth_baton_t * auth_baton,
  4391. apr_pool_t * pool)
  4392. {
  4393. int i = 0;
  4394. provider_set_t * table = NULL;
  4395. auth_provider_object_t * provider = NULL;
  4396. void * creds = NULL;
  4397. void * iter_baton = NULL;
  4398. bool got_first = FALSE;
  4399. auth_iterstate_t * iterstate = NULL;
  4400. const char * cache_key = NULL;
  4401. // Get the appropriate table of providers for CRED_KIND.
  4402. table = static_cast<provider_set_t *>(apr_hash_get(auth_baton->tables, cred_kind, APR_HASH_KEY_STRING));
  4403. if (!table)
  4404. return error_createf(WEBDAV_ERR_AUTHN_NO_PROVIDER, NULL,
  4405. "No provider registered for '%s' credentials",
  4406. cred_kind);
  4407. // First, see if we have cached creds in the auth_baton.
  4408. cache_key = apr_pstrcat(pool, cred_kind, ":", realmstring, (char *)NULL);
  4409. creds = static_cast<void *>(apr_hash_get(auth_baton->creds_cache,
  4410. cache_key, APR_HASH_KEY_STRING));
  4411. if (creds)
  4412. {
  4413. got_first = false;
  4414. }
  4415. else
  4416. // If not, find a provider that can give "first" credentials.
  4417. {
  4418. // Find a provider that can give "first" credentials.
  4419. for (i = 0; i < table->providers->nelts; i++)
  4420. {
  4421. provider = APR_ARRAY_IDX(table->providers, i,
  4422. auth_provider_object_t *);
  4423. WEBDAV_ERR(provider->vtable->first_credentials(
  4424. &creds, &iter_baton, provider->provider_baton,
  4425. auth_baton->parameters, realmstring, auth_baton->pool));
  4426. if (creds != NULL)
  4427. {
  4428. got_first = true;
  4429. break;
  4430. }
  4431. }
  4432. }
  4433. if (!creds)
  4434. *state = NULL;
  4435. else
  4436. {
  4437. // Build an abstract iteration state.
  4438. iterstate = static_cast<auth_iterstate_t *>(apr_pcalloc(pool, sizeof(*iterstate)));
  4439. iterstate->table = table;
  4440. iterstate->provider_idx = i;
  4441. iterstate->got_first = got_first;
  4442. iterstate->provider_iter_baton = iter_baton;
  4443. iterstate->realmstring = apr_pstrdup(pool, realmstring);
  4444. iterstate->cache_key = cache_key;
  4445. iterstate->auth_baton = auth_baton;
  4446. *state = iterstate;
  4447. // Put the creds in the cache
  4448. apr_hash_set(auth_baton->creds_cache,
  4449. apr_pstrdup(auth_baton->pool, cache_key),
  4450. APR_HASH_KEY_STRING,
  4451. creds);
  4452. }
  4453. *credentials = creds;
  4454. return WEBDAV_NO_ERROR;
  4455. }
  4456. static error_t
  4457. auth_next_credentials(
  4458. void ** credentials,
  4459. auth_iterstate_t * state,
  4460. apr_pool_t * pool)
  4461. {
  4462. auth_baton_t * auth_baton = state->auth_baton;
  4463. auth_provider_object_t * provider = NULL;
  4464. provider_set_t * table = state->table;
  4465. void * creds = NULL;
  4466. // Continue traversing the table from where we left off.
  4467. for (/* no init */;
  4468. state->provider_idx < table->providers->nelts;
  4469. state->provider_idx++)
  4470. {
  4471. provider = APR_ARRAY_IDX(table->providers,
  4472. state->provider_idx,
  4473. auth_provider_object_t *);
  4474. if (!state->got_first)
  4475. {
  4476. WEBDAV_ERR(provider->vtable->first_credentials(
  4477. &creds, &(state->provider_iter_baton),
  4478. provider->provider_baton, auth_baton->parameters,
  4479. state->realmstring, auth_baton->pool));
  4480. state->got_first = TRUE;
  4481. }
  4482. else
  4483. {
  4484. if (provider->vtable->next_credentials)
  4485. WEBDAV_ERR(provider->vtable->next_credentials(
  4486. &creds, state->provider_iter_baton,
  4487. provider->provider_baton, auth_baton->parameters,
  4488. state->realmstring, auth_baton->pool));
  4489. }
  4490. if (creds != NULL)
  4491. {
  4492. // Put the creds in the cache
  4493. apr_hash_set(auth_baton->creds_cache,
  4494. state->cache_key, APR_HASH_KEY_STRING,
  4495. creds);
  4496. break;
  4497. }
  4498. state->got_first = FALSE;
  4499. }
  4500. *credentials = creds;
  4501. return WEBDAV_NO_ERROR;
  4502. }
  4503. static error_t
  4504. auth_save_credentials(
  4505. auth_iterstate_t * state,
  4506. apr_pool_t * pool)
  4507. {
  4508. int i = 0;
  4509. auth_provider_object_t * provider = NULL;
  4510. bool save_succeeded = FALSE;
  4511. const char * no_auth_cache = NULL;
  4512. auth_baton_t * auth_baton = NULL;
  4513. void * creds = NULL;
  4514. if (!state || state->table->providers->nelts <= state->provider_idx)
  4515. return WEBDAV_NO_ERROR;
  4516. auth_baton = state->auth_baton;
  4517. creds = apr_hash_get(state->auth_baton->creds_cache,
  4518. state->cache_key, APR_HASH_KEY_STRING);
  4519. if (!creds)
  4520. return WEBDAV_NO_ERROR;
  4521. // Do not save the creds if AUTH_PARAM_NO_AUTH_CACHE is set
  4522. no_auth_cache = static_cast<const char *>(apr_hash_get(auth_baton->parameters,
  4523. AUTH_PARAM_NO_AUTH_CACHE,
  4524. APR_HASH_KEY_STRING));
  4525. if (no_auth_cache)
  4526. return WEBDAV_NO_ERROR;
  4527. // First, try to save the creds using the provider that produced them.
  4528. provider = APR_ARRAY_IDX(state->table->providers,
  4529. state->provider_idx,
  4530. auth_provider_object_t *);
  4531. if (provider->vtable->save_credentials)
  4532. WEBDAV_ERR(provider->vtable->save_credentials(&save_succeeded,
  4533. creds,
  4534. provider->provider_baton,
  4535. auth_baton->parameters,
  4536. state->realmstring,
  4537. pool));
  4538. if (save_succeeded)
  4539. return WEBDAV_NO_ERROR;
  4540. // Otherwise, loop from the top of the list, asking every provider
  4541. // to attempt a save. todo: someday optimize so we don't
  4542. // necessarily start from the top of the list.
  4543. for (i = 0; i < state->table->providers->nelts; i++)
  4544. {
  4545. provider = APR_ARRAY_IDX(state->table->providers, i,
  4546. auth_provider_object_t *);
  4547. if (provider->vtable->save_credentials)
  4548. WEBDAV_ERR(provider->vtable->save_credentials(
  4549. &save_succeeded, creds,
  4550. provider->provider_baton,
  4551. auth_baton->parameters,
  4552. state->realmstring,
  4553. pool));
  4554. if (save_succeeded)
  4555. break;
  4556. }
  4557. // notice that at the moment, if no provider can save, there's
  4558. // no way the caller will know.
  4559. return WEBDAV_NO_ERROR;
  4560. }
  4561. static error_t
  4562. auth_get_platform_specific_provider(
  4563. auth_provider_object_t ** provider,
  4564. const char * provider_name,
  4565. const char * provider_type,
  4566. apr_pool_t * pool)
  4567. {
  4568. *provider = NULL;
  4569. {
  4570. if (strcmp(provider_name, "windows") == 0 &&
  4571. strcmp(provider_type, "simple") == 0)
  4572. {
  4573. auth_get_windows_simple_provider(provider, pool);
  4574. }
  4575. else if (strcmp(provider_name, "windows") == 0 &&
  4576. strcmp(provider_type, "ssl_client_cert_pw") == 0)
  4577. {
  4578. auth_get_windows_ssl_client_cert_pw_provider(provider, pool);
  4579. }
  4580. else if (strcmp(provider_name, "windows") == 0 &&
  4581. strcmp(provider_type, "ssl_server_trust") == 0)
  4582. {
  4583. auth_get_windows_ssl_server_trust_provider(provider, pool);
  4584. }
  4585. }
  4586. return WEBDAV_NO_ERROR;
  4587. }
  4588. #define WEBDAV_MAYBE_ADD_PROVIDER(list, p) \
  4589. { if (p) APR_ARRAY_PUSH(list, auth_provider_object_t *) = p; }
  4590. static error_t
  4591. auth_get_platform_specific_client_providers(
  4592. apr_array_header_t ** providers,
  4593. apr_pool_t * pool)
  4594. {
  4595. auth_provider_object_t * provider;
  4596. const char * password_stores_config_option;
  4597. apr_array_header_t * password_stores;
  4598. int i;
  4599. password_stores_config_option = "windows-cryptoapi";
  4600. *providers = apr_array_make(pool, 12, sizeof(auth_provider_object_t *));
  4601. password_stores = cstring_split(password_stores_config_option, " ,", TRUE, pool);
  4602. for (i = 0; i < password_stores->nelts; i++)
  4603. {
  4604. const char * password_store = APR_ARRAY_IDX(password_stores, i,
  4605. const char *);
  4606. // Windows
  4607. if (apr_strnatcmp(password_store, "windows-cryptoapi") == 0)
  4608. {
  4609. WEBDAV_ERR(auth_get_platform_specific_provider(&provider,
  4610. "windows",
  4611. "simple",
  4612. pool));
  4613. WEBDAV_MAYBE_ADD_PROVIDER(*providers, provider);
  4614. WEBDAV_ERR(auth_get_platform_specific_provider(&provider,
  4615. "windows",
  4616. "ssl_client_cert_pw",
  4617. pool));
  4618. WEBDAV_MAYBE_ADD_PROVIDER(*providers, provider);
  4619. continue;
  4620. }
  4621. return error_createf(WEBDAV_ERR_BAD_CONFIG_VALUE, NULL,
  4622. "Invalid config: unknown password store "
  4623. "'%s'",
  4624. password_store);
  4625. }
  4626. return WEBDAV_NO_ERROR;
  4627. }
  4628. //------------------------------------------------------------------------------
  4629. // from dirent_uri.c
  4630. // TRUE if s is the canonical empty path, FALSE otherwise
  4631. #define PATH_IS_EMPTY(s) ((s)[0] == '\0')
  4632. // Path separator for local filesystem
  4633. #define WEBDAV_PATH_LOCAL_SEPARATOR '\\'
  4634. // Path type definition. Used only by internal functions.
  4635. typedef enum path_type_t
  4636. {
  4637. type_uri,
  4638. type_dirent,
  4639. type_relpath
  4640. } path_type_t;
  4641. // Locale insensitive tolower() for converting parts of dirents and urls
  4642. // while canonicalizing
  4643. static char
  4644. canonicalize_to_lower(char c)
  4645. {
  4646. if (c < 'A' || c > 'Z')
  4647. return c;
  4648. else
  4649. return c - 'A' + 'a';
  4650. }
  4651. // Locale insensitive toupper() for converting parts of dirents and urls
  4652. // while canonicalizing
  4653. static char
  4654. canonicalize_to_upper(char c)
  4655. {
  4656. if (c < 'a' || c > 'z')
  4657. return c;
  4658. else
  4659. return c - 'a' + 'A';
  4660. }
  4661. // Return the canonicalized version of PATH, of type TYPE, allocated in POOL.
  4662. static const char *
  4663. canonicalize(
  4664. path_type_t type,
  4665. const char * path,
  4666. apr_pool_t * pool)
  4667. {
  4668. char * canon = NULL, *dst = NULL;
  4669. const char * src = NULL;
  4670. size_t seglen = 0;
  4671. size_t schemelen = 0;
  4672. size_t canon_segments = 0;
  4673. bool url = FALSE;
  4674. char * schema_data = NULL;
  4675. // "" is already canonical, so just return it; note that later code
  4676. // depends on path not being zero-length.
  4677. if (PATH_IS_EMPTY(path))
  4678. {
  4679. assert(type != type_uri);
  4680. return "";
  4681. }
  4682. dst = canon = static_cast<char *>(apr_pcalloc(pool, strlen(path) + 1));
  4683. // If this is supposed to be an URI, it should start with
  4684. // "scheme://". We'll copy the scheme, host name, etc. to DST and
  4685. // set URL = TRUE.
  4686. src = path;
  4687. if (type == type_uri)
  4688. {
  4689. assert(*src != '/');
  4690. while (*src && (*src != '/') && (*src != ':'))
  4691. src++;
  4692. if ((*src == ':') && (*(src+1) == '/') && (*(src+2) == '/'))
  4693. {
  4694. const char * seg;
  4695. url = TRUE;
  4696. // Found a scheme, convert to lowercase and copy to dst.
  4697. src = path;
  4698. while (*src != ':')
  4699. {
  4700. *(dst++) = canonicalize_to_lower((*src++));
  4701. schemelen++;
  4702. }
  4703. *(dst++) = ':';
  4704. *(dst++) = '/';
  4705. *(dst++) = '/';
  4706. src += 3;
  4707. schemelen += 3;
  4708. // This might be the hostname
  4709. seg = src;
  4710. while (*src && (*src != '/') && (*src != '@'))
  4711. src++;
  4712. if (*src == '@')
  4713. {
  4714. // Copy the username & password.
  4715. seglen = src - seg + 1;
  4716. memcpy(dst, seg, seglen);
  4717. dst += seglen;
  4718. src++;
  4719. }
  4720. else
  4721. src = seg;
  4722. // Found a hostname, convert to lowercase and copy to dst.
  4723. while (*src && (*src != '/') && (*src != ':'))
  4724. *(dst++) = canonicalize_to_lower((*src++));
  4725. if (*src == ':')
  4726. {
  4727. // We probably have a port number: Is it a default portnumber
  4728. // which doesn't belong in a canonical url?
  4729. if ((src[1] == '8') && (src[2] == '0') &&
  4730. ((src[3] == '/') || !src[3]) &&
  4731. !strncmp(canon, "http:", 5))
  4732. {
  4733. src += 3;
  4734. }
  4735. else if ((src[1] == '4') && (src[2] == '4') && (src[3] == '3') &&
  4736. ((src[4] == '/') || !src[4]) &&
  4737. !strncmp(canon, "https:", 6))
  4738. {
  4739. src += 4;
  4740. }
  4741. else if ((src[1] == '/') || !src[1])
  4742. {
  4743. src += 1;
  4744. }
  4745. while (*src && (*src != '/'))
  4746. *(dst++) = canonicalize_to_lower((*src++));
  4747. }
  4748. // Copy trailing slash, or null-terminator.
  4749. *(dst) = *(src);
  4750. // Move src and dst forward only if we are not
  4751. // at null-terminator yet.
  4752. if (*src)
  4753. {
  4754. src++;
  4755. dst++;
  4756. schema_data = dst;
  4757. }
  4758. canon_segments = 1;
  4759. }
  4760. }
  4761. // Copy to DST any separator or drive letter that must come before the
  4762. // first regular path segment.
  4763. if (!url && type != type_relpath)
  4764. {
  4765. src = path;
  4766. // If this is an absolute path, then just copy over the initial
  4767. // separator character.
  4768. if (*src == '/')
  4769. {
  4770. *(dst++) = *(src++);
  4771. // On Windows permit two leading separator characters which means an
  4772. // UNC path.
  4773. if ((type == type_dirent) && (*src == '/'))
  4774. *(dst++) = *(src++);
  4775. }
  4776. // On Windows the first segment can be a drive letter, which we normalize
  4777. // to upper case.
  4778. else if ((type == type_dirent) &&
  4779. ((*src >= 'a' && *src <= 'z') ||
  4780. (*src >= 'A' && *src <= 'Z')) &&
  4781. (src[1] == ':'))
  4782. {
  4783. *(dst++) = canonicalize_to_upper(*(src++));
  4784. // Leave the ':' to be processed as (or as part of) a path segment
  4785. // by the following code block, so we need not care whether it has
  4786. // a slash after it.
  4787. }
  4788. }
  4789. while (*src)
  4790. {
  4791. // Parse each segment, finding the closing '/' (which might look
  4792. // like '%2F' for URIs).
  4793. const char * next = src;
  4794. size_t slash_len = 0;
  4795. while (*next &&
  4796. (next[0] != '/') &&
  4797. (!((type == type_uri) && (next[0] == '%') && (next[1] == '2') &&
  4798. (canonicalize_to_upper(next[2]) == 'F'))))
  4799. {
  4800. ++next;
  4801. }
  4802. // Record how long our "slash" is.
  4803. if (next[0] == '/')
  4804. slash_len = 1;
  4805. else if ((type == type_uri) && (next[0] == '%'))
  4806. slash_len = 3;
  4807. seglen = next - src;
  4808. if ((seglen == 0) ||
  4809. ((seglen == 1) && (src[0] == '.')) ||
  4810. ((type == type_uri) && (seglen == 3) && (src[0] == '%') && (src[1] == '2') &&
  4811. (canonicalize_to_upper(src[2]) == 'E')))
  4812. {
  4813. // Empty or noop segment, so do nothing. (For URIs, '%2E'
  4814. // is equivalent to '.').
  4815. }
  4816. // If this is the first path segment of a file:// URI and it contains a
  4817. // windows drive letter, convert the drive letter to upper case.
  4818. else if (url && (canon_segments == 1) && (seglen == 2) &&
  4819. (strncmp(canon, "file:", 5) == 0) &&
  4820. (src[0] >= 'a') && (src[0] <= 'z') && (src[1] == ':'))
  4821. {
  4822. *(dst++) = canonicalize_to_upper(src[0]);
  4823. *(dst++) = ':';
  4824. if (*next)
  4825. *(dst++) = *next;
  4826. canon_segments++;
  4827. }
  4828. else
  4829. {
  4830. // An actual segment, append it to the destination path
  4831. memcpy(dst, src, seglen);
  4832. dst += seglen;
  4833. if (slash_len)
  4834. {
  4835. *(dst++) = '/';
  4836. }
  4837. canon_segments++;
  4838. }
  4839. // Skip over trailing slash to the next segment.
  4840. src = next + slash_len;
  4841. }
  4842. *dst = '\0';
  4843. // Skip leading double slashes when there are less than 2
  4844. // canon segments. UNC paths *MUST* have two segments.
  4845. if ((type == type_dirent) && (canon[0] == '/') && (canon[1] == '/'))
  4846. {
  4847. if (canon_segments < 2)
  4848. return canon + 1;
  4849. else
  4850. {
  4851. // Now we're sure this is a valid UNC path, convert the server name
  4852. // (the first path segment) to lowercase as Windows treats it as case
  4853. // insensitive.
  4854. // Note: normally the share name is treated as case insensitive too,
  4855. // but it seems to be possible to configure Samba to treat those as
  4856. // case sensitive, so better leave that alone.
  4857. for (dst = canon + 2; *dst && (*dst != '/'); dst++)
  4858. *dst = canonicalize_to_lower(*dst);
  4859. }
  4860. }
  4861. // Check the normalization of characters in a uri
  4862. if (schema_data)
  4863. {
  4864. int need_extra = 0;
  4865. src = schema_data;
  4866. while (*src)
  4867. {
  4868. switch (*src)
  4869. {
  4870. case '/':
  4871. break;
  4872. case '%':
  4873. if (!ctype_isxdigit(*(src+1)) ||
  4874. !ctype_isxdigit(*(src+2)))
  4875. need_extra += 2;
  4876. else
  4877. src += 2;
  4878. break;
  4879. default:
  4880. if (!uri_char_validity[(unsigned char)*src])
  4881. need_extra += 2;
  4882. break;
  4883. }
  4884. src++;
  4885. }
  4886. if (need_extra > 0)
  4887. {
  4888. size_t pre_schema_size = (size_t)(schema_data - canon);
  4889. dst = static_cast<char *>(apr_pcalloc(pool, (size_t)(src - canon) + need_extra + 1));
  4890. memcpy(dst, canon, pre_schema_size);
  4891. canon = dst;
  4892. dst += pre_schema_size;
  4893. }
  4894. else
  4895. dst = schema_data;
  4896. src = schema_data;
  4897. while (*src)
  4898. {
  4899. switch (*src)
  4900. {
  4901. case '/':
  4902. *(dst++) = '/';
  4903. break;
  4904. case '%':
  4905. if (!ctype_isxdigit(*(src+1)) ||
  4906. !ctype_isxdigit(*(src+2)))
  4907. {
  4908. *(dst++) = '%';
  4909. *(dst++) = '2';
  4910. *(dst++) = '5';
  4911. }
  4912. else
  4913. {
  4914. char digitz[3];
  4915. int val;
  4916. digitz[0] = *(++src);
  4917. digitz[1] = *(++src);
  4918. digitz[2] = 0;
  4919. val = (int)strtol(digitz, NULL, 16);
  4920. if (uri_char_validity[(unsigned char)val])
  4921. *(dst++) = (char)val;
  4922. else
  4923. {
  4924. *(dst++) = '%';
  4925. *(dst++) = canonicalize_to_upper(digitz[0]);
  4926. *(dst++) = canonicalize_to_upper(digitz[1]);
  4927. }
  4928. }
  4929. break;
  4930. default:
  4931. if (!uri_char_validity[(unsigned char)*src])
  4932. {
  4933. apr_snprintf(dst, 4, "%%%02X", (unsigned char)*src);
  4934. dst += 3;
  4935. }
  4936. else
  4937. *(dst++) = *src;
  4938. break;
  4939. }
  4940. src++;
  4941. }
  4942. *dst = '\0';
  4943. }
  4944. return canon;
  4945. }
  4946. static const char *
  4947. uri_canonicalize(
  4948. const char * uri,
  4949. apr_pool_t * pool)
  4950. {
  4951. return canonicalize(type_uri, uri, pool);
  4952. }
  4953. static const char *
  4954. relpath_canonicalize(
  4955. const char * relpath,
  4956. apr_pool_t * pool)
  4957. {
  4958. return canonicalize(type_relpath, relpath, pool);
  4959. }
  4960. static const char *
  4961. fspath_canonicalize(
  4962. const char * fspath,
  4963. apr_pool_t * pool)
  4964. {
  4965. if ((fspath[0] == '/') && (fspath[1] == '\0'))
  4966. return "/";
  4967. return apr_pstrcat(pool, "/", relpath_canonicalize(fspath, pool),
  4968. (char *)NULL);
  4969. }
  4970. // Examine PATH as a potential URI, and return a substring of PATH
  4971. // that immediately follows the (scheme):// portion of the URI, or
  4972. // NULL if PATH doesn't appear to be a valid URI. The returned value
  4973. // is not allocated -- it shares memory with PATH.
  4974. static const char *
  4975. skip_uri_scheme(
  4976. const char * path)
  4977. {
  4978. size_t j = 0;
  4979. // A scheme is terminated by a : and cannot contain any /'s.
  4980. for (j = 0; path[j] && (path[j] != ':'); ++j)
  4981. if (path[j] == '/')
  4982. return NULL;
  4983. if ((j > 0) && (path[j] == ':') && (path[j+1] == '/') && (path[j+2] == '/'))
  4984. return path + j + 3;
  4985. return NULL;
  4986. }
  4987. static bool
  4988. path_is_url(
  4989. const char * path)
  4990. {
  4991. // This function is reaaaaaaaaaaaaaally stupid right now.
  4992. // We're just going to look for:
  4993. // (scheme)://(optional_stuff)
  4994. // Where (scheme) has no ':' or '/' characters.
  4995. // Someday it might be nice to have an actual URI parser here.
  4996. return skip_uri_scheme(path) != NULL;
  4997. }
  4998. static const char *
  4999. urlpath_canonicalize(
  5000. const char * uri,
  5001. apr_pool_t * pool)
  5002. {
  5003. if (path_is_url(uri))
  5004. {
  5005. uri = uri_canonicalize(uri, pool);
  5006. }
  5007. else
  5008. {
  5009. uri = fspath_canonicalize(uri, pool);
  5010. // Do a little dance to normalize hex encoding.
  5011. uri = path_uri_decode(uri, pool);
  5012. uri = path_uri_encode(uri, pool);
  5013. }
  5014. return uri;
  5015. }
  5016. // We decided against using apr_filepath_root here because of the negative
  5017. // performance impact (creating a pool and converting strings ).
  5018. static bool
  5019. dirent_is_root(
  5020. const char * dirent,
  5021. apr_size_t len)
  5022. {
  5023. // On Windows and Cygwin, 'H:' or 'H:/' (where 'H' is any letter)
  5024. // are also root directories
  5025. if ((len == 2 || ((len == 3) && (dirent[2] == '/'))) &&
  5026. (dirent[1] == ':') &&
  5027. ((dirent[0] >= 'A' && dirent[0] <= 'Z') ||
  5028. (dirent[0] >= 'a' && dirent[0] <= 'z')))
  5029. return TRUE;
  5030. // On Windows and Cygwin //server/share is a root directory,
  5031. // and on Cygwin //drive is a drive alias
  5032. if ((len >= 2) && (dirent[0] == '/') && (dirent[1] == '/') &&
  5033. (dirent[len - 1] != '/'))
  5034. {
  5035. int segments = 0;
  5036. for (size_t i = len; i >= 2; i--)
  5037. {
  5038. if (dirent[i] == '/')
  5039. {
  5040. segments++;
  5041. if (segments > 1)
  5042. return FALSE;
  5043. }
  5044. }
  5045. return (segments == 1); // //drive is invalid on plain Windows
  5046. }
  5047. // directory is root if it's equal to '/'
  5048. if ((len == 1) && (dirent[0] == '/'))
  5049. return TRUE;
  5050. return FALSE;
  5051. }
  5052. static bool
  5053. relpath_is_canonical(
  5054. const char * relpath)
  5055. {
  5056. const char * ptr = relpath, *seg = relpath;
  5057. // RELPATH is canonical if it has:
  5058. // - no '.' segments
  5059. // - no start and closing '/'
  5060. // - no '//'
  5061. if (*relpath == '\0')
  5062. return TRUE;
  5063. if (*ptr == '/')
  5064. return FALSE;
  5065. // Now validate the rest of the path.
  5066. while (1)
  5067. {
  5068. apr_size_t seglen = ptr - seg;
  5069. if ((seglen == 1) && (*seg == '.'))
  5070. return FALSE; // /./
  5071. if ((*ptr == '/') && (*(ptr+1) == '/'))
  5072. return FALSE; // //
  5073. if (!*ptr && (*(ptr - 1) == '/'))
  5074. return FALSE; // foo/
  5075. if (!*ptr)
  5076. break;
  5077. if (*ptr == '/')
  5078. ptr++;
  5079. seg = ptr;
  5080. while (*ptr && (*ptr != '/'))
  5081. ptr++;
  5082. }
  5083. return TRUE;
  5084. }
  5085. static const char *
  5086. relpath_basename(
  5087. const char * relpath,
  5088. apr_pool_t * pool)
  5089. {
  5090. apr_size_t len = strlen(relpath);
  5091. apr_size_t start = 0;
  5092. assert(relpath_is_canonical(relpath));
  5093. start = len;
  5094. while ((start > 0) && (relpath[start - 1] != '/'))
  5095. --start;
  5096. if (pool)
  5097. return apr_pstrmemdup(pool, relpath + start, len - start);
  5098. else
  5099. return relpath + start;
  5100. }
  5101. static char *
  5102. relpath_join(
  5103. const char * base,
  5104. const char * component,
  5105. apr_pool_t * pool)
  5106. {
  5107. apr_size_t blen = strlen(base);
  5108. apr_size_t clen = strlen(component);
  5109. char * path = NULL;
  5110. assert(relpath_is_canonical(base));
  5111. assert(relpath_is_canonical(component));
  5112. // If either is empty return the other
  5113. if (blen == 0)
  5114. return static_cast<char *>(apr_pmemdup(pool, component, clen + 1));
  5115. if (clen == 0)
  5116. return static_cast<char *>(apr_pmemdup(pool, base, blen + 1));
  5117. path = static_cast<char *>(apr_pcalloc(pool, blen + 1 + clen + 1));
  5118. memcpy(path, base, blen);
  5119. path[blen] = '/';
  5120. memcpy(path + blen + 1, component, clen + 1);
  5121. return path;
  5122. }
  5123. static const char *
  5124. dirent_canonicalize(
  5125. const char * dirent,
  5126. apr_pool_t * pool)
  5127. {
  5128. const char * dst = canonicalize(type_dirent, dirent, pool);
  5129. // Handle a specific case on Windows where path == "X:/". Here we have to
  5130. // append the final '/', as path_canonicalize will chop this of.
  5131. if (((dirent[0] >= 'A' && dirent[0] <= 'Z') ||
  5132. (dirent[0] >= 'a' && dirent[0] <= 'z')) &&
  5133. (dirent[1] == ':') && (dirent[2] == '/') &&
  5134. (dst[3] == '\0'))
  5135. {
  5136. char * dst_slash = static_cast<char *>(apr_pcalloc(pool, 4));
  5137. dst_slash[0] = canonicalize_to_upper(dirent[0]);
  5138. dst_slash[1] = ':';
  5139. dst_slash[2] = '/';
  5140. dst_slash[3] = '\0';
  5141. return dst_slash;
  5142. }
  5143. return dst;
  5144. }
  5145. static bool
  5146. dirent_is_canonical(
  5147. const char * dirent,
  5148. apr_pool_t * pool)
  5149. {
  5150. const char * ptr = dirent;
  5151. if (*ptr == '/')
  5152. {
  5153. ptr++;
  5154. // Check for UNC paths
  5155. if (*ptr == '/')
  5156. {
  5157. // TODO: Scan hostname and sharename and fall back to part code
  5158. // Fall back to old implementation
  5159. return (strcmp(dirent, dirent_canonicalize(dirent, pool)) == 0);
  5160. }
  5161. }
  5162. else if (((*ptr >= 'a' && *ptr <= 'z') || (*ptr >= 'A' && *ptr <= 'Z')) &&
  5163. (ptr[1] == ':'))
  5164. {
  5165. // The only canonical drive names are "A:"..."Z:", no lower case
  5166. if (*ptr < 'A' || *ptr > 'Z')
  5167. return FALSE;
  5168. ptr += 2;
  5169. if (*ptr == '/')
  5170. ptr++;
  5171. }
  5172. return relpath_is_canonical(ptr);
  5173. }
  5174. static const char *
  5175. dirent_basename(
  5176. const char * dirent,
  5177. apr_pool_t * pool)
  5178. {
  5179. apr_size_t len = strlen(dirent);
  5180. apr_size_t start = 0;
  5181. assert(!pool || dirent_is_canonical(dirent, pool));
  5182. if (dirent_is_root(dirent, len))
  5183. {
  5184. return "";
  5185. }
  5186. else
  5187. {
  5188. start = len;
  5189. while ((start > 0) && (dirent[start - 1] != '/') &&
  5190. (dirent[start - 1] != ':'))
  5191. {
  5192. --start;
  5193. }
  5194. }
  5195. if (pool)
  5196. return apr_pstrmemdup(pool, dirent + start, len - start);
  5197. else
  5198. return dirent + start;
  5199. }
  5200. static const char *
  5201. uri_skip_ancestor(
  5202. const char * parent_uri,
  5203. const char * child_uri)
  5204. {
  5205. apr_size_t len = strlen(parent_uri);
  5206. if (0 != strncmp(parent_uri, child_uri, len))
  5207. return NULL; // parent_uri is no ancestor of child_uri
  5208. if (child_uri[len] == 0)
  5209. return ""; // parent_uri == child_uri
  5210. if (child_uri[len] == '/')
  5211. return child_uri + len + 1;
  5212. return NULL;
  5213. }
  5214. static const char *
  5215. uri_skip_ancestor(
  5216. const char * parent_uri,
  5217. const char * child_uri,
  5218. apr_pool_t * result_pool)
  5219. {
  5220. const char * result = uri_skip_ancestor(parent_uri, child_uri);
  5221. return result ? path_uri_decode(result, result_pool) : NULL;
  5222. }
  5223. static bool
  5224. dirent_is_rooted(
  5225. const char * dirent)
  5226. {
  5227. if (!dirent)
  5228. return FALSE;
  5229. // Root on all systems
  5230. if (dirent[0] == '/')
  5231. return TRUE;
  5232. // On Windows, dirent is also absolute when it starts with 'H:' or 'H:/'
  5233. // where 'H' is any letter.
  5234. if (((dirent[0] >= 'A' && dirent[0] <= 'Z') ||
  5235. (dirent[0] >= 'a' && dirent[0] <= 'z')) &&
  5236. (dirent[1] == ':'))
  5237. {
  5238. return TRUE;
  5239. }
  5240. return FALSE;
  5241. }
  5242. static const char *
  5243. is_child(
  5244. path_type_t type,
  5245. const char * path1,
  5246. const char * path2,
  5247. apr_pool_t * pool)
  5248. {
  5249. apr_size_t i = 0;
  5250. // Allow "" and "foo" or "H:foo" to be parent/child
  5251. if (WEBDAV_PATH_IS_EMPTY(path1)) // "" is the parent
  5252. {
  5253. if (WEBDAV_PATH_IS_EMPTY(path2)) // "" not a child
  5254. {
  5255. return NULL;
  5256. }
  5257. // check if this is an absolute path
  5258. if ((type == type_uri) ||
  5259. (type == type_dirent && dirent_is_rooted(path2)))
  5260. {
  5261. return NULL;
  5262. }
  5263. else
  5264. {
  5265. // everything else is child
  5266. return pool ? apr_pstrdup(pool, path2) : path2;
  5267. }
  5268. }
  5269. for (i = 0; path1[i] && path2[i]; i++)
  5270. if (path1[i] != path2[i])
  5271. {
  5272. return NULL;
  5273. }
  5274. /* FIXME: This comment does not really match
  5275. the checks made in the code it refers to:
  5276. There are two cases that are parent/child
  5277. ... path1[i] == '\0'
  5278. .../foo path2[i] == '/'
  5279. or
  5280. / path1[i] == '\0'
  5281. /foo path2[i] != '/'
  5282. Other root paths (like X:/) fall under the former case:
  5283. X:/ path1[i] == '\0'
  5284. X:/foo path2[i] != '/'
  5285. Check for '//' to avoid matching '/' and '//srv'.
  5286. */
  5287. if ((path1[i] == '\0') && path2[i])
  5288. {
  5289. if ((path1[i - 1] == '/') ||
  5290. ((type == type_dirent) && path1[i - 1] == ':'))
  5291. {
  5292. if (path2[i] == '/')
  5293. /* .../
  5294. * ..../
  5295. * i */
  5296. return NULL;
  5297. else
  5298. /* .../
  5299. * .../foo
  5300. * i */
  5301. return pool ? apr_pstrdup(pool, path2 + i) : path2 + i;
  5302. }
  5303. else if (path2[i] == '/')
  5304. {
  5305. if (path2[i + 1])
  5306. /* ...
  5307. * .../foo
  5308. * i */
  5309. return pool ? apr_pstrdup(pool, path2 + i + 1) : path2 + i + 1;
  5310. else
  5311. /* ...
  5312. * .../
  5313. * i */
  5314. return NULL;
  5315. }
  5316. }
  5317. // Otherwise, path2 isn't a child.
  5318. return NULL;
  5319. }
  5320. static const char *
  5321. uri_is_child(
  5322. const char * parent_uri,
  5323. const char * child_uri,
  5324. apr_pool_t * pool)
  5325. {
  5326. const char * relpath = NULL;
  5327. assert(pool); // hysterical raisins.
  5328. relpath = is_child(type_uri, parent_uri, child_uri, pool);
  5329. if (relpath)
  5330. relpath = path_uri_decode(relpath, pool);
  5331. return relpath;
  5332. }
  5333. static bool
  5334. dirent_is_absolute(
  5335. const char * dirent)
  5336. {
  5337. if (!dirent)
  5338. return FALSE;
  5339. // dirent is absolute if it starts with '/' on non-Windows platforms
  5340. // or with '//' on Windows platforms
  5341. if ((dirent[0] == '/') &&
  5342. (dirent[1] == '/')) // Single '/' depends on current drive
  5343. {
  5344. return TRUE;
  5345. }
  5346. // On Windows, dirent is also absolute when it starts with 'H:/'
  5347. // where 'H' is any letter.
  5348. if (((dirent[0] >= 'A' && dirent[0] <= 'Z')) &&
  5349. (dirent[1] == ':') && (dirent[2] == '/'))
  5350. {
  5351. return TRUE;
  5352. }
  5353. return FALSE;
  5354. }
  5355. static error_t
  5356. dirent_get_absolute(
  5357. const char ** pabsolute,
  5358. const char * relative,
  5359. apr_pool_t * pool)
  5360. {
  5361. char * buffer = NULL;
  5362. apr_status_t apr_err = 0;
  5363. const char * path_apr = NULL;
  5364. WEBDAV_ERR_ASSERT(!path_is_url(relative));
  5365. // Merge the current working directory with the relative dirent.
  5366. WEBDAV_ERR(path_cstring_from_utf8(&path_apr, relative, pool));
  5367. apr_err = apr_filepath_merge(&buffer, NULL,
  5368. path_apr,
  5369. APR_FILEPATH_NOTRELATIVE,
  5370. pool);
  5371. if (apr_err)
  5372. {
  5373. // In some cases when the passed path or its ancestor(s) do not exist
  5374. // or no longer exist apr returns an error.
  5375. // In many of these cases we would like to return a path anyway, when the
  5376. // passed path was already a safe absolute path. So check for that now to
  5377. // avoid an error.
  5378. // dirent_is_absolute() doesn't perform the necessary checks to see
  5379. // if the path doesn't need post processing to be in the canonical absolute
  5380. // format.
  5381. if (dirent_is_absolute(relative) &&
  5382. dirent_is_canonical(relative, pool) &&
  5383. !path_is_backpath_present(relative))
  5384. {
  5385. *pabsolute = apr_pstrdup(pool, relative);
  5386. return WEBDAV_NO_ERROR;
  5387. }
  5388. return error_createf(WEBDAV_ERR_BAD_FILENAME,
  5389. NULL,
  5390. "Couldn't determine absolute path of '%s'", relative);
  5391. }
  5392. WEBDAV_ERR(path_cstring_to_utf8(pabsolute, buffer, pool));
  5393. *pabsolute = dirent_canonicalize(*pabsolute, pool);
  5394. return WEBDAV_NO_ERROR;
  5395. }
  5396. //------------------------------------------------------------------------------
  5397. // from atomic.c
  5398. #define atomic_t apr_uint32_t
  5399. // Magic values for atomic initialization
  5400. #define WEBDAV_ATOMIC_UNINITIALIZED 0
  5401. #define WEBDAV_ATOMIC_START_INIT 1
  5402. #define WEBDAV_ATOMIC_INIT_FAILED 2
  5403. #define WEBDAV_ATOMIC_INITIALIZED 3
  5404. static error_t
  5405. atomic_init_once(
  5406. volatile atomic_t * global_status,
  5407. error_t (*init_func)(void *,apr_pool_t *),
  5408. void * baton,
  5409. apr_pool_t * pool)
  5410. {
  5411. // We have to call init_func exactly once. Because APR
  5412. // doesn't have statically-initialized mutexes, we implement a poor
  5413. // man's spinlock using atomic_cas.
  5414. atomic_t status = apr_atomic_cas32(global_status,
  5415. WEBDAV_ATOMIC_START_INIT,
  5416. WEBDAV_ATOMIC_UNINITIALIZED);
  5417. if (status == WEBDAV_ATOMIC_UNINITIALIZED)
  5418. {
  5419. error_t err = init_func(baton, pool);
  5420. if (err)
  5421. {
  5422. #if APR_HAS_THREADS
  5423. // Tell other threads that the initialization failed.
  5424. apr_atomic_cas32(global_status,
  5425. WEBDAV_ATOMIC_INIT_FAILED,
  5426. WEBDAV_ATOMIC_START_INIT);
  5427. #endif
  5428. return error_create(WEBDAV_ERR_ATOMIC_INIT_FAILURE, &err,
  5429. "Couldn't perform atomic initialization");
  5430. }
  5431. apr_atomic_cas32(global_status,
  5432. WEBDAV_ATOMIC_INITIALIZED,
  5433. WEBDAV_ATOMIC_START_INIT);
  5434. }
  5435. #if APR_HAS_THREADS
  5436. // Wait for whichever thread is performing initialization to finish.
  5437. // XXX FIXME: Should we have a maximum wait here, like we have in
  5438. // the Windows file IO spinner?
  5439. else while (status != WEBDAV_ATOMIC_INITIALIZED)
  5440. {
  5441. if (status == WEBDAV_ATOMIC_INIT_FAILED)
  5442. return error_create(WEBDAV_ERR_ATOMIC_INIT_FAILURE, NULL,
  5443. "Couldn't perform atomic initialization");
  5444. apr_sleep(APR_USEC_PER_SEC / 1000);
  5445. status = apr_atomic_cas32(global_status,
  5446. WEBDAV_ATOMIC_UNINITIALIZED,
  5447. WEBDAV_ATOMIC_UNINITIALIZED);
  5448. }
  5449. #endif // APR_HAS_THREADS
  5450. return WEBDAV_NO_ERROR;
  5451. }
  5452. //------------------------------------------------------------------------------
  5453. // from io.c
  5454. #define RETRY_MAX_ATTEMPTS 2
  5455. #define RETRY_INITIAL_SLEEP 1000
  5456. #define RETRY_MAX_SLEEP 128000
  5457. // Suppress warning: Condition is always true
  5458. #pragma warn -8008
  5459. #define RETRY_LOOP(err, expr, retry_test, sleep_test) \
  5460. do \
  5461. { \
  5462. apr_status_t os_err = APR_TO_OS_ERROR(err); \
  5463. int sleep_count = RETRY_INITIAL_SLEEP; \
  5464. int retries; \
  5465. for (retries = 0; \
  5466. retries < RETRY_MAX_ATTEMPTS && (retry_test); \
  5467. os_err = APR_TO_OS_ERROR(err)) \
  5468. { \
  5469. if (sleep_test) \
  5470. { \
  5471. ++retries; \
  5472. apr_sleep(sleep_count); \
  5473. if (sleep_count < RETRY_MAX_SLEEP) \
  5474. sleep_count *= 2; \
  5475. } \
  5476. (err) = (expr); \
  5477. } \
  5478. } \
  5479. while (0)
  5480. #if defined(EDEADLK) && APR_HAS_THREADS
  5481. #define FILE_LOCK_RETRY_LOOP(err, expr) \
  5482. RETRY_LOOP(err, \
  5483. expr, \
  5484. (APR_STATUS_IS_EINTR(err) || os_err == EDEADLK), \
  5485. (!APR_STATUS_IS_EINTR(err)))
  5486. #else
  5487. #define FILE_LOCK_RETRY_LOOP(err, expr) \
  5488. RETRY_LOOP(err, \
  5489. expr, \
  5490. (APR_STATUS_IS_EINTR(err)), \
  5491. 0)
  5492. #endif
  5493. #ifndef WIN32_RETRY_LOOP
  5494. #if !defined(WEBDAV_NO_WIN32_RETRY_LOOP)
  5495. #define WIN32_RETRY_LOOP(err, expr) \
  5496. RETRY_LOOP(err, expr, (os_err == ERROR_ACCESS_DENIED || \
  5497. os_err == ERROR_SHARING_VIOLATION || \
  5498. os_err == ERROR_DIR_NOT_EMPTY), \
  5499. 1)
  5500. #else
  5501. #define WIN32_RETRY_LOOP(err, expr) ((void)0)
  5502. #endif
  5503. #endif
  5504. // Not specifying any of these means no removal at all.
  5505. typedef enum io_file_del_t
  5506. {
  5507. // No deletion ever
  5508. io_file_del_none = 0,
  5509. // Remove when the file is closed
  5510. io_file_del_on_close,
  5511. // Remove when the associated pool is cleared
  5512. io_file_del_on_pool_cleanup
  5513. } io_file_del_t;
  5514. // Wrapper for apr_file_open(), taking an APR-encoded filename.
  5515. static apr_status_t
  5516. file_open(
  5517. apr_file_t ** file,
  5518. const char * fname_apr,
  5519. apr_int32_t flags,
  5520. apr_fileperms_t perm,
  5521. bool retry_on_failure,
  5522. apr_pool_t * pool)
  5523. {
  5524. apr_status_t status = apr_file_open(file, fname_apr, flags, perm, pool);
  5525. if (retry_on_failure)
  5526. {
  5527. WIN32_RETRY_LOOP(status, apr_file_open(file, fname_apr, flags, perm, pool));
  5528. }
  5529. return status;
  5530. }
  5531. #pragma warn +8008
  5532. static error_t
  5533. io_file_open(
  5534. apr_file_t ** new_file,
  5535. const char * fname,
  5536. apr_int32_t flags,
  5537. apr_fileperms_t perms,
  5538. apr_pool_t * pool)
  5539. {
  5540. const char * fname_apr = NULL;
  5541. apr_status_t status = 0;
  5542. WEBDAV_ERR(cstring_from_utf8(&fname_apr, fname, pool));
  5543. status = file_open(new_file, fname_apr, flags | APR_BINARY, perms,
  5544. /* retry_on_failure */ FALSE,
  5545. pool);
  5546. if (status)
  5547. return error_wrap_apr(status, "Can't open file '%s'", fname);
  5548. else
  5549. return WEBDAV_NO_ERROR;
  5550. }
  5551. static error_t
  5552. io_file_open_writable(
  5553. apr_file_t ** new_file,
  5554. apr_os_file_t * thefile,
  5555. apr_int32_t flags,
  5556. apr_pool_t * pool)
  5557. {
  5558. apr_status_t status = 0;
  5559. status = apr_os_file_put(new_file, thefile,
  5560. flags | APR_BINARY,
  5561. pool);
  5562. if (status)
  5563. return error_wrap_apr(status, "Can't open file");
  5564. else
  5565. return WEBDAV_NO_ERROR;
  5566. }
  5567. // Wrapper for apr_file_name_get(), passing out a UTF8-encoded filename.
  5568. static error_t
  5569. io_file_name_get(
  5570. const char ** filename,
  5571. apr_file_t * file,
  5572. apr_pool_t * pool)
  5573. {
  5574. const char * fname_apr = NULL;
  5575. apr_status_t status = 0;
  5576. status = apr_file_name_get(&fname_apr, file);
  5577. if (status)
  5578. return error_wrap_apr(status, "Can't get file name");
  5579. if (fname_apr)
  5580. WEBDAV_ERR(path_cstring_to_utf8(filename, fname_apr, pool));
  5581. else
  5582. *filename = NULL;
  5583. return WEBDAV_NO_ERROR;
  5584. }
  5585. static APR_INLINE error_t
  5586. do_io_file_wrapper_cleanup(
  5587. apr_file_t * file,
  5588. apr_status_t status,
  5589. const char * msg,
  5590. const char * msg_no_name,
  5591. apr_pool_t * pool)
  5592. {
  5593. const char * name = NULL;
  5594. error_t err = 0;
  5595. if (!status)
  5596. return WEBDAV_NO_ERROR;
  5597. err = io_file_name_get(&name, file, pool);
  5598. if (err)
  5599. name = NULL;
  5600. error_clear(&err);
  5601. // Issue #3014: Return a specific error for broken pipes,
  5602. // with a single element in the error chain.
  5603. if (APR_STATUS_IS_EPIPE(status))
  5604. return error_create(WEBDAV_ERR_IO_PIPE_WRITE_ERROR, NULL, NULL);
  5605. if (name)
  5606. return error_wrap_apr(status, msg, name);
  5607. else
  5608. return error_wrap_apr(status, "%s", msg_no_name);
  5609. }
  5610. static error_t
  5611. io_file_close(
  5612. apr_file_t * file,
  5613. apr_pool_t * pool)
  5614. {
  5615. return do_io_file_wrapper_cleanup(file, apr_file_close(file),
  5616. "Can't close file '%s'",
  5617. "Can't close stream",
  5618. pool);
  5619. }
  5620. static error_t
  5621. io_file_getc(
  5622. char * ch,
  5623. apr_file_t * file,
  5624. apr_pool_t * pool)
  5625. {
  5626. return do_io_file_wrapper_cleanup(file, apr_file_getc(ch, file),
  5627. "Can't read file '%s'",
  5628. "Can't read stream",
  5629. pool);
  5630. }
  5631. static error_t
  5632. io_file_write_full(
  5633. apr_file_t * file,
  5634. const void * buf,
  5635. apr_size_t nbytes,
  5636. apr_size_t * bytes_written,
  5637. apr_pool_t * pool)
  5638. {
  5639. // We cannot simply call apr_file_write_full on Win32 as it may fail
  5640. // for larger values of NBYTES. In that case, we have to emulate the
  5641. // "_full" part here. Thus, always call apr_file_write directly on
  5642. // Win32 as this minimizes overhead for small data buffers.
  5643. #define MAXBUFSIZE 64*1024
  5644. apr_size_t bw = nbytes;
  5645. apr_size_t to_write = nbytes;
  5646. // try a simple "write everything at once" first
  5647. apr_status_t rv = apr_file_write(file, buf, &bw);
  5648. buf = (char *)buf + bw;
  5649. to_write -= bw;
  5650. // if the OS cannot handle that, use smaller chunks
  5651. if ((rv == APR_FROM_OS_ERROR(ERROR_NOT_ENOUGH_MEMORY)) &&
  5652. (nbytes > MAXBUFSIZE))
  5653. {
  5654. do
  5655. {
  5656. bw = to_write > MAXBUFSIZE ? MAXBUFSIZE : to_write;
  5657. rv = apr_file_write(file, buf, &bw);
  5658. buf = (char *)buf + bw;
  5659. to_write -= bw;
  5660. }
  5661. while (rv == APR_SUCCESS && to_write > 0);
  5662. }
  5663. // bytes_written may actually be NULL
  5664. if (bytes_written)
  5665. *bytes_written = nbytes - to_write;
  5666. #undef MAXBUFSIZE
  5667. return error_trace(do_io_file_wrapper_cleanup(file, rv,
  5668. "Can't write to file '%s'",
  5669. "Can't write to stream",
  5670. pool));
  5671. }
  5672. static error_t
  5673. io_file_seek(
  5674. apr_file_t * file,
  5675. apr_seek_where_t where,
  5676. apr_off_t * offset,
  5677. apr_pool_t * pool)
  5678. {
  5679. return do_io_file_wrapper_cleanup(file, apr_file_seek(file, where, offset),
  5680. "Can't set position pointer in file '%s'",
  5681. "Can't set position pointer in stream",
  5682. pool);
  5683. }
  5684. static error_t
  5685. io_file_putc(
  5686. char ch,
  5687. apr_file_t * file,
  5688. apr_pool_t * pool)
  5689. {
  5690. return do_io_file_wrapper_cleanup(file, apr_file_putc(ch, file),
  5691. "Can't write file '%s'",
  5692. "Can't write stream",
  5693. pool);
  5694. }
  5695. static error_t
  5696. io_file_read(
  5697. apr_file_t * file,
  5698. void * buf,
  5699. apr_size_t * nbytes,
  5700. apr_pool_t * pool)
  5701. {
  5702. return do_io_file_wrapper_cleanup(file, apr_file_read(file, buf, nbytes),
  5703. "Can't read file '%s'",
  5704. "Can't read stream",
  5705. pool);
  5706. }
  5707. // Local wrapper of path_cstring_from_utf8() that does no copying on
  5708. // operating systems where APR always uses utf-8 as native path format
  5709. static error_t
  5710. cstring_from_utf8(
  5711. const char ** path_apr,
  5712. const char * path_utf8,
  5713. apr_pool_t * pool)
  5714. {
  5715. *path_apr = path_utf8;
  5716. return WEBDAV_NO_ERROR;
  5717. }
  5718. static error_t
  5719. io_file_read_full2(
  5720. apr_file_t * file,
  5721. void * buf,
  5722. apr_size_t nbytes,
  5723. apr_size_t * bytes_read,
  5724. bool * hit_eof,
  5725. apr_pool_t * pool)
  5726. {
  5727. apr_status_t status = apr_file_read_full(file, buf, nbytes, bytes_read);
  5728. if (hit_eof)
  5729. {
  5730. if (APR_STATUS_IS_EOF(status))
  5731. {
  5732. *hit_eof = TRUE;
  5733. return WEBDAV_NO_ERROR;
  5734. }
  5735. else
  5736. *hit_eof = FALSE;
  5737. }
  5738. return do_io_file_wrapper_cleanup(file, status,
  5739. "Can't read file '%s'",
  5740. "Can't read stream",
  5741. pool);
  5742. }
  5743. //------------------------------------------------------------------------------
  5744. // from svn_io.h
  5745. // Read handler function for a generic stream. see stream_t.
  5746. typedef error_t (*read_fn_t)(
  5747. void * baton,
  5748. char * buffer,
  5749. apr_size_t * len);
  5750. // Skip data handler function for a generic stream. see stream_t
  5751. // and stream_skip().
  5752. typedef error_t (*stream_skip_fn_t)(
  5753. void * baton,
  5754. apr_size_t len);
  5755. // Write handler function for a generic stream. see stream_t.
  5756. typedef error_t (*write_fn_t)(
  5757. void * baton,
  5758. const char * data,
  5759. apr_size_t * len);
  5760. // Close handler function for a generic stream. see stream_t.
  5761. typedef error_t (*close_fn_t)(void * baton);
  5762. typedef struct stream_mark_t stream_mark_t;
  5763. typedef error_t (*stream_mark_fn_t)(
  5764. void * baton,
  5765. stream_mark_t ** mark,
  5766. apr_pool_t * pool);
  5767. typedef error_t (*stream_seek_fn_t)(
  5768. void * baton,
  5769. const stream_mark_t * mark);
  5770. typedef bool (*stream_is_buffered_fn_t)(void * baton);
  5771. //------------------------------------------------------------------------------
  5772. // from stream.c
  5773. typedef struct stream_t
  5774. {
  5775. void * baton;
  5776. read_fn_t read_fn;
  5777. stream_skip_fn_t skip_fn;
  5778. write_fn_t write_fn;
  5779. close_fn_t close_fn;
  5780. stream_mark_fn_t mark_fn;
  5781. stream_seek_fn_t seek_fn;
  5782. stream_is_buffered_fn_t is_buffered_fn;
  5783. } stream_t;
  5784. // Generic stream for APR files
  5785. struct baton_apr_t
  5786. {
  5787. apr_file_t * file;
  5788. apr_pool_t * pool;
  5789. };
  5790. // stream_mark_t for streams backed by APR files.
  5791. struct mark_apr_t
  5792. {
  5793. apr_off_t off;
  5794. };
  5795. static error_t
  5796. read_handler_apr(
  5797. void * baton,
  5798. char * buffer,
  5799. apr_size_t * len)
  5800. {
  5801. struct baton_apr_t * btn = static_cast<baton_apr_t *>(baton);
  5802. error_t err = 0;
  5803. bool eof = FALSE;
  5804. if (*len == 1)
  5805. {
  5806. err = io_file_getc(buffer, btn->file, btn->pool);
  5807. if (err)
  5808. {
  5809. *len = 0;
  5810. if (APR_STATUS_IS_EOF(err))
  5811. {
  5812. error_clear(&err);
  5813. err = WEBDAV_NO_ERROR;
  5814. }
  5815. }
  5816. }
  5817. else
  5818. err = io_file_read_full2(btn->file, buffer, *len, len,
  5819. &eof, btn->pool);
  5820. return err;
  5821. }
  5822. static error_t
  5823. skip_handler_apr(
  5824. void * baton,
  5825. apr_size_t len)
  5826. {
  5827. struct baton_apr_t * btn = static_cast<baton_apr_t *>(baton);
  5828. apr_off_t offset = len;
  5829. return io_file_seek(btn->file, APR_CUR, &offset, btn->pool);
  5830. }
  5831. static error_t
  5832. write_handler_apr(
  5833. void * baton,
  5834. const char * data,
  5835. apr_size_t * len)
  5836. {
  5837. struct baton_apr_t * btn = static_cast<baton_apr_t *>(baton);
  5838. error_t err = 0;
  5839. if (*len == 1)
  5840. {
  5841. err = io_file_putc(*data, btn->file, btn->pool);
  5842. if (err)
  5843. *len = 0;
  5844. }
  5845. else
  5846. err = io_file_write_full(btn->file, data, *len, len, btn->pool);
  5847. return err;
  5848. }
  5849. static error_t
  5850. close_handler_apr(
  5851. void * baton)
  5852. {
  5853. struct baton_apr_t * btn = static_cast<baton_apr_t *>(baton);
  5854. return io_file_close(btn->file, btn->pool);
  5855. }
  5856. static error_t
  5857. mark_handler_apr(
  5858. void * baton,
  5859. stream_mark_t ** mark,
  5860. apr_pool_t * pool)
  5861. {
  5862. struct baton_apr_t * btn = static_cast<baton_apr_t *>(baton);
  5863. struct mark_apr_t * mark_apr = 0;
  5864. mark_apr = static_cast<mark_apr_t *>(apr_pcalloc(pool, sizeof(*mark_apr)));
  5865. mark_apr->off = 0;
  5866. WEBDAV_ERR(io_file_seek(btn->file, APR_CUR, &mark_apr->off, btn->pool));
  5867. *mark = (stream_mark_t *)mark_apr;
  5868. return WEBDAV_NO_ERROR;
  5869. }
  5870. static error_t
  5871. seek_handler_apr(
  5872. void * baton,
  5873. const stream_mark_t * mark)
  5874. {
  5875. struct baton_apr_t * btn = static_cast<baton_apr_t *>(baton);
  5876. apr_off_t offset = (mark != NULL) ? ((const struct mark_apr_t *)mark)->off : 0;
  5877. WEBDAV_ERR(io_file_seek(btn->file, APR_SET, &offset, btn->pool));
  5878. return WEBDAV_NO_ERROR;
  5879. }
  5880. static bool
  5881. is_buffered_handler_apr(
  5882. void * baton)
  5883. {
  5884. struct baton_apr_t * btn = static_cast<baton_apr_t *>(baton);
  5885. return (apr_file_flags_get(btn->file) & APR_BUFFERED) != 0;
  5886. }
  5887. static stream_t *
  5888. stream_create(
  5889. void * baton,
  5890. apr_pool_t * pool)
  5891. {
  5892. stream_t * stream = static_cast<stream_t *>(apr_pcalloc(pool, sizeof(*stream)));
  5893. stream->baton = baton;
  5894. stream->read_fn = NULL;
  5895. stream->skip_fn = NULL;
  5896. stream->write_fn = NULL;
  5897. stream->close_fn = NULL;
  5898. stream->mark_fn = NULL;
  5899. stream->seek_fn = NULL;
  5900. stream->is_buffered_fn = NULL;
  5901. return stream;
  5902. }
  5903. static void
  5904. stream_set_read(
  5905. stream_t * stream,
  5906. read_fn_t read_fn)
  5907. {
  5908. stream->read_fn = read_fn;
  5909. }
  5910. static void
  5911. stream_set_skip(
  5912. stream_t * stream,
  5913. stream_skip_fn_t skip_fn)
  5914. {
  5915. stream->skip_fn = skip_fn;
  5916. }
  5917. static void
  5918. stream_set_write(
  5919. stream_t * stream,
  5920. write_fn_t write_fn)
  5921. {
  5922. stream->write_fn = write_fn;
  5923. }
  5924. static void
  5925. stream_set_close(
  5926. stream_t * stream,
  5927. close_fn_t close_fn)
  5928. {
  5929. stream->close_fn = close_fn;
  5930. }
  5931. static void
  5932. stream_set_mark(
  5933. stream_t * stream,
  5934. stream_mark_fn_t mark_fn)
  5935. {
  5936. stream->mark_fn = mark_fn;
  5937. }
  5938. static void
  5939. stream_set_seek(
  5940. stream_t * stream,
  5941. stream_seek_fn_t seek_fn)
  5942. {
  5943. stream->seek_fn = seek_fn;
  5944. }
  5945. static void
  5946. stream_set_is_buffered(
  5947. stream_t * stream,
  5948. stream_is_buffered_fn_t is_buffered_fn)
  5949. {
  5950. stream->is_buffered_fn = is_buffered_fn;
  5951. }
  5952. static error_t
  5953. read_handler_empty(
  5954. void * baton,
  5955. char * buffer,
  5956. apr_size_t * len)
  5957. {
  5958. *len = 0;
  5959. return WEBDAV_NO_ERROR;
  5960. }
  5961. static error_t
  5962. write_handler_empty(
  5963. void * baton,
  5964. const char * data,
  5965. apr_size_t * len)
  5966. {
  5967. return WEBDAV_NO_ERROR;
  5968. }
  5969. static error_t
  5970. mark_handler_empty(
  5971. void * baton,
  5972. stream_mark_t ** mark,
  5973. apr_pool_t * pool)
  5974. {
  5975. *mark = NULL; // Seek to start of stream marker
  5976. return WEBDAV_NO_ERROR;
  5977. }
  5978. static error_t
  5979. seek_handler_empty(
  5980. void * baton,
  5981. const stream_mark_t * mark)
  5982. {
  5983. return WEBDAV_NO_ERROR;
  5984. }
  5985. static bool
  5986. is_buffered_handler_empty(void * baton)
  5987. {
  5988. return FALSE;
  5989. }
  5990. static stream_t *
  5991. stream_empty(
  5992. apr_pool_t * pool)
  5993. {
  5994. stream_t * stream = stream_create(NULL, pool);
  5995. stream_set_read(stream, read_handler_empty);
  5996. stream_set_write(stream, write_handler_empty);
  5997. stream_set_mark(stream, mark_handler_empty);
  5998. stream_set_seek(stream, seek_handler_empty);
  5999. stream_set_is_buffered(stream, is_buffered_handler_empty);
  6000. return stream;
  6001. }
  6002. static stream_t *
  6003. stream_from_aprfile2(
  6004. apr_file_t * file,
  6005. bool disown,
  6006. apr_pool_t * pool)
  6007. {
  6008. stream_t * stream = NULL;
  6009. if (file == NULL)
  6010. return stream_empty(pool);
  6011. baton_apr_t * baton = static_cast<baton_apr_t *>(apr_pcalloc(pool, sizeof(*baton)));
  6012. baton->file = file;
  6013. baton->pool = pool;
  6014. stream = stream_create(baton, pool);
  6015. stream_set_read(stream, read_handler_apr);
  6016. stream_set_write(stream, write_handler_apr);
  6017. stream_set_skip(stream, skip_handler_apr);
  6018. stream_set_mark(stream, mark_handler_apr);
  6019. stream_set_seek(stream, seek_handler_apr);
  6020. stream_set_is_buffered(stream, is_buffered_handler_apr);
  6021. if (!disown)
  6022. stream_set_close(stream, close_handler_apr);
  6023. return stream;
  6024. }
  6025. static error_t
  6026. stream_open_writable(
  6027. stream_t ** stream,
  6028. apr_os_file_t * thefile,
  6029. apr_pool_t * result_pool,
  6030. apr_pool_t * scratch_pool)
  6031. {
  6032. apr_file_t * file = NULL;
  6033. WEBDAV_ERR(io_file_open_writable(&file,
  6034. thefile,
  6035. APR_WRITE
  6036. | APR_BUFFERED
  6037. | APR_BINARY
  6038. | APR_CREATE,
  6039. // | APR_EXCL,
  6040. result_pool));
  6041. *stream = stream_from_aprfile2(file, FALSE, result_pool);
  6042. return WEBDAV_NO_ERROR;
  6043. }
  6044. static error_t
  6045. stream_write(
  6046. stream_t * stream,
  6047. const char * data,
  6048. apr_size_t * len)
  6049. {
  6050. WEBDAV_ERR_ASSERT(stream->write_fn != NULL);
  6051. return stream->write_fn(stream->baton, data, len);
  6052. }
  6053. static error_t
  6054. stream_close(
  6055. stream_t * stream)
  6056. {
  6057. if (stream->close_fn == NULL)
  6058. return WEBDAV_NO_ERROR;
  6059. return stream->close_fn(stream->baton);
  6060. }
  6061. //------------------------------------------------------------------------------
  6062. // from util.c
  6063. static apr_status_t
  6064. dav_request_cleanup(
  6065. void * baton);
  6066. static apr_status_t
  6067. dav_request_sess_cleanup(
  6068. void * baton)
  6069. {
  6070. neon_request_t * req = static_cast<neon_request_t *>(baton);
  6071. // Make sure we don't run the 'child' cleanup anymore:
  6072. // the pool it refers to probably doesn't exist anymore when it
  6073. // finally does get run if it hasn't by now.
  6074. apr_pool_cleanup_kill(req->pool, req, dav_request_cleanup);
  6075. if (req->ne_req)
  6076. ne_request_destroy(req->ne_req);
  6077. return APR_SUCCESS;
  6078. }
  6079. static apr_status_t
  6080. dav_request_cleanup(
  6081. void * baton)
  6082. {
  6083. neon_request_t * req = static_cast<neon_request_t *>(baton);
  6084. apr_pool_cleanup_run(req->sess->pool, req, dav_request_sess_cleanup);
  6085. return APR_SUCCESS;
  6086. }
  6087. // Return a path-absolute relative URL, given a URL reference (which may
  6088. // be absolute or relative).
  6089. static const char *
  6090. path_from_url(
  6091. const char * url)
  6092. {
  6093. const char * p = NULL;
  6094. // Look for the scheme/authority separator. Stop if we see a path
  6095. // separator - that indicates that this definitely isn't an absolute URL.
  6096. for (p = url; *p; p++)
  6097. {
  6098. if ((*p == ':') || (*p == '/'))
  6099. break;
  6100. }
  6101. // Check whether we found the scheme/authority separator.
  6102. if ((*p++ != ':') || (*p++ != '/') || (*p++ != '/'))
  6103. {
  6104. // No separator, so it must already be relative.
  6105. return url;
  6106. }
  6107. // Find the end of the authority section, indicated by the start of
  6108. // a path, query, or fragment section.
  6109. for (; *p; p++)
  6110. {
  6111. if ((*p == '/') || (*p == '?') || (*p == '#'))
  6112. break;
  6113. }
  6114. // Return a pointer to the rest of the URL, or to "/" if there
  6115. // was no next section.
  6116. return *p == '\0' ? "/" : p;
  6117. }
  6118. // Simple multi-status parser
  6119. // For the purpose of 'simple' requests which - if it weren't
  6120. // for our custom error parser - could use the ne_basic.h interfaces.
  6121. // List of XML elements expected in 207 Multi-Status responses.
  6122. static const neon_xml_elm_t multistatus_elements[] =
  6123. {
  6124. { "DAV:", "multistatus", ELEM_multistatus, 0 },
  6125. { "DAV:", "response", ELEM_response, 0 },
  6126. {
  6127. "DAV:", "responsedescription", ELEM_responsedescription,
  6128. NEON_XML_CDATA
  6129. },
  6130. { "DAV:", "status", ELEM_status, NEON_XML_CDATA },
  6131. { "DAV:", "href", ELEM_href, NEON_XML_CDATA },
  6132. { "DAV:", "propstat", ELEM_propstat, NEON_XML_CDATA },
  6133. { "DAV:", "prop", ELEM_prop, NEON_XML_CDATA },
  6134. // We start out basic and are not interested in other elements
  6135. { "", "", ELEM_unknown, 0 },
  6136. { NULL }
  6137. };
  6138. static const int multistatus_nesting_table[][5] =
  6139. {
  6140. { ELEM_root, ELEM_multistatus, NEON_XML_INVALID },
  6141. {
  6142. ELEM_multistatus, ELEM_response, ELEM_responsedescription,
  6143. NEON_XML_DECLINE
  6144. },
  6145. { ELEM_responsedescription, NEON_XML_INVALID },
  6146. {
  6147. ELEM_response, ELEM_href, ELEM_status, ELEM_propstat,
  6148. NEON_XML_DECLINE
  6149. },
  6150. { ELEM_status, NEON_XML_INVALID },
  6151. { ELEM_href, NEON_XML_INVALID },
  6152. {
  6153. ELEM_propstat, ELEM_prop, ELEM_status, ELEM_responsedescription,
  6154. NEON_XML_INVALID
  6155. },
  6156. { ELEM_prop, NEON_XML_DECLINE },
  6157. { NEON_XML_DECLINE },
  6158. };
  6159. static int
  6160. multistatus_validate_element(
  6161. int parent,
  6162. int child)
  6163. {
  6164. int i = 0;
  6165. int j = 0;
  6166. while ((parent != multistatus_nesting_table[i][0]) &&
  6167. (multistatus_nesting_table[i][0] > 0 || i == 0))
  6168. i++;
  6169. if (parent == multistatus_nesting_table[i][0])
  6170. while ((multistatus_nesting_table[i][++j] != child) &&
  6171. (multistatus_nesting_table[i][j] > 0))
  6172. ;
  6173. return multistatus_nesting_table[i][j];
  6174. }
  6175. typedef struct multistatus_baton_t
  6176. {
  6177. stringbuf_t * want_cdata;
  6178. stringbuf_t * cdata;
  6179. bool in_propstat;
  6180. bool propstat_has_error;
  6181. stringbuf_t * propname;
  6182. stringbuf_t * propstat_description;
  6183. neon_request_t * req;
  6184. stringbuf_t * description;
  6185. bool contains_error;
  6186. bool contains_precondition_error;
  6187. } multistatus_baton_t;
  6188. // Implements neon_startelm_cb_t.
  6189. static error_t
  6190. start_207_element(
  6191. int * elem,
  6192. void * baton,
  6193. int parent,
  6194. const char * nspace,
  6195. const char * name,
  6196. const char ** atts)
  6197. {
  6198. multistatus_baton_t * b = static_cast<multistatus_baton_t *>(baton);
  6199. const neon_xml_elm_t * elm =
  6200. neon_lookup_xml_elem(multistatus_elements, nspace, name);
  6201. *elem = elm ? multistatus_validate_element(parent, elm->id) : NEON_XML_DECLINE;
  6202. if (parent == ELEM_prop)
  6203. {
  6204. stringbuf_setempty(b->propname);
  6205. if (strcmp(nspace, "DAV:") == 0)
  6206. stringbuf_set(b->propname, "DAV:");
  6207. stringbuf_appendcstr(b->propname, name);
  6208. }
  6209. if (*elem < 1) // ! > 0
  6210. return WEBDAV_NO_ERROR;
  6211. switch (*elem)
  6212. {
  6213. case ELEM_propstat:
  6214. b->in_propstat = TRUE;
  6215. b->propstat_has_error = FALSE;
  6216. break;
  6217. default:
  6218. break;
  6219. }
  6220. // We're guaranteed to have ELM now: NEON_XML_DECLINE < 1
  6221. if (elm->flags & NEON_XML_CDATA)
  6222. {
  6223. stringbuf_setempty(b->cdata);
  6224. b->want_cdata = b->cdata;
  6225. }
  6226. return WEBDAV_NO_ERROR;
  6227. }
  6228. // Implements neon_endelm_cb_t
  6229. static error_t
  6230. end_207_element(
  6231. void * baton,
  6232. int state,
  6233. const char * nspace,
  6234. const char * name)
  6235. {
  6236. multistatus_baton_t * b = static_cast<multistatus_baton_t *>(baton);
  6237. switch (state)
  6238. {
  6239. case ELEM_multistatus:
  6240. if (b->contains_error)
  6241. {
  6242. if (stringbuf_isempty(b->description))
  6243. return error_create(WEBDAV_ERR_DAV_REQUEST_FAILED, NULL,
  6244. "The request response contained at least one error");
  6245. else if (b->contains_precondition_error)
  6246. return error_create(WEBDAV_ERR_FS_PROP_BASEVALUE_MISMATCH, NULL,
  6247. b->description->data);
  6248. else
  6249. return error_create(WEBDAV_ERR_DAV_REQUEST_FAILED, NULL,
  6250. b->description->data);
  6251. }
  6252. break;
  6253. case ELEM_responsedescription:
  6254. if (b->in_propstat)
  6255. stringbuf_set(b->propstat_description, b->cdata->data);
  6256. else
  6257. {
  6258. if (!stringbuf_isempty(b->description))
  6259. stringbuf_appendcstr(b->description, "\n");
  6260. stringbuf_appendstr(b->description, b->cdata);
  6261. }
  6262. break;
  6263. case ELEM_status:
  6264. {
  6265. ne_status status;
  6266. if (ne_parse_statusline(b->cdata->data, &status) == 0)
  6267. {
  6268. // I wanted ||=, but I guess the end result is the same
  6269. if (!b->in_propstat)
  6270. b->contains_error |= (status.klass != 2);
  6271. else
  6272. b->propstat_has_error = (status.klass != 2);
  6273. // Handle "412 Precondition Failed" specially
  6274. if (status.code == 412)
  6275. b->contains_precondition_error = TRUE;
  6276. ne_free(status.reason_phrase);
  6277. }
  6278. else
  6279. return error_create(WEBDAV_ERR_DAV_REQUEST_FAILED, NULL,
  6280. "The response contains a non-conforming HTTP status line");
  6281. }
  6282. break;
  6283. case ELEM_propstat:
  6284. b->in_propstat = FALSE;
  6285. b->contains_error |= b->propstat_has_error;
  6286. stringbuf_appendcstr(b->description,
  6287. apr_psprintf(b->req->pool,
  6288. "Error setting property '%s': ",
  6289. b->propname->data));
  6290. stringbuf_appendstr(b->description,
  6291. b->propstat_description);
  6292. default:
  6293. // do nothing
  6294. break;
  6295. }
  6296. // When we have an element which wants cdata,
  6297. // we'll set it all up in start_207_element() again
  6298. b->want_cdata = NULL;
  6299. return WEBDAV_NO_ERROR;
  6300. }
  6301. // Create a status parser attached to the request REQ. Detected errors
  6302. // will be returned there.
  6303. static void
  6304. multistatus_parser_create(
  6305. neon_request_t * req)
  6306. {
  6307. multistatus_baton_t * b = static_cast<multistatus_baton_t *>(apr_pcalloc(req->pool, sizeof(*b)));
  6308. // Create a parser, attached to REQ. (Ignore the return value.)
  6309. neon_xml_parser_create(req, ne_accept_207,
  6310. start_207_element,
  6311. neon_xml_collect_cdata,
  6312. end_207_element, b);
  6313. b->cdata = stringbuf_create("", req->pool);
  6314. b->description = stringbuf_create("", req->pool);
  6315. b->req = req;
  6316. b->propname = stringbuf_create("", req->pool);
  6317. b->propstat_description = stringbuf_create("", req->pool);
  6318. }
  6319. static apr_status_t
  6320. compressed_body_reader_cleanup(
  6321. void * baton)
  6322. {
  6323. if (baton)
  6324. ne_decompress_destroy(static_cast<ne_decompress *>(baton));
  6325. return APR_SUCCESS;
  6326. }
  6327. // Attach READER as a response reader for the request REQ, with the
  6328. // acceptance function ACCPT. The response body data will be decompressed,
  6329. // if compressed, before being passed to READER. USERDATA will be passed as
  6330. // the first argument to the acceptance and reader callbacks.
  6331. static void
  6332. attach_ne_body_reader(
  6333. neon_request_t * req,
  6334. ne_accept_response accpt,
  6335. ne_block_reader reader,
  6336. void * userdata)
  6337. {
  6338. if (req->sess->compression)
  6339. {
  6340. ne_decompress * decompress =
  6341. ne_decompress_reader(req->ne_req, accpt, reader, userdata);
  6342. apr_pool_cleanup_register(req->pool,
  6343. decompress,
  6344. compressed_body_reader_cleanup,
  6345. apr_pool_cleanup_null);
  6346. }
  6347. else
  6348. ne_add_response_body_reader(req->ne_req, accpt, reader, userdata);
  6349. }
  6350. typedef struct cancellation_baton_t
  6351. {
  6352. ne_block_reader real_cb;
  6353. void * real_userdata;
  6354. neon_request_t * req;
  6355. } cancellation_baton_t;
  6356. static int
  6357. cancellation_callback(
  6358. void * userdata,
  6359. const char * block,
  6360. size_t len)
  6361. {
  6362. cancellation_baton_t * b = static_cast<cancellation_baton_t *>(userdata);
  6363. neon_session_t * ras = b->req->sess;
  6364. if (ras->callbacks->cancel_func)
  6365. {
  6366. NEON_REQ_ERR(b->req, (ras->callbacks->cancel_func)(ras->callback_baton));
  6367. }
  6368. if (b->req->err)
  6369. return 1;
  6370. else
  6371. return (b->real_cb)(b->real_userdata, block, len);
  6372. }
  6373. static cancellation_baton_t *
  6374. get_cancellation_baton(
  6375. neon_request_t * req,
  6376. ne_block_reader real_cb,
  6377. void * real_userdata,
  6378. apr_pool_t * pool)
  6379. {
  6380. cancellation_baton_t * b = static_cast<cancellation_baton_t *>(apr_pcalloc(pool, sizeof(*b)));
  6381. b->real_cb = real_cb;
  6382. b->real_userdata = real_userdata;
  6383. b->req = req;
  6384. return b;
  6385. }
  6386. typedef struct body_provider_baton_t
  6387. {
  6388. neon_request_t * req;
  6389. apr_file_t * body_file;
  6390. } body_provider_baton_t;
  6391. static ssize_t
  6392. ra_neon_body_provider(
  6393. void * userdata,
  6394. char * buffer,
  6395. size_t buflen)
  6396. {
  6397. body_provider_baton_t * b = static_cast<body_provider_baton_t *>(userdata);
  6398. neon_request_t * req = b->req;
  6399. apr_file_t * body_file = b->body_file;
  6400. if (req->sess->callbacks &&
  6401. req->sess->callbacks->cancel_func)
  6402. {
  6403. NEON_REQ_ERR(req, (req->sess->callbacks->cancel_func)(
  6404. req->sess->callback_baton));
  6405. }
  6406. if (req->err)
  6407. return -1;
  6408. webdav_pool_clear(req->iterpool);
  6409. if (buflen == 0)
  6410. {
  6411. // This is the beginning of a new body pull. Rewind the file.
  6412. apr_off_t offset = 0;
  6413. NEON_REQ_ERR(b->req, io_file_seek(body_file, APR_SET, &offset, req->iterpool));
  6414. return (req->err ? -1 : 0);
  6415. }
  6416. else
  6417. {
  6418. callback_baton_t * cb = static_cast<callback_baton_t *>(req->sess->callback_baton);
  6419. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(cb->ctx->auth_baton->parameters,
  6420. CONST_FS_KEY,
  6421. APR_HASH_KEY_STRING));
  6422. assert(fs);
  6423. fs->AdjustToCPSLimit(buflen);
  6424. apr_size_t nbytes = buflen;
  6425. error_t err = io_file_read(body_file, buffer, &nbytes,
  6426. req->iterpool);
  6427. if (err)
  6428. {
  6429. if (APR_STATUS_IS_EOF(err))
  6430. {
  6431. error_clear(&err);
  6432. return 0;
  6433. }
  6434. NEON_REQ_ERR(req, err);
  6435. return -1;
  6436. }
  6437. else
  6438. return (ssize_t)nbytes;
  6439. }
  6440. }
  6441. static error_t
  6442. neon_set_neon_body_provider(
  6443. neon_request_t * req,
  6444. apr_file_t * body_file)
  6445. {
  6446. apr_status_t status = 0;
  6447. apr_finfo_t finfo = {0};
  6448. body_provider_baton_t * b = static_cast<body_provider_baton_t *>(apr_pcalloc(req->pool, sizeof(*b)));
  6449. status = apr_file_info_get(&finfo, APR_FINFO_SIZE, body_file);
  6450. if (status)
  6451. return error_wrap_apr(status,
  6452. "Can't calculate the request body size");
  6453. b->body_file = body_file;
  6454. b->req = req;
  6455. ne_set_request_body_provider(req->ne_req, (ne_off_t)finfo.size,
  6456. ra_neon_body_provider, b);
  6457. return WEBDAV_NO_ERROR;
  6458. }
  6459. // See doc string for neon_parsed_request.
  6460. static error_t
  6461. parsed_request(
  6462. neon_request_t * req,
  6463. neon_session_t * ras,
  6464. const char * method,
  6465. const char * url,
  6466. const char * body,
  6467. apr_file_t * body_file,
  6468. void set_parser(ne_xml_parser * parser, void * baton),
  6469. neon_startelm_cb_t startelm_cb,
  6470. neon_cdata_cb_t cdata_cb,
  6471. neon_endelm_cb_t endelm_cb,
  6472. void * baton,
  6473. apr_hash_t * extra_headers,
  6474. int * status_code,
  6475. bool check_errors,
  6476. apr_pool_t * pool)
  6477. {
  6478. ne_xml_parser * success_parser = NULL;
  6479. if (body == NULL)
  6480. WEBDAV_ERR(neon_set_neon_body_provider(req, body_file));
  6481. // use a symbolic name somewhere for this MIME type?
  6482. ne_add_request_header(req->ne_req, "Content-Type", "text/xml");
  6483. // create a parser to read the normal response body
  6484. success_parser = neon_xml_parser_create(req, NULL,
  6485. startelm_cb, cdata_cb,
  6486. endelm_cb, baton);
  6487. // if our caller is interested in having access to this parser, call
  6488. // the SET_PARSER callback with BATON.
  6489. if (set_parser != NULL)
  6490. set_parser(success_parser, baton);
  6491. // Register the "main" accepter and body-reader with the request --
  6492. // the one to use when the HTTP status is 2XX.
  6493. attach_ne_body_reader(req, ne_accept_2xx, cancellation_callback,
  6494. get_cancellation_baton(req, ne_xml_parse_v,
  6495. success_parser, pool));
  6496. // run the request and get the resulting status code.
  6497. WEBDAV_ERR(neon_request_dispatch(
  6498. status_code, req, extra_headers, body,
  6499. (strcmp(method, "PROPFIND") == 0) ? 207 : 200,
  6500. 0,
  6501. check_errors,
  6502. pool));
  6503. WEBDAV_ERR(neon_check_parse_error(method, success_parser, url));
  6504. return WEBDAV_NO_ERROR;
  6505. }
  6506. static error_t
  6507. neon_parsed_request(
  6508. neon_session_t * sess,
  6509. const char * method,
  6510. const char * url,
  6511. const char * body,
  6512. apr_file_t * body_file,
  6513. void set_parser(ne_xml_parser * parser, void * baton),
  6514. neon_startelm_cb_t startelm_cb,
  6515. neon_cdata_cb_t cdata_cb,
  6516. neon_endelm_cb_t endelm_cb,
  6517. void * baton,
  6518. apr_hash_t * extra_headers,
  6519. int * status_code,
  6520. bool check_errors,
  6521. apr_pool_t * pool)
  6522. {
  6523. // create/prep the request
  6524. neon_request_t * req = NULL;
  6525. error_t err = 0;
  6526. WEBDAV_ERR(neon_request_create(&req, sess, method, url, pool));
  6527. err = parsed_request(req, sess, method, url, body, body_file,
  6528. set_parser, startelm_cb, cdata_cb, endelm_cb,
  6529. baton, extra_headers, status_code,
  6530. check_errors,
  6531. pool);
  6532. neon_request_destroy(req);
  6533. return err;
  6534. }
  6535. static error_t
  6536. neon_simple_request(
  6537. int * code,
  6538. neon_session_t * ras,
  6539. const char * method,
  6540. const char * url,
  6541. apr_hash_t * extra_headers,
  6542. const char * body,
  6543. int okay_1, int okay_2, apr_pool_t * pool)
  6544. {
  6545. neon_request_t * req = NULL;
  6546. error_t err = 0;
  6547. WEBDAV_ERR(neon_request_create(&req, ras, method, url, pool));
  6548. multistatus_parser_create(req);
  6549. // neon_request_dispatch() adds the custom error response
  6550. // reader. Neon will take care of the Content-Length calculation
  6551. err = neon_request_dispatch(code, req, extra_headers,
  6552. body ? body : "",
  6553. okay_1, okay_2, false, pool);
  6554. neon_request_destroy(req);
  6555. return err;
  6556. }
  6557. static void
  6558. neon_add_depth_header(
  6559. apr_hash_t * extra_headers,
  6560. int depth)
  6561. {
  6562. assert(extra_headers != NULL);
  6563. assert(depth == NEON_DEPTH_ZERO ||
  6564. depth == NEON_DEPTH_ONE ||
  6565. depth == NEON_DEPTH_INFINITE);
  6566. apr_hash_set(extra_headers, "Depth", APR_HASH_KEY_STRING,
  6567. (depth == NEON_DEPTH_INFINITE) ?
  6568. "infinity" : (depth == NEON_DEPTH_ZERO) ? "0" : "1");
  6569. return;
  6570. }
  6571. static const neon_xml_elm_t *
  6572. neon_lookup_xml_elem(
  6573. const neon_xml_elm_t * table,
  6574. const char * nspace,
  6575. const char * name)
  6576. {
  6577. // placeholder for `unknown' element if it's present
  6578. const neon_xml_elm_t * elem_unknown = NULL;
  6579. const neon_xml_elm_t * elem = NULL;
  6580. for (elem = table; elem->nspace; ++elem)
  6581. {
  6582. if ((strcmp(elem->nspace, nspace) == 0) &&
  6583. (strcmp(elem->name, name) == 0))
  6584. return elem;
  6585. // Use a single loop to save CPU cycles.
  6586. // Maybe this element is defined as `unknown'?
  6587. if (elem->id == ELEM_unknown)
  6588. elem_unknown = elem;
  6589. }
  6590. // ELEM_unknown position in the table or NULL
  6591. return elem_unknown;
  6592. }
  6593. static error_t
  6594. neon_xml_collect_cdata(
  6595. void * baton,
  6596. int state,
  6597. const char * cdata,
  6598. size_t len)
  6599. {
  6600. stringbuf_t ** b = static_cast<stringbuf_t **>(baton);
  6601. if (*b)
  6602. stringbuf_appendbytes(*b, cdata, len);
  6603. return WEBDAV_NO_ERROR;
  6604. }
  6605. // Custom function of type ne_accept_response.
  6606. static int
  6607. ra_neon_error_accepter(
  6608. void * userdata,
  6609. ne_request * req,
  6610. const ne_status * st)
  6611. {
  6612. // Before, this function was being run for *all* responses including
  6613. // the 401 auth challenge. In neon 0.24.x that was harmless. But
  6614. // in neon 0.25.0, trying to parse a 401 response as XML using
  6615. // ne_xml_parse_v aborts the response; so the auth hooks never got a
  6616. // chance.
  6617. ne_content_type ctype = {0};
  6618. // Only accept non-2xx responses with text/xml content-type
  6619. if (st->klass != 2 && ne_get_content_type(req, &ctype) == 0)
  6620. {
  6621. int is_xml = (strcmp(ctype.type, "text") == 0) &&
  6622. (strcmp(ctype.subtype, "xml") == 0);
  6623. ne_free(ctype.value);
  6624. return is_xml;
  6625. }
  6626. else
  6627. return 0;
  6628. }
  6629. static const neon_xml_elm_t error_elements[] =
  6630. {
  6631. { "DAV:", "error", ELEM_error, 0 },
  6632. {
  6633. "http://apache.org/dav/xmlns", "human-readable",
  6634. ELEM_human_readable, NEON_XML_CDATA
  6635. },
  6636. // our validator doesn't yet recognize the rich, specific
  6637. // <D:some-condition-failed/> objects as defined by DeltaV.
  6638. { NULL }
  6639. };
  6640. static error_t
  6641. xml_parser_cleanup(void * baton)
  6642. {
  6643. ne_xml_destroy(static_cast<ne_xml_parser *>(baton));
  6644. return WEBDAV_NO_ERROR;
  6645. }
  6646. static ne_xml_parser *
  6647. xml_parser_create(
  6648. neon_request_t * req)
  6649. {
  6650. ne_xml_parser * p = ne_xml_create();
  6651. // HACK: Set the parser's error to the empty string. Someday we
  6652. // hope neon will let us have an easy way to tell the difference
  6653. // between XML parsing errors, and errors that occur while handling
  6654. // the XML tags that we get. Until then, trust that whenever neon
  6655. // has an error somewhere below the API, it sets its own error to
  6656. // something non-empty (the API promises non-NULL, at least).
  6657. ne_xml_set_error(p, "");
  6658. apr_pool_cleanup_register(req->pool, p,
  6659. xml_parser_cleanup,
  6660. apr_pool_cleanup_null);
  6661. return p;
  6662. }
  6663. static int
  6664. validate_error_elements(
  6665. neon_xml_elmid parent,
  6666. neon_xml_elmid child)
  6667. {
  6668. switch (parent)
  6669. {
  6670. case ELEM_root:
  6671. if (child == ELEM_error)
  6672. return child;
  6673. else
  6674. return NEON_XML_INVALID;
  6675. case ELEM_error:
  6676. if ((child == ELEM_error) ||
  6677. (child == ELEM_human_readable))
  6678. return child;
  6679. else
  6680. return NEON_XML_DECLINE; // ignore if something else
  6681. // was in there
  6682. default:
  6683. return NEON_XML_DECLINE;
  6684. }
  6685. // NOTREACHED
  6686. }
  6687. static error_t
  6688. generate_error(
  6689. neon_request_t * req,
  6690. apr_pool_t * pool)
  6691. {
  6692. int errcode = WEBDAV_ERR_DAV_REQUEST_FAILED;
  6693. const char * context =
  6694. apr_psprintf(req->pool, "%s of '%s'", req->method, req->url);
  6695. const char * msg = NULL;
  6696. const char * hostport = NULL;
  6697. // Convert the return codes.
  6698. switch (req->rv)
  6699. {
  6700. case NE_OK:
  6701. switch (req->code)
  6702. {
  6703. case 404:
  6704. return error_create(WEBDAV_ERR_FS_NOT_FOUND, NULL,
  6705. apr_psprintf(pool, "'%s' path not found", req->url));
  6706. case 403:
  6707. return error_create(WEBDAV_ERR_DAV_FORBIDDEN, NULL,
  6708. apr_psprintf(pool, "Access to '%s' forbidden",
  6709. req->url));
  6710. case 301:
  6711. case 302:
  6712. case 307:
  6713. return error_create(WEBDAV_ERR_DAV_RELOCATED, NULL,
  6714. apr_psprintf(pool, (req->code == 301) ?
  6715. "WebDAV resource moved permanently to '%s';"
  6716. " please relocate"
  6717. : "WebDAV resource moved temporarily to '%s';"
  6718. " please relocate",
  6719. neon_request_get_location(req, pool)));
  6720. default:
  6721. return error_create(errcode, NULL,
  6722. apr_psprintf(pool,
  6723. "Server sent unexpected return value (%d %s) "
  6724. "in response to %s request for '%s'", req->code,
  6725. req->code_desc, req->method, req->url));
  6726. }
  6727. case NE_AUTH:
  6728. case NE_PROXYAUTH:
  6729. errcode = WEBDAV_ERR_NOT_AUTHORIZED;
  6730. // neon >= 0.27 gives a descriptive error message after auth
  6731. // failure; expose this since it's a useful diagnostic e.g. for
  6732. // an unsupported challenge scheme, or a local GSSAPI error due
  6733. // to an expired ticket.
  6734. WEBDAV_ERR(utf_cstring_to_utf8(&msg, ne_get_error(req->ne_sess), pool));
  6735. msg = apr_psprintf(pool, "authorization failed: %s", msg);
  6736. break;
  6737. case NE_CONNECT:
  6738. msg = "could not connect to server";
  6739. break;
  6740. case NE_TIMEOUT:
  6741. msg = "timed out waiting for server";
  6742. break;
  6743. default:
  6744. // Get the error string from neon and convert to UTF-8.
  6745. WEBDAV_ERR(utf_cstring_to_utf8(&msg, ne_get_error(req->ne_sess), pool));
  6746. break;
  6747. }
  6748. // The hostname may contain non-ASCII characters, so convert it to UTF-8.
  6749. WEBDAV_ERR(utf_cstring_to_utf8(&hostport,
  6750. ne_get_server_hostport(req->ne_sess), pool));
  6751. // This is a translation nightmare. Make sure to compose full strings
  6752. // and mark those for translation.
  6753. return error_createf(errcode, NULL, "%s: %s (%s://%s)",
  6754. context, msg, ne_get_scheme(req->ne_sess),
  6755. hostport);
  6756. }
  6757. typedef struct error_parser_baton
  6758. {
  6759. stringbuf_t * want_cdata;
  6760. stringbuf_t * cdata;
  6761. error_t * dst_err;
  6762. error_t tmp_err;
  6763. bool * marshalled_error;
  6764. } error_parser_baton_t;
  6765. static int
  6766. start_err_element(
  6767. void * baton,
  6768. int parent,
  6769. const char * nspace,
  6770. const char * name,
  6771. const char ** atts)
  6772. {
  6773. const neon_xml_elm_t * elm = neon_lookup_xml_elem(error_elements, nspace, name);
  6774. int acc = elm ? validate_error_elements(parent, elm->id) : NEON_XML_DECLINE;
  6775. error_parser_baton_t * b = static_cast<error_parser_baton_t *>(baton);
  6776. error_t * err = &(b->tmp_err);
  6777. if (acc < 1) // ! > 0
  6778. return acc;
  6779. switch (elm->id)
  6780. {
  6781. case ELEM_error:
  6782. {
  6783. // allocate the error_t. Hopefully the value will be
  6784. // overwritten by the <human-readable> tag, or even someday by
  6785. // a <D:failed-precondition/> tag.
  6786. *err = error_create(APR_EGENERAL, NULL,
  6787. "General svn error from server");
  6788. break;
  6789. }
  6790. case ELEM_human_readable:
  6791. {
  6792. // get the errorcode attribute if present
  6793. const char * errcode_str =
  6794. xml_get_attr_value("errcode", // make constant in
  6795. // some mod_dav header?
  6796. atts);
  6797. if (errcode_str && *err)
  6798. {
  6799. apr_int64_t val;
  6800. error_t err2;
  6801. err2 = cstring_atoi64(&val, errcode_str);
  6802. if (err2)
  6803. {
  6804. error_clear(&err2);
  6805. break;
  6806. }
  6807. }
  6808. break;
  6809. }
  6810. default:
  6811. break;
  6812. }
  6813. switch (elm->id)
  6814. {
  6815. case ELEM_human_readable:
  6816. b->want_cdata = b->cdata;
  6817. stringbuf_setempty(b->want_cdata);
  6818. break;
  6819. default:
  6820. b->want_cdata = NULL;
  6821. break;
  6822. }
  6823. return elm->id;
  6824. }
  6825. static int
  6826. end_err_element(
  6827. void * baton,
  6828. int state,
  6829. const char * nspace,
  6830. const char * name)
  6831. {
  6832. error_parser_baton_t * b = static_cast<error_parser_baton_t *>(baton);
  6833. error_t * err = &(b->tmp_err);
  6834. switch (state)
  6835. {
  6836. case ELEM_human_readable:
  6837. {
  6838. if (b->cdata->data && err)
  6839. {
  6840. // On the server dav_error_response_tag() will add a leading
  6841. // and trailing newline if DEBUG_CR is defined in mod_dav.h,
  6842. // so remove any such characters here.
  6843. apr_size_t len;
  6844. const char * cd = b->cdata->data;
  6845. if (*cd == '\n')
  6846. ++cd;
  6847. len = strlen(cd);
  6848. if (len > 0 && cd[len - 1] == '\n')
  6849. --len;
  6850. }
  6851. break;
  6852. }
  6853. case ELEM_error:
  6854. {
  6855. if (b->dst_err)
  6856. error_clear(&b->tmp_err);
  6857. else if (b->tmp_err)
  6858. {
  6859. b->dst_err = &b->tmp_err;
  6860. if (b->marshalled_error)
  6861. *(b->marshalled_error) = TRUE;
  6862. }
  6863. b->tmp_err = NULL;
  6864. break;
  6865. }
  6866. default:
  6867. break;
  6868. }
  6869. return 0;
  6870. }
  6871. static int
  6872. collect_error_cdata(
  6873. void * baton,
  6874. int state,
  6875. const char * cdata,
  6876. size_t len)
  6877. {
  6878. stringbuf_t ** b = static_cast<stringbuf_t **>(baton);
  6879. if (*b)
  6880. stringbuf_appendbytes(*b, cdata, len);
  6881. return 0;
  6882. }
  6883. static apr_status_t
  6884. error_parser_baton_cleanup(
  6885. void * baton)
  6886. {
  6887. error_parser_baton_t * b = static_cast<error_parser_baton_t *>(baton);
  6888. if (b->tmp_err)
  6889. error_clear(&b->tmp_err);
  6890. return APR_SUCCESS;
  6891. }
  6892. static ne_xml_parser *
  6893. error_parser_create(
  6894. neon_request_t * req)
  6895. {
  6896. error_parser_baton_t * b = static_cast<error_parser_baton_t *>(apr_pcalloc(req->pool, sizeof(*b)));
  6897. ne_xml_parser * error_parser = NULL;
  6898. b->dst_err = &(req->err);
  6899. b->marshalled_error = &(req->marshalled_error);
  6900. b->tmp_err = NULL;
  6901. b->want_cdata = NULL;
  6902. b->cdata = stringbuf_create("", req->pool);
  6903. // attach a standard <D:error> body parser to the request
  6904. error_parser = xml_parser_create(req);
  6905. ne_xml_push_handler(error_parser,
  6906. start_err_element,
  6907. collect_error_cdata,
  6908. end_err_element, b);
  6909. apr_pool_cleanup_register(req->pool, b,
  6910. error_parser_baton_cleanup,
  6911. apr_pool_cleanup_null);
  6912. // Register the "error" accepter and body-reader with the request --
  6913. // the one to use when HTTP status is *not* 2XX
  6914. attach_ne_body_reader(req, ra_neon_error_accepter,
  6915. ne_xml_parse_v, error_parser);
  6916. return error_parser;
  6917. }
  6918. static error_t
  6919. neon_maybe_store_auth_info(
  6920. neon_session_t * ras,
  6921. apr_pool_t * pool)
  6922. {
  6923. // No auth_baton? Never mind.
  6924. if (!ras->callbacks->auth_baton)
  6925. return WEBDAV_NO_ERROR;
  6926. // If we ever got credentials, ask the iter_baton to save them.
  6927. return auth_save_credentials(ras->auth_iterstate, pool);
  6928. }
  6929. // A baton that is used along with a set of Neon ne_startelm_cb,
  6930. // ne_cdata_cb, and ne_endelm_cb callbacks to handle conversion
  6931. // from our style errors to Neon style errors.
  6932. // The underlying callbacks are called, and if errors
  6933. // are returned they are stored in this baton and a Neon level
  6934. // error code is returned to the parser.
  6935. typedef struct parser_wrapper_baton_t
  6936. {
  6937. neon_request_t * req;
  6938. ne_xml_parser * parser;
  6939. void * baton;
  6940. neon_startelm_cb_t startelm_cb;
  6941. neon_cdata_cb_t cdata_cb;
  6942. neon_endelm_cb_t endelm_cb;
  6943. } parser_wrapper_baton_t;
  6944. static int
  6945. wrapper_startelm_cb(
  6946. void * baton,
  6947. int parent,
  6948. const char * nspace,
  6949. const char * name,
  6950. const char ** atts)
  6951. {
  6952. parser_wrapper_baton_t * pwb = static_cast<parser_wrapper_baton_t *>(baton);
  6953. int elem = NEON_XML_DECLINE;
  6954. if (pwb->startelm_cb)
  6955. {
  6956. NEON_REQ_ERR(pwb->req, pwb->startelm_cb(&elem, pwb->baton, parent, nspace,
  6957. name, atts));
  6958. }
  6959. if (elem == NEON_XML_INVALID)
  6960. {
  6961. NEON_REQ_ERR(pwb->req, error_create(WEBDAV_ERR_XML_MALFORMED, NULL, NULL));
  6962. }
  6963. if (pwb->req->err)
  6964. return NE_XML_ABORT;
  6965. return elem;
  6966. }
  6967. static int
  6968. wrapper_cdata_cb(
  6969. void * baton,
  6970. int state,
  6971. const char * cdata,
  6972. size_t len)
  6973. {
  6974. parser_wrapper_baton_t * pwb = static_cast<parser_wrapper_baton_t *>(baton);
  6975. if (pwb->cdata_cb)
  6976. {
  6977. NEON_REQ_ERR(pwb->req, pwb->cdata_cb(pwb->baton, state, cdata, len));
  6978. }
  6979. if (pwb->req->err)
  6980. return NE_XML_ABORT;
  6981. return 0;
  6982. }
  6983. static int
  6984. wrapper_endelm_cb(
  6985. void * baton,
  6986. int state,
  6987. const char * nspace,
  6988. const char * name)
  6989. {
  6990. parser_wrapper_baton_t * pwb = static_cast<parser_wrapper_baton_t *>(baton);
  6991. if (pwb->endelm_cb)
  6992. {
  6993. NEON_REQ_ERR(pwb->req, pwb->endelm_cb(pwb->baton, state, nspace, name));
  6994. }
  6995. if (pwb->req->err)
  6996. return NE_XML_ABORT;
  6997. return 0;
  6998. }
  6999. static error_t
  7000. neon_check_parse_error(
  7001. const char * method,
  7002. ne_xml_parser * xml_parser,
  7003. const char * url)
  7004. {
  7005. const char * msg = ne_xml_get_error(xml_parser);
  7006. if (msg != NULL && *msg != '\0')
  7007. return error_createf(WEBDAV_ERR_DAV_REQUEST_FAILED, NULL,
  7008. "The %s request returned invalid XML "
  7009. "in the response: %s (%s)",
  7010. method, msg, url);
  7011. return WEBDAV_NO_ERROR;
  7012. }
  7013. static int
  7014. wrapper_reader_cb(
  7015. void * baton,
  7016. const char * data,
  7017. size_t len)
  7018. {
  7019. parser_wrapper_baton_t * pwb = static_cast<parser_wrapper_baton_t *>(baton);
  7020. neon_session_t * sess = pwb->req->sess;
  7021. int parser_status = 0;
  7022. if (pwb->req->err)
  7023. return 1;
  7024. if (sess->callbacks->cancel_func)
  7025. {
  7026. NEON_REQ_ERR(pwb->req, (sess->callbacks->cancel_func)(sess->callback_baton));
  7027. }
  7028. if (pwb->req->err)
  7029. return 1;
  7030. if (len)
  7031. parser_status = ne_xml_parse(pwb->parser, data, len);
  7032. if (parser_status)
  7033. {
  7034. // Pass XML parser error.
  7035. NEON_REQ_ERR(pwb->req, neon_check_parse_error(pwb->req->method,
  7036. pwb->parser,
  7037. pwb->req->url));
  7038. }
  7039. return parser_status;
  7040. }
  7041. // Create a Neon xml parser with callbacks STARTELM_CB, ENDELM_CB and
  7042. // CDATA_CB. The created parser wraps the Neon callbacks and marshals any
  7043. // errors returned by the callbacks through the Neon layer. Any errors
  7044. // raised will be returned by neon_request_dispatch() unless
  7045. // an earlier error occurred.
  7046. // Register a pool cleanup on the pool of REQ to clean up any allocated
  7047. // Neon resources.
  7048. // Return the new parser. Also attach it to REQ if ACCPT is non-null.
  7049. // ACCPT indicates whether the parser wants to read the response body
  7050. // or not. Pass NULL for ACCPT when you don't want the returned parser
  7051. // to be attached to REQ.
  7052. static ne_xml_parser *
  7053. neon_xml_parser_create(
  7054. neon_request_t * req,
  7055. ne_accept_response accpt,
  7056. neon_startelm_cb_t startelm_cb,
  7057. neon_cdata_cb_t cdata_cb,
  7058. neon_endelm_cb_t endelm_cb,
  7059. void * baton)
  7060. {
  7061. ne_xml_parser * p = xml_parser_create(req);
  7062. parser_wrapper_baton_t * pwb = static_cast<parser_wrapper_baton_t *>(apr_pcalloc(req->pool, sizeof(*pwb)));
  7063. pwb->req = req;
  7064. pwb->parser = p;
  7065. pwb->baton = baton;
  7066. pwb->startelm_cb = startelm_cb;
  7067. pwb->cdata_cb = cdata_cb;
  7068. pwb->endelm_cb = endelm_cb;
  7069. ne_xml_push_handler(p,
  7070. wrapper_startelm_cb,
  7071. wrapper_cdata_cb,
  7072. wrapper_endelm_cb, pwb);
  7073. if (accpt)
  7074. attach_ne_body_reader(req, accpt, wrapper_reader_cb, pwb);
  7075. return p;
  7076. }
  7077. static error_t
  7078. neon_request_dispatch(
  7079. int * code_p,
  7080. neon_request_t * req,
  7081. apr_hash_t * extra_headers,
  7082. const char * body,
  7083. int okay_1,
  7084. int okay_2,
  7085. bool check_errors,
  7086. apr_pool_t * pool)
  7087. {
  7088. // add any extra headers passed in by caller.
  7089. if (extra_headers != NULL)
  7090. {
  7091. for (apr_hash_index_t * hi = apr_hash_first(pool, extra_headers); hi;
  7092. hi = apr_hash_next(hi))
  7093. {
  7094. const void * key;
  7095. void * val;
  7096. apr_hash_this(hi, &key, NULL, &val);
  7097. ne_add_request_header(req->ne_req,
  7098. static_cast<const char *>(key), static_cast<const char *>(val));
  7099. }
  7100. }
  7101. if (body)
  7102. ne_set_request_body_buffer(req->ne_req, body, strlen(body));
  7103. // attach a standard <D:error> body parser to the request
  7104. ne_xml_parser * error_parser = error_parser_create(req);
  7105. if (check_errors)
  7106. multistatus_parser_create(req);
  7107. // run the request, see what comes back.
  7108. req->rv = ne_request_dispatch(req->ne_req);
  7109. // Save values from the request
  7110. const ne_status * statstruct = ne_get_status(req->ne_req);
  7111. req->code_desc = apr_pstrdup(pool, statstruct->reason_phrase);
  7112. req->code = statstruct->code;
  7113. // If we see a successful request that used authentication, we should store
  7114. // the credentials for future use.
  7115. if ((req->sess->auth_used) && (statstruct->code < 400))
  7116. {
  7117. req->sess->auth_used = FALSE;
  7118. WEBDAV_ERR(neon_maybe_store_auth_info(req->sess, pool));
  7119. }
  7120. if (code_p)
  7121. *code_p = req->code;
  7122. if (!req->marshalled_error && req->err)
  7123. WEBDAV_ERR(req->err);
  7124. // If the status code was one of the two that we expected, then go
  7125. // ahead and return now. IGNORE any marshalled error.
  7126. if ((req->rv == NE_OK) && (req->code == okay_1 || req->code == okay_2))
  7127. return WEBDAV_NO_ERROR;
  7128. // Any other errors? Report them
  7129. if (req->err)
  7130. WEBDAV_ERR(req->err);
  7131. WEBDAV_ERR(neon_check_parse_error(req->method, error_parser, req->url));
  7132. // We either have a neon error, or some other error
  7133. // that we didn't expect.
  7134. return generate_error(req, pool);
  7135. }
  7136. static const char *
  7137. neon_request_get_location(
  7138. neon_request_t * request,
  7139. apr_pool_t * pool)
  7140. {
  7141. const char * val = ne_get_response_header(request->ne_req, "Location");
  7142. return val ? urlpath_canonicalize(val, pool) : NULL;
  7143. }
  7144. static error_t
  7145. neon_request_create(
  7146. neon_request_t ** request,
  7147. neon_session_t * sess,
  7148. const char * method, const char * url,
  7149. apr_pool_t * pool)
  7150. {
  7151. apr_pool_t * reqpool = webdav_pool_create(pool);
  7152. neon_request_t * req = NULL;
  7153. const char * path = NULL;
  7154. // We never want to send Neon an absolute URL, since that can cause
  7155. // problems with some servers (for example, those that may be accessed
  7156. // using different server names from different locations, or those that
  7157. // want to rewrite the incoming URL). If the URL passed in is absolute,
  7158. // convert it to a path-absolute relative URL.
  7159. path = path_from_url(url);
  7160. req = static_cast<neon_request_t *>(apr_pcalloc(reqpool, sizeof(*req)));
  7161. req->ne_sess = sess->ne_sess;
  7162. req->ne_req = ne_request_create(req->ne_sess, method, path);
  7163. req->sess = sess;
  7164. req->pool = reqpool;
  7165. req->iterpool = webdav_pool_create(req->pool);
  7166. req->method = apr_pstrdup(req->pool, method);
  7167. req->url = apr_pstrdup(req->pool, url);
  7168. req->rv = -1;
  7169. // Neon resources may be NULL on out-of-memory
  7170. assert(req->ne_req != NULL);
  7171. apr_pool_cleanup_register(sess->pool, req,
  7172. dav_request_sess_cleanup,
  7173. apr_pool_cleanup_null);
  7174. apr_pool_cleanup_register(reqpool, req,
  7175. dav_request_cleanup,
  7176. apr_pool_cleanup_null);
  7177. *request = req;
  7178. return WEBDAV_NO_ERROR;
  7179. }
  7180. static error_t
  7181. get_path_relative_to_session(
  7182. session_t * session,
  7183. const char ** rel_path,
  7184. const char * url,
  7185. apr_pool_t * pool)
  7186. {
  7187. const char * sess_url = NULL;
  7188. WEBDAV_ERR(session->vtable->get_session_url(session, &sess_url, pool));
  7189. if (strcmp(sess_url, url) == 0)
  7190. {
  7191. *rel_path = "";
  7192. }
  7193. else
  7194. {
  7195. *rel_path = uri_is_child(sess_url, url, pool);
  7196. if (!*rel_path)
  7197. {
  7198. return error_createf(WEBDAV_ERR_ILLEGAL_URL, NULL,
  7199. "'%s' isn't a child of session URL '%s'", url, sess_url);
  7200. }
  7201. }
  7202. return WEBDAV_NO_ERROR;
  7203. }
  7204. static error_t
  7205. client_path_relative_to_root(
  7206. const char ** rel_path,
  7207. const char * abspath_or_url,
  7208. const char * webdav_root,
  7209. bool include_leading_slash,
  7210. session_t * ra_session,
  7211. apr_pool_t * result_pool,
  7212. apr_pool_t * scratch_pool)
  7213. {
  7214. const char * webdav_relpath = NULL;
  7215. if (!path_is_url(abspath_or_url))
  7216. {
  7217. error_createf(WEBDAV_ERR_DAV_NOT_IMPLEMENTED, NULL,
  7218. "not implemented: 'client_path_relative_to_root'");
  7219. }
  7220. // Merge handling passes a root that is not WebDAV resource root
  7221. else if (webdav_root != NULL)
  7222. {
  7223. /*if (!uri_is_ancestor(webdav_root, abspath_or_url))
  7224. return error_createf(WEBDAV_ERR_CLIENT_UNRELATED_RESOURCES, NULL,
  7225. "URL '%s' is not a child of "
  7226. "root URL '%s'",
  7227. abspath_or_url, webdav_root);*/
  7228. webdav_relpath = uri_skip_ancestor(webdav_root, abspath_or_url,
  7229. result_pool);
  7230. }
  7231. else
  7232. {
  7233. error_t err = 0;
  7234. WEBDAV_ERR_ASSERT(ra_session != NULL);
  7235. // Ask the RA layer to create a relative path for us
  7236. err = get_path_relative_to_root(ra_session, &webdav_relpath,
  7237. abspath_or_url, scratch_pool);
  7238. if (err)
  7239. {
  7240. if (err == WEBDAV_ERR_ILLEGAL_URL)
  7241. {
  7242. return error_createf(WEBDAV_ERR_CLIENT_UNRELATED_RESOURCES, &err,
  7243. "URL '%s' is not inside WebDAV resource root", abspath_or_url);
  7244. }
  7245. return error_trace(err);
  7246. }
  7247. }
  7248. if (include_leading_slash)
  7249. *rel_path = apr_pstrcat(result_pool, "/", webdav_relpath, NULL);
  7250. else
  7251. *rel_path = webdav_relpath;
  7252. return WEBDAV_NO_ERROR;
  7253. }
  7254. static const char *
  7255. neon_uri_unparse(
  7256. const ne_uri * uri,
  7257. apr_pool_t * pool)
  7258. {
  7259. char * unparsed_uri = NULL;
  7260. const char * result = NULL;
  7261. // Unparse uri.
  7262. unparsed_uri = ne_uri_unparse(uri);
  7263. result = uri_canonicalize(unparsed_uri, pool);
  7264. // Free neon's allocated copy.
  7265. ne_free(unparsed_uri);
  7266. // Return string allocated in result pool.
  7267. return result;
  7268. }
  7269. typedef struct body_reader_wrapper_baton_t
  7270. {
  7271. neon_request_t * req;
  7272. neon_block_reader real_reader;
  7273. void * real_baton;
  7274. } body_reader_wrapper_baton_t;
  7275. static int
  7276. body_reader_wrapper(
  7277. void * userdata,
  7278. const char * data,
  7279. size_t len)
  7280. {
  7281. body_reader_wrapper_baton_t * b = static_cast<body_reader_wrapper_baton_t *>(userdata);
  7282. if (b->req->err)
  7283. // We already had an error? Bail out.
  7284. return 1;
  7285. NEON_REQ_ERR(b->req, b->real_reader(b->real_baton, data, len));
  7286. if (b->req->err)
  7287. return 1;
  7288. return 0;
  7289. }
  7290. static void
  7291. neon_add_response_body_reader(
  7292. neon_request_t * req,
  7293. ne_accept_response accpt,
  7294. neon_block_reader reader,
  7295. void * userdata)
  7296. {
  7297. body_reader_wrapper_baton_t * b = static_cast<body_reader_wrapper_baton_t *>(apr_pcalloc(req->pool, sizeof(*b)));
  7298. b->req = req;
  7299. b->real_baton = userdata;
  7300. b->real_reader = reader;
  7301. attach_ne_body_reader(req, accpt, body_reader_wrapper, b);
  7302. }
  7303. //------------------------------------------------------------------------------
  7304. // from fetch.c
  7305. typedef struct file_read_ctx_t
  7306. {
  7307. apr_pool_t * pool;
  7308. // these two are the handler that the editor gave us
  7309. void * handler_baton;
  7310. // if we're receiving an svndiff, this is a parser which places the
  7311. // resulting windows into the above handler/baton.
  7312. stream_t * stream;
  7313. } file_read_ctx_t;
  7314. typedef struct file_write_ctx_t
  7315. {
  7316. stream_t * stream; // stream to write file contents to
  7317. } file_write_ctx_t;
  7318. typedef struct custom_get_ctx_t
  7319. {
  7320. neon_request_t * req; // Used to propagate errors out of the reader
  7321. int checked_type; // have we processed ctype yet?
  7322. void * subctx;
  7323. void * callback_baton;
  7324. } custom_get_ctx_t;
  7325. // Helper for neon_get_file. This implements
  7326. // the neon_block_reader() callback interface.
  7327. static error_t
  7328. get_file_reader(
  7329. void * userdata,
  7330. const char * buf,
  7331. size_t len)
  7332. {
  7333. custom_get_ctx_t * cgc = static_cast<custom_get_ctx_t *>(userdata);
  7334. if (cgc->req->sess->callbacks &&
  7335. cgc->req->sess->callbacks->cancel_func)
  7336. {
  7337. NEON_REQ_ERR(cgc->req, (cgc->req->sess->callbacks->cancel_func)(
  7338. cgc->req->sess->callback_baton));
  7339. }
  7340. assert(cgc->callback_baton);
  7341. callback_baton_t * cb = static_cast<callback_baton_t *>(cgc->callback_baton);
  7342. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(cb->ctx->auth_baton->parameters,
  7343. CONST_FS_KEY,
  7344. APR_HASH_KEY_STRING));
  7345. assert(fs);
  7346. fs->AdjustToCPSLimit(len);
  7347. // The stream we want to push data at.
  7348. file_write_ctx_t * fwc = static_cast<file_write_ctx_t *>(cgc->subctx);
  7349. stream_t * stream = fwc->stream;
  7350. // Write however many bytes were passed in by neon.
  7351. WEBDAV_ERR(stream_write(stream, buf, &len));
  7352. return WEBDAV_NO_ERROR;
  7353. }
  7354. static error_t
  7355. custom_get_request(
  7356. neon_session_t * ras,
  7357. const char * url,
  7358. const char * editor_relpath,
  7359. neon_block_reader reader,
  7360. void * subctx,
  7361. void * cb_baton,
  7362. apr_pool_t * pool)
  7363. {
  7364. custom_get_ctx_t cgc = { 0 };
  7365. neon_request_t * request = NULL;
  7366. error_t err = 0;
  7367. WEBDAV_ERR(neon_request_create(&request, ras, "GET", url, pool));
  7368. neon_add_response_body_reader(request, ne_accept_2xx, reader, &cgc);
  7369. // complete initialization of the body reading context
  7370. cgc.req = request;
  7371. cgc.subctx = subctx;
  7372. cgc.callback_baton = cb_baton;
  7373. // run the request
  7374. err = neon_request_dispatch(NULL, request, NULL, NULL,
  7375. 200 /* OK */,
  7376. 226 /* IM Used */,
  7377. false,
  7378. pool);
  7379. neon_request_destroy(request);
  7380. // The request runner raises internal errors before Neon errors,
  7381. // pass a returned error to our callers
  7382. return err;
  7383. }
  7384. //------------------------------------------------------------------------------
  7385. static error_t
  7386. get_file(
  7387. session_t * session,
  7388. const char * path,
  7389. stream_t * stream,
  7390. apr_hash_t ** props,
  7391. apr_pool_t * pool)
  7392. {
  7393. WEBDAV_ERR_ASSERT(*path != '/');
  7394. return session->vtable->get_file(session, path,
  7395. stream,
  7396. props, pool);
  7397. }
  7398. static error_t
  7399. get_dir2(
  7400. session_t * session,
  7401. apr_hash_t ** dirents,
  7402. const char * path,
  7403. apr_uint32_t dirent_fields,
  7404. apr_pool_t * pool)
  7405. {
  7406. WEBDAV_ERR_ASSERT(*path != '/');
  7407. return session->vtable->get_dir(session, dirents,
  7408. path,
  7409. dirent_fields, pool);
  7410. }
  7411. static error_t
  7412. get_webdav_resource_root2(
  7413. session_t * session,
  7414. const char ** url,
  7415. apr_pool_t * pool)
  7416. {
  7417. WEBDAV_ERR(session->vtable->get_webdav_resource_root(session, url, pool));
  7418. *url = *url ? apr_pstrdup(pool, *url) : NULL;
  7419. return WEBDAV_NO_ERROR;
  7420. }
  7421. static error_t
  7422. stat(
  7423. session_t * session,
  7424. const char * path,
  7425. dirent_t ** dirent,
  7426. apr_pool_t * pool)
  7427. {
  7428. WEBDAV_ERR_ASSERT(*path != '/');
  7429. return session->vtable->stat(session, path,
  7430. dirent, pool);
  7431. }
  7432. static error_t
  7433. get_path_relative_to_root(
  7434. session_t * session,
  7435. const char ** rel_path,
  7436. const char * url,
  7437. apr_pool_t * pool)
  7438. {
  7439. const char * root_url = NULL;
  7440. WEBDAV_ERR(session->vtable->get_webdav_resource_root(session, &root_url, pool));
  7441. if (strcmp(root_url, url) == 0)
  7442. {
  7443. *rel_path = "";
  7444. }
  7445. else
  7446. {
  7447. *rel_path = uri_is_child(root_url, url, pool);
  7448. if (!*rel_path)
  7449. {
  7450. return error_createf(WEBDAV_ERR_ILLEGAL_URL, NULL,
  7451. "'%s' isn't a child of root URL '%s'", url, root_url);
  7452. }
  7453. }
  7454. return WEBDAV_NO_ERROR;
  7455. }
  7456. static error_t
  7457. check_path(
  7458. session_t * session,
  7459. const char * path,
  7460. node_kind_t * kind,
  7461. apr_pool_t * pool)
  7462. {
  7463. WEBDAV_ERR_ASSERT(*path != '/');
  7464. return session->vtable->check_path(session, path,
  7465. kind, pool);
  7466. }
  7467. static error_t
  7468. reparent(
  7469. session_t * session,
  7470. const char * url,
  7471. apr_pool_t * pool)
  7472. {
  7473. return session->vtable->reparent(session, url, pool);
  7474. }
  7475. static error_t
  7476. session_open(
  7477. session_t ** session_p,
  7478. const char ** corrected_url_p,
  7479. const char * session_URL,
  7480. const callbacks2_t * callbacks,
  7481. void * callback_baton,
  7482. apr_pool_t * pool)
  7483. {
  7484. assert(callback_baton);
  7485. // check options, url, prepare parameters, callbacks, auth etc
  7486. apr_pool_t * sesspool = webdav_pool_create(pool);
  7487. // Initialize the return variable.
  7488. *session_p = NULL;
  7489. ne_uri * webdav_URI = NULL;
  7490. error_t err = parse_ne_uri(&webdav_URI, session_URL, sesspool);
  7491. if ((err != WEBDAV_NO_ERROR) || (webdav_URI->host == NULL))
  7492. {
  7493. return error_createf(WEBDAV_ERR_ILLEGAL_URL, NULL,
  7494. "Illegal URL '%s'", session_URL);
  7495. }
  7496. // Auth caching parameters.
  7497. bool store_passwords = WEBDAV_CONFIG_DEFAULT_OPTION_STORE_PASSWORDS;
  7498. bool store_auth_creds = WEBDAV_CONFIG_DEFAULT_OPTION_STORE_AUTH_CREDS;
  7499. const char * store_plaintext_passwords = WEBDAV_CONFIG_DEFAULT_OPTION_STORE_PLAINTEXT_PASSWORDS;
  7500. bool store_pp = WEBDAV_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP;
  7501. const char * store_pp_plaintext = WEBDAV_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT;
  7502. if (callbacks->auth_baton)
  7503. {
  7504. if (auth_baton_get_parameter(callbacks->auth_baton,
  7505. WEBDAV_AUTH_PARAM_DONT_STORE_PASSWORDS) != NULL)
  7506. {
  7507. store_passwords = FALSE;
  7508. }
  7509. if (auth_baton_get_parameter(callbacks->auth_baton,
  7510. WEBDAV_AUTH_PARAM_NO_AUTH_CACHE) != NULL)
  7511. {
  7512. store_auth_creds = FALSE;
  7513. }
  7514. }
  7515. if (callbacks->auth_baton)
  7516. {
  7517. // Save auth caching parameters in the auth parameter hash.
  7518. if (!store_passwords)
  7519. auth_baton_set_parameter(callbacks->auth_baton,
  7520. WEBDAV_AUTH_PARAM_DONT_STORE_PASSWORDS, "");
  7521. auth_baton_set_parameter(callbacks->auth_baton,
  7522. WEBDAV_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS,
  7523. store_plaintext_passwords);
  7524. if (!store_pp)
  7525. auth_baton_set_parameter(callbacks->auth_baton,
  7526. WEBDAV_AUTH_PARAM_DONT_STORE_SSL_CLIENT_CERT_PP,
  7527. "");
  7528. auth_baton_set_parameter(callbacks->auth_baton,
  7529. WEBDAV_AUTH_PARAM_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT,
  7530. store_pp_plaintext);
  7531. if (!store_auth_creds)
  7532. auth_baton_set_parameter(callbacks->auth_baton,
  7533. WEBDAV_AUTH_PARAM_NO_AUTH_CACHE, "");
  7534. }
  7535. const vtable_t * vtable = NULL;
  7536. WEBDAV_ERR(neon_init(&vtable, sesspool));
  7537. // Create the session object.
  7538. session_t * session = static_cast<session_t *>(apr_pcalloc(sesspool, sizeof(*session)));
  7539. session->vtable = vtable;
  7540. session->pool = sesspool;
  7541. const char * corrected_url = NULL;
  7542. // Ask the library to open the session.
  7543. WEBDAV_ERR_W(vtable->open_session(
  7544. session,
  7545. &corrected_url,
  7546. session_URL,
  7547. callbacks, callback_baton, sesspool),
  7548. apr_psprintf(pool, "Unable to connect to a WebDAV resource at URL '%s'",
  7549. session_URL));
  7550. if (corrected_url_p && corrected_url)
  7551. {
  7552. if (!path_is_url(corrected_url))
  7553. {
  7554. ne_uri * corrected_URI = NULL;
  7555. WEBDAV_ERR(parse_ne_uri(&corrected_URI, session_URL, sesspool));
  7556. if (corrected_URI->path) ne_free(corrected_URI->path);
  7557. corrected_URI->path = ne_strdup(corrected_url);
  7558. corrected_url = neon_uri_unparse(corrected_URI, pool);
  7559. }
  7560. *corrected_url_p = uri_canonicalize(corrected_url, pool);
  7561. webdav_pool_destroy(sesspool);
  7562. return WEBDAV_NO_ERROR;
  7563. }
  7564. *session_p = session;
  7565. return WEBDAV_NO_ERROR;
  7566. }
  7567. //---------------------------------------------------------------------------
  7568. // This implements the client_list_func_t API
  7569. static error_t
  7570. list_func(
  7571. void * baton,
  7572. const char * path,
  7573. const dirent_t * dirent,
  7574. const char * abs_path,
  7575. apr_pool_t * pool)
  7576. {
  7577. list_func_baton_t * pb = static_cast<list_func_baton_t *>(baton);
  7578. assert(pb);
  7579. assert(pb->entries);
  7580. const char * entryname = NULL;
  7581. neon_session_t * ras = static_cast<neon_session_t *>(pb->session->priv);
  7582. assert(ras);
  7583. if (ras->callbacks->cancel_func)
  7584. WEBDAV_ERR(ras->callbacks->cancel_func(ras->callback_baton));
  7585. if (strcmp(path, "") == 0)
  7586. {
  7587. if (dirent->kind == node_file)
  7588. entryname = dirent_basename(abs_path, pool);
  7589. else if (pb->verbose)
  7590. entryname = ".";
  7591. else
  7592. // Don't bother to list if no useful information will be shown.
  7593. return WEBDAV_NO_ERROR;
  7594. }
  7595. else
  7596. entryname = path;
  7597. if (pb->verbose)
  7598. {
  7599. apr_time_t now = apr_time_now();
  7600. apr_time_exp_t exp_time;
  7601. apr_status_t apr_err;
  7602. apr_size_t size;
  7603. char timestr[20];
  7604. const char * utf8_timestr;
  7605. // time_to_human_cstring gives us something *way* too long
  7606. // to use for this, so we have to roll our own. We include
  7607. // the year if the entry's time is not within half a year.
  7608. apr_time_exp_lt(&exp_time, dirent->time);
  7609. if (apr_time_sec(now - dirent->time) < (365 * 86400 / 2) &&
  7610. apr_time_sec(dirent->time - now) < (365 * 86400 / 2))
  7611. {
  7612. apr_err = apr_strftime(timestr, &size, sizeof(timestr),
  7613. "%b %d %H:%M", &exp_time);
  7614. }
  7615. else
  7616. {
  7617. apr_err = apr_strftime(timestr, &size, sizeof(timestr),
  7618. "%b %d %Y", &exp_time);
  7619. }
  7620. // if that failed, just zero out the string and print nothing
  7621. if (apr_err)
  7622. timestr[0] = '\0';
  7623. // we need it in UTF-8.
  7624. WEBDAV_ERR(utf_cstring_to_utf8(&utf8_timestr, timestr, pool));
  7625. TListDataEntry entry = {NULL, NULL, NULL, 0, false, false, {0}, NULL};
  7626. if (APR_SUCCESS != utf8_to_unicode(const_cast<wchar_t **>(&entry.Name), entryname, pb->pool))
  7627. {
  7628. return error_create(WEBDAV_ERR_DAV_MALFORMED_DATA, NULL, NULL);
  7629. }
  7630. entry.Permissions = L"";
  7631. entry.OwnerGroup = L"";
  7632. int dir = dirent->kind == node_dir;
  7633. entry.Size = dir == 0 ? dirent->size : 0;
  7634. entry.Dir = dir != 0;
  7635. entry.Link = false;
  7636. entry.Time.Year = exp_time.tm_year + 1900;
  7637. entry.Time.Month = exp_time.tm_mon + 1;
  7638. entry.Time.Day = exp_time.tm_mday;
  7639. entry.Time.Hour = exp_time.tm_hour;
  7640. entry.Time.Minute = exp_time.tm_min;
  7641. entry.Time.Second = exp_time.tm_sec;
  7642. entry.Time.HasTime = true;
  7643. entry.Time.HasSeconds = true;
  7644. entry.Time.HasDate = true;
  7645. entry.LinkTarget = L"";
  7646. pb->entries->push_back(entry);
  7647. }
  7648. return WEBDAV_NO_ERROR;
  7649. }
  7650. //---------------------------------------------------------------------------
  7651. // from url.c
  7652. static error_t
  7653. client_url_from_path2(
  7654. const char ** url,
  7655. const char * path_or_url,
  7656. stringbuf_t * session_url,
  7657. apr_pool_t * result_pool,
  7658. apr_pool_t * scratch_pool)
  7659. {
  7660. if (!path_is_url(path_or_url))
  7661. {
  7662. ne_uri * uri = NULL;
  7663. WEBDAV_ERR(parse_ne_uri(&uri, session_url->data, result_pool));
  7664. if (uri->path) ne_free(uri->path);
  7665. uri->path = ne_strdup(path_or_url);
  7666. const char * corrected_url = neon_uri_unparse(uri, result_pool);
  7667. *url = uri_canonicalize(corrected_url, result_pool);
  7668. }
  7669. else
  7670. *url = uri_canonicalize(path_or_url, result_pool);
  7671. return WEBDAV_NO_ERROR;
  7672. }
  7673. //---------------------------------------------------------------------------
  7674. // from ctx.c
  7675. static error_t
  7676. client_create_context(
  7677. client_ctx_t ** ctx,
  7678. apr_pool_t * pool)
  7679. {
  7680. *ctx = static_cast<client_ctx_t *>(apr_pcalloc(pool, sizeof(client_ctx_t)));
  7681. return WEBDAV_NO_ERROR;
  7682. }
  7683. //------------------------------------------------------------------------------
  7684. // from auth.c
  7685. static void
  7686. auth_baton_create(
  7687. auth_baton_t ** auth_baton,
  7688. apr_pool_t * pool)
  7689. {
  7690. auth_baton_t * ab = NULL;
  7691. // Build the auth_baton.
  7692. ab = static_cast<auth_baton_t *>(apr_pcalloc(pool, sizeof(*ab)));
  7693. ab->tables = apr_hash_make(pool);
  7694. ab->parameters = apr_hash_make(pool);
  7695. ab->creds_cache = apr_hash_make(pool);
  7696. ab->pool = pool;
  7697. *auth_baton = ab;
  7698. }
  7699. static void
  7700. create_baton_open(
  7701. auth_baton_t * auth_baton,
  7702. const apr_array_header_t * providers,
  7703. apr_pool_t * pool)
  7704. {
  7705. auth_provider_object_t * provider = NULL;
  7706. // Register each provider in order. Providers of different
  7707. // credentials will be automatically sorted into different tables by
  7708. // register_provider().
  7709. if (providers)
  7710. {
  7711. for (int i = 0; i < providers->nelts; i++)
  7712. {
  7713. provider_set_t * table = NULL;
  7714. provider = APR_ARRAY_IDX(providers, i, auth_provider_object_t *);
  7715. // Add it to the appropriate table in the auth_baton
  7716. table = static_cast<provider_set_t *>(apr_hash_get(auth_baton->tables,
  7717. provider->vtable->cred_kind, APR_HASH_KEY_STRING));
  7718. if (!table)
  7719. {
  7720. table = static_cast<provider_set_t *>(apr_pcalloc(pool, sizeof(*table)));
  7721. table->providers = apr_array_make(pool, 1, sizeof(auth_provider_object_t *));
  7722. apr_hash_set(auth_baton->tables,
  7723. provider->vtable->cred_kind, APR_HASH_KEY_STRING,
  7724. table);
  7725. }
  7726. APR_ARRAY_PUSH(table->providers, auth_provider_object_t *) = provider;
  7727. }
  7728. }
  7729. }
  7730. //---------------------------------------------------------------------------
  7731. // from ssl_client_cert_providers.c
  7732. // A function returning an SSL client certificate passphrase provider.
  7733. typedef void (*auth_ssl_client_cert_pw_provider_func_t)(
  7734. auth_provider_object_t ** provider,
  7735. apr_pool_t * pool);
  7736. // retrieve and load the ssl client certificate file from servers config
  7737. static error_t
  7738. ssl_client_cert_file_first_credentials(
  7739. void ** credentials_p,
  7740. void ** iter_baton,
  7741. void * provider_baton,
  7742. apr_hash_t * parameters,
  7743. const char * realmstring,
  7744. apr_pool_t * pool)
  7745. {
  7746. const char * cert_file;
  7747. cert_file = NULL;
  7748. if (cert_file != NULL)
  7749. {
  7750. auth_cred_ssl_client_cert_t * cred =
  7751. static_cast<auth_cred_ssl_client_cert_t *>(apr_pcalloc(pool, sizeof(*cred)));
  7752. cred->cert_file = cert_file;
  7753. cred->may_save = FALSE;
  7754. *credentials_p = cred;
  7755. }
  7756. else
  7757. {
  7758. *credentials_p = NULL;
  7759. }
  7760. *iter_baton = NULL;
  7761. return WEBDAV_NO_ERROR;
  7762. }
  7763. static const auth_provider_t ssl_client_cert_file_provider =
  7764. {
  7765. AUTH_CRED_SSL_CLIENT_CERT,
  7766. ssl_client_cert_file_first_credentials,
  7767. NULL,
  7768. NULL
  7769. };
  7770. // Public API to SSL file providers.
  7771. static void
  7772. auth_get_ssl_client_cert_file_provider(
  7773. auth_provider_object_t ** provider,
  7774. apr_pool_t * pool)
  7775. {
  7776. auth_provider_object_t * po =
  7777. static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
  7778. po->vtable = &ssl_client_cert_file_provider;
  7779. *provider = po;
  7780. }
  7781. /*-----------------------------------------------------------------------*/
  7782. // Prompt provider
  7783. /*-----------------------------------------------------------------------*/
  7784. // Baton type for prompting to send client ssl creds.
  7785. // There is no iteration baton type.
  7786. typedef struct ssl_client_cert_prompt_provider_baton_t
  7787. {
  7788. auth_ssl_client_cert_prompt_func_t prompt_func;
  7789. void * prompt_baton;
  7790. // how many times to re-prompt after the first one fails
  7791. int retry_limit;
  7792. } ssl_client_cert_prompt_provider_baton_t;
  7793. // Iteration baton.
  7794. typedef struct ssl_client_cert_prompt_iter_baton_t
  7795. {
  7796. // The original provider baton
  7797. ssl_client_cert_prompt_provider_baton_t * pb;
  7798. // The original realmstring
  7799. const char * realmstring;
  7800. // how many times we've reprompted
  7801. int retries;
  7802. } ssl_client_cert_prompt_iter_baton_t;
  7803. static error_t
  7804. ssl_client_cert_prompt_first_cred(
  7805. void ** credentials_p,
  7806. void ** iter_baton,
  7807. void * provider_baton,
  7808. apr_hash_t * parameters,
  7809. const char * realmstring,
  7810. apr_pool_t * pool)
  7811. {
  7812. ssl_client_cert_prompt_provider_baton_t * pb =
  7813. static_cast<ssl_client_cert_prompt_provider_baton_t *>(provider_baton);
  7814. ssl_client_cert_prompt_iter_baton_t * ib =
  7815. static_cast<ssl_client_cert_prompt_iter_baton_t *>(apr_pcalloc(pool, sizeof(*ib)));
  7816. const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
  7817. WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
  7818. APR_HASH_KEY_STRING));
  7819. WEBDAV_ERR(pb->prompt_func((auth_cred_ssl_client_cert_t **) credentials_p,
  7820. pb->prompt_baton, realmstring, !no_auth_cache,
  7821. pool));
  7822. ib->pb = pb;
  7823. ib->realmstring = apr_pstrdup(pool, realmstring);
  7824. ib->retries = 0;
  7825. *iter_baton = ib;
  7826. return WEBDAV_NO_ERROR;
  7827. }
  7828. static error_t
  7829. ssl_client_cert_prompt_next_cred(
  7830. void ** credentials_p,
  7831. void * iter_baton,
  7832. void * provider_baton,
  7833. apr_hash_t * parameters,
  7834. const char * realmstring,
  7835. apr_pool_t * pool)
  7836. {
  7837. ssl_client_cert_prompt_iter_baton_t * ib =
  7838. static_cast<ssl_client_cert_prompt_iter_baton_t *>(iter_baton);
  7839. const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
  7840. WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
  7841. APR_HASH_KEY_STRING));
  7842. if ((ib->pb->retry_limit >= 0) && (ib->retries >= ib->pb->retry_limit))
  7843. {
  7844. // give up, go on to next provider.
  7845. *credentials_p = NULL;
  7846. return WEBDAV_NO_ERROR;
  7847. }
  7848. ib->retries++;
  7849. return ib->pb->prompt_func((auth_cred_ssl_client_cert_t **)
  7850. credentials_p, ib->pb->prompt_baton,
  7851. ib->realmstring, !no_auth_cache, pool);
  7852. }
  7853. static const auth_provider_t ssl_client_cert_prompt_provider =
  7854. {
  7855. AUTH_CRED_SSL_CLIENT_CERT,
  7856. ssl_client_cert_prompt_first_cred,
  7857. ssl_client_cert_prompt_next_cred,
  7858. NULL
  7859. };
  7860. // Public API to SSL prompting providers.
  7861. static void
  7862. auth_get_ssl_client_cert_prompt_provider(
  7863. auth_provider_object_t ** provider,
  7864. auth_ssl_client_cert_prompt_func_t prompt_func,
  7865. void * prompt_baton,
  7866. int retry_limit,
  7867. apr_pool_t * pool)
  7868. {
  7869. auth_provider_object_t * po =
  7870. static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
  7871. ssl_client_cert_prompt_provider_baton_t * pb =
  7872. static_cast<ssl_client_cert_prompt_provider_baton_t *>(apr_pcalloc(pool, sizeof(*pb)));
  7873. pb->prompt_func = prompt_func;
  7874. pb->prompt_baton = prompt_baton;
  7875. pb->retry_limit = retry_limit;
  7876. po->vtable = &ssl_client_cert_prompt_provider;
  7877. po->provider_baton = pb;
  7878. *provider = po;
  7879. }
  7880. //---------------------------------------------------------------------------
  7881. // from ssl_server_trust_providers.c
  7882. // retrieve ssl server CA failure overrides (if any) from servers config
  7883. static error_t
  7884. ssl_server_trust_file_first_credentials(
  7885. void ** credentials,
  7886. void ** iter_baton,
  7887. void * provider_baton,
  7888. apr_hash_t * parameters,
  7889. const char * realmstring,
  7890. apr_pool_t * pool)
  7891. {
  7892. apr_uint32_t * failures = static_cast<apr_uint32_t *>(apr_hash_get(parameters,
  7893. AUTH_PARAM_SSL_SERVER_FAILURES,
  7894. APR_HASH_KEY_STRING));
  7895. const auth_ssl_server_cert_info_t * cert_info =
  7896. static_cast<const auth_ssl_server_cert_info_t *>(apr_hash_get(parameters,
  7897. AUTH_PARAM_SSL_SERVER_CERT_INFO,
  7898. APR_HASH_KEY_STRING));
  7899. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
  7900. CONST_FS_KEY,
  7901. APR_HASH_KEY_STRING));
  7902. assert(fs);
  7903. apr_hash_t * creds_hash = NULL;
  7904. error_t error = WEBDAV_NO_ERROR;
  7905. *credentials = NULL;
  7906. *iter_baton = NULL;
  7907. // Check if this is a permanently accepted certificate
  7908. error = config_read_auth_data(&creds_hash, AUTH_CRED_SSL_SERVER_TRUST,
  7909. realmstring, fs, pool);
  7910. error_clear(&error);
  7911. if (!error && creds_hash)
  7912. {
  7913. string_t * trusted_cert, *this_cert, *failstr;
  7914. apr_uint32_t last_failures = 0;
  7915. trusted_cert = static_cast<string_t *>(apr_hash_get(creds_hash, AUTHN_ASCII_CERT_KEY,
  7916. APR_HASH_KEY_STRING));
  7917. this_cert = string_create(cert_info->fingerprint, pool);
  7918. failstr = static_cast<string_t *>(apr_hash_get(creds_hash, AUTHN_FAILURES_KEY,
  7919. APR_HASH_KEY_STRING));
  7920. if (failstr)
  7921. {
  7922. char * endptr;
  7923. unsigned long tmp_ulong = strtoul(failstr->data, &endptr, 10);
  7924. if (*endptr == '\0')
  7925. last_failures = (apr_uint32_t) tmp_ulong;
  7926. }
  7927. // If the cert is trusted and there are no new failures, we
  7928. // accept it by clearing all failures.
  7929. if (trusted_cert &&
  7930. string_compare(this_cert, trusted_cert) &&
  7931. (*failures & ~last_failures) == 0)
  7932. {
  7933. *failures = 0;
  7934. }
  7935. }
  7936. // If all failures are cleared now, we return the creds
  7937. if (!*failures)
  7938. {
  7939. auth_cred_ssl_server_trust_t * creds =
  7940. static_cast<auth_cred_ssl_server_trust_t *>(apr_pcalloc(pool, sizeof(*creds)));
  7941. creds->may_save = FALSE; // No need to save it again...
  7942. *credentials = creds;
  7943. }
  7944. return WEBDAV_NO_ERROR;
  7945. }
  7946. static error_t
  7947. ssl_server_trust_file_save_credentials(
  7948. bool * saved,
  7949. void * credentials,
  7950. void * provider_baton,
  7951. apr_hash_t * parameters,
  7952. const char * realmstring,
  7953. apr_pool_t * pool)
  7954. {
  7955. auth_cred_ssl_server_trust_t * creds =
  7956. static_cast<auth_cred_ssl_server_trust_t *>(credentials);
  7957. const auth_ssl_server_cert_info_t * cert_info;
  7958. apr_hash_t * creds_hash = NULL;
  7959. if (!creds->may_save)
  7960. return WEBDAV_NO_ERROR;
  7961. cert_info = static_cast<const auth_ssl_server_cert_info_t *>(apr_hash_get(parameters,
  7962. AUTH_PARAM_SSL_SERVER_CERT_INFO,
  7963. APR_HASH_KEY_STRING));
  7964. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
  7965. CONST_FS_KEY,
  7966. APR_HASH_KEY_STRING));
  7967. assert(fs);
  7968. creds_hash = apr_hash_make(pool);
  7969. apr_hash_set(creds_hash, AUTHN_ASCII_CERT_KEY, APR_HASH_KEY_STRING,
  7970. string_create(cert_info->fingerprint, pool));
  7971. apr_hash_set(creds_hash, AUTHN_FAILURES_KEY, APR_HASH_KEY_STRING,
  7972. string_createf(pool, "%lu", (unsigned long)
  7973. creds->accepted_failures));
  7974. WEBDAV_ERR(config_write_auth_data(creds_hash,
  7975. AUTH_CRED_SSL_SERVER_TRUST,
  7976. realmstring,
  7977. fs,
  7978. pool));
  7979. *saved = TRUE;
  7980. return WEBDAV_NO_ERROR;
  7981. }
  7982. static const auth_provider_t ssl_server_trust_file_provider =
  7983. {
  7984. AUTH_CRED_SSL_SERVER_TRUST,
  7985. &ssl_server_trust_file_first_credentials,
  7986. NULL,
  7987. &ssl_server_trust_file_save_credentials,
  7988. };
  7989. // Public API to SSL file providers.
  7990. static void
  7991. auth_get_ssl_server_trust_file_provider(
  7992. auth_provider_object_t ** provider,
  7993. apr_pool_t * pool)
  7994. {
  7995. auth_provider_object_t * po =
  7996. static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
  7997. po->vtable = &ssl_server_trust_file_provider;
  7998. *provider = po;
  7999. }
  8000. /*-----------------------------------------------------------------------*/
  8001. // Prompt provider
  8002. /*-----------------------------------------------------------------------*/
  8003. // Baton type for prompting to verify server ssl creds.
  8004. // There is no iteration baton type.
  8005. typedef struct ssl_server_trust_prompt_provider_baton_t
  8006. {
  8007. auth_ssl_server_trust_prompt_func_t prompt_func;
  8008. void * prompt_baton;
  8009. } ssl_server_trust_prompt_provider_baton_t;
  8010. static error_t
  8011. ssl_server_trust_prompt_first_cred(
  8012. void ** credentials_p,
  8013. void ** iter_baton,
  8014. void * provider_baton,
  8015. apr_hash_t * parameters,
  8016. const char * realmstring,
  8017. apr_pool_t * pool)
  8018. {
  8019. ssl_server_trust_prompt_provider_baton_t * pb =
  8020. static_cast<ssl_server_trust_prompt_provider_baton_t *>(provider_baton);
  8021. apr_uint32_t * failures = static_cast<apr_uint32_t *>(apr_hash_get(parameters,
  8022. AUTH_PARAM_SSL_SERVER_FAILURES,
  8023. APR_HASH_KEY_STRING));
  8024. const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
  8025. WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
  8026. APR_HASH_KEY_STRING));
  8027. const auth_ssl_server_cert_info_t * cert_info =
  8028. static_cast<const auth_ssl_server_cert_info_t *>(apr_hash_get(parameters,
  8029. AUTH_PARAM_SSL_SERVER_CERT_INFO,
  8030. APR_HASH_KEY_STRING));
  8031. WEBDAV_ERR(pb->prompt_func((auth_cred_ssl_server_trust_t **)
  8032. credentials_p, pb->prompt_baton, realmstring,
  8033. *failures, cert_info, !no_auth_cache &&
  8034. !(*failures & WEBDAV_AUTH_SSL_OTHER), pool));
  8035. *iter_baton = NULL;
  8036. return WEBDAV_NO_ERROR;
  8037. }
  8038. static const auth_provider_t ssl_server_trust_prompt_provider =
  8039. {
  8040. AUTH_CRED_SSL_SERVER_TRUST,
  8041. ssl_server_trust_prompt_first_cred,
  8042. NULL,
  8043. NULL
  8044. };
  8045. // Public API to SSL prompting providers.
  8046. static void
  8047. auth_get_ssl_server_trust_prompt_provider(
  8048. auth_provider_object_t ** provider,
  8049. auth_ssl_server_trust_prompt_func_t prompt_func,
  8050. void * prompt_baton,
  8051. apr_pool_t * pool)
  8052. {
  8053. auth_provider_object_t * po =
  8054. static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
  8055. ssl_server_trust_prompt_provider_baton_t * pb =
  8056. static_cast<ssl_server_trust_prompt_provider_baton_t *>(apr_pcalloc(pool, sizeof(*pb)));
  8057. pb->prompt_func = prompt_func;
  8058. pb->prompt_baton = prompt_baton;
  8059. po->vtable = &ssl_server_trust_prompt_provider;
  8060. po->provider_baton = pb;
  8061. *provider = po;
  8062. }
  8063. //---------------------------------------------------------------------------
  8064. // from cmdline.h
  8065. typedef struct cmdline_prompt_baton2_t
  8066. {
  8067. cancel_func_t cancel_func;
  8068. void * cancel_baton;
  8069. } cmdline_prompt_baton2_t;
  8070. //---------------------------------------------------------------------------
  8071. // from prompt.c
  8072. // This is a helper for plaintext prompt functions.
  8073. static error_t
  8074. plaintext_prompt_helper(
  8075. bool * may_save_plaintext,
  8076. const char * realmstring,
  8077. const char * prompt_string,
  8078. const char * prompt_text,
  8079. void * baton,
  8080. apr_pool_t * pool)
  8081. {
  8082. cmdline_prompt_baton2_t * pb = static_cast<cmdline_prompt_baton2_t *>(baton);
  8083. auth_baton_t * ab = static_cast<auth_baton_t *>(pb->cancel_baton);
  8084. assert(ab);
  8085. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(ab->parameters,
  8086. CONST_FS_KEY,
  8087. APR_HASH_KEY_STRING));
  8088. assert(fs);
  8089. unsigned int RequestResult = 0;
  8090. error_t err = fs->SimplePrompt(prompt_text, prompt_string, RequestResult);
  8091. if (err)
  8092. {
  8093. if (err == WEBDAV_ERR_CANCELLED)
  8094. {
  8095. error_clear(&err);
  8096. *may_save_plaintext = FALSE;
  8097. return WEBDAV_NO_ERROR;
  8098. }
  8099. else
  8100. return err;
  8101. }
  8102. if (RequestResult == qaYes)
  8103. {
  8104. *may_save_plaintext = TRUE;
  8105. }
  8106. else if (RequestResult == qaNo)
  8107. {
  8108. *may_save_plaintext = FALSE;
  8109. }
  8110. return WEBDAV_NO_ERROR;
  8111. }
  8112. // This implements 'auth_plaintext_prompt_func_t'.
  8113. static error_t
  8114. cmdline_auth_plaintext_prompt(
  8115. bool * may_save_plaintext,
  8116. const char * realmstring,
  8117. void * baton,
  8118. apr_pool_t * pool)
  8119. {
  8120. const char * prompt_string = "Store password unencrypted (yes/no)? ";
  8121. const char * prompt_text =
  8122. "\n-----------------------------------------------------------------------"
  8123. "\nATTENTION! Your password for authentication realm:\n"
  8124. "\n"
  8125. " %s\n"
  8126. "\n"
  8127. "can only be stored to disk unencrypted! You are advised to configure\n"
  8128. "your system so that system can store passwords encrypted, if\n"
  8129. "possible. See the documentation for details.\n"
  8130. "\n"
  8131. "You can avoid future appearances of this warning by setting the value\n"
  8132. "of the 'store-plaintext-passwords' option to either 'yes' or 'no' in\n"
  8133. "'%s'.\n"
  8134. "-----------------------------------------------------------------------\n"
  8135. ;
  8136. return plaintext_prompt_helper(may_save_plaintext, realmstring,
  8137. prompt_string, prompt_text, baton,
  8138. pool);
  8139. }
  8140. // This implements 'auth_plaintext_passphrase_prompt_func_t'.
  8141. static error_t
  8142. cmdline_auth_plaintext_passphrase_prompt(
  8143. bool * may_save_plaintext,
  8144. const char * realmstring,
  8145. void * baton,
  8146. apr_pool_t * pool)
  8147. {
  8148. const char * prompt_string = "Store passphrase unencrypted (yes/no)? ";
  8149. const char * prompt_text =
  8150. "\n-----------------------------------------------------------------------\n"
  8151. "ATTENTION! Your passphrase for client certificate:\n"
  8152. "\n"
  8153. " %s\n"
  8154. "\n"
  8155. "can only be stored to disk unencrypted! You are advised to configure\n"
  8156. "your system so that system can store passphrase encrypted, if\n"
  8157. "possible. See the documentation for details.\n"
  8158. "\n"
  8159. "You can avoid future appearances of this warning by setting the value\n"
  8160. "of the 'store-ssl-client-cert-pp-plaintext' option to either 'yes' or\n"
  8161. "'no' in '%s'.\n"
  8162. "-----------------------------------------------------------------------\n"
  8163. ;
  8164. return plaintext_prompt_helper(may_save_plaintext, realmstring,
  8165. prompt_string, prompt_text, baton,
  8166. pool);
  8167. }
  8168. // This implements 'auth_ssl_server_trust_prompt_func_t'.
  8169. static error_t
  8170. cmdline_auth_ssl_server_trust_prompt(
  8171. auth_cred_ssl_server_trust_t ** cred_p,
  8172. void * baton,
  8173. const char * realm,
  8174. apr_uint32_t failures,
  8175. const auth_ssl_server_cert_info_t * cert_info,
  8176. bool may_save,
  8177. apr_pool_t * pool)
  8178. {
  8179. cmdline_prompt_baton2_t * pb =
  8180. static_cast<cmdline_prompt_baton2_t *>(baton);
  8181. stringbuf_t * buf = stringbuf_create("", pool);
  8182. /*if (failures & WEBDAV_AUTH_SSL_UNKNOWNCA)
  8183. {
  8184. stringbuf_appendcstr(buf,
  8185. " - The certificate is not issued by a trusted authority. Use the\n"
  8186. " fingerprint to validate the certificate manually!\n");
  8187. }*/
  8188. if (failures & WEBDAV_AUTH_SSL_CNMISMATCH)
  8189. {
  8190. stringbuf_appendcstr(buf, "- The certificate hostname does not match.\n");
  8191. }
  8192. if (failures & WEBDAV_AUTH_SSL_NOTYETVALID)
  8193. {
  8194. stringbuf_appendcstr(buf, "- The certificate is not yet valid.\n");
  8195. }
  8196. if (failures & WEBDAV_AUTH_SSL_EXPIRED)
  8197. {
  8198. stringbuf_appendcstr(buf, "- The certificate has expired.\n");
  8199. }
  8200. if (failures & WEBDAV_AUTH_SSL_OTHER)
  8201. {
  8202. stringbuf_appendcstr(buf, "- The certificate has an unknown error.\n");
  8203. }
  8204. stringbuf_t * msg = stringbuf_createf(pool,
  8205. // "Certificate information:\n"
  8206. " - Hostname: %s\n"
  8207. " - Valid: from %s until %s\n"
  8208. " - Issuer: %s\n"
  8209. " - Fingerprint: %s",
  8210. cert_info->hostname,
  8211. cert_info->valid_from,
  8212. cert_info->valid_until,
  8213. cert_info->issuer_dname,
  8214. cert_info->fingerprint);
  8215. stringbuf_appendstr(buf, msg);
  8216. auth_baton_t * ab = static_cast<auth_baton_t *>(pb->cancel_baton);
  8217. assert(ab);
  8218. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(ab->parameters,
  8219. CONST_FS_KEY,
  8220. APR_HASH_KEY_STRING));
  8221. assert(fs);
  8222. unsigned int RequestResult = 0;
  8223. WEBDAV_ERR(fs->VerifyCertificate(buf->data, cert_info->fingerprint, RequestResult));
  8224. if (RequestResult == qaYes)
  8225. {
  8226. *cred_p = static_cast<auth_cred_ssl_server_trust_t *>(apr_pcalloc(pool, sizeof(**cred_p)));
  8227. (*cred_p)->may_save = TRUE;
  8228. (*cred_p)->accepted_failures = failures;
  8229. }
  8230. else if (RequestResult == qaNo)
  8231. {
  8232. *cred_p = static_cast<auth_cred_ssl_server_trust_t *>(apr_pcalloc(pool, sizeof(**cred_p)));
  8233. (*cred_p)->may_save = FALSE;
  8234. (*cred_p)->accepted_failures = failures;
  8235. }
  8236. else
  8237. {
  8238. *cred_p = NULL;
  8239. }
  8240. return WEBDAV_NO_ERROR;
  8241. }
  8242. // This implements 'auth_ssl_client_cert_prompt_func_t'.
  8243. static error_t
  8244. cmdline_auth_ssl_client_cert_prompt(
  8245. auth_cred_ssl_client_cert_t ** cred_p,
  8246. void * baton,
  8247. const char * realm,
  8248. bool may_save,
  8249. apr_pool_t * pool)
  8250. {
  8251. auth_cred_ssl_client_cert_t * cred = NULL;
  8252. const char * cert_file = NULL;
  8253. const char * abs_cert_file = NULL;
  8254. cmdline_prompt_baton2_t * pb =
  8255. static_cast<cmdline_prompt_baton2_t *>(baton);
  8256. auth_baton_t * ab = static_cast<auth_baton_t *>(pb->cancel_baton);
  8257. assert(ab);
  8258. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(ab->parameters,
  8259. CONST_FS_KEY,
  8260. APR_HASH_KEY_STRING));
  8261. assert(fs);
  8262. unsigned int RequestResult = 0;
  8263. WEBDAV_ERR(fs->AskForClientCertificateFilename(&cert_file, RequestResult, pool));
  8264. if (RequestResult != qaOK) return WEBDAV_NO_ERROR;
  8265. WEBDAV_ERR(dirent_get_absolute(&abs_cert_file, cert_file, pool));
  8266. cred = static_cast<auth_cred_ssl_client_cert_t *>(apr_pcalloc(pool, sizeof(*cred)));
  8267. cred->cert_file = abs_cert_file;
  8268. cred->may_save = may_save;
  8269. *cred_p = cred;
  8270. return WEBDAV_NO_ERROR;
  8271. }
  8272. // This implements 'auth_ssl_client_cert_pw_prompt_func_t'.
  8273. static error_t
  8274. cmdline_auth_ssl_client_cert_pw_prompt(
  8275. auth_cred_ssl_client_cert_pw_t ** cred_p,
  8276. void * baton,
  8277. const char * realm,
  8278. bool may_save,
  8279. apr_pool_t * pool)
  8280. {
  8281. auth_cred_ssl_client_cert_pw_t * cred = NULL;
  8282. cmdline_prompt_baton2_t * pb =
  8283. static_cast<cmdline_prompt_baton2_t *>(baton);
  8284. auth_baton_t * ab = static_cast<auth_baton_t *>(pb->cancel_baton);
  8285. assert(ab);
  8286. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(ab->parameters,
  8287. CONST_FS_KEY,
  8288. APR_HASH_KEY_STRING));
  8289. assert(fs);
  8290. unsigned int RequestResult = 0;
  8291. const char * result = NULL;
  8292. WEBDAV_ERR(fs->AskForPassphrase(&result, realm, RequestResult, pool));
  8293. if (RequestResult != qaOK) return WEBDAV_NO_ERROR;
  8294. cred = static_cast<auth_cred_ssl_client_cert_pw_t *>(apr_pcalloc(pool, sizeof(*cred)));
  8295. cred->password = result;
  8296. cred->may_save = may_save;
  8297. *cred_p = cred;
  8298. return WEBDAV_NO_ERROR;
  8299. }
  8300. // This implements 'auth_simple_prompt_func_t'.
  8301. static error_t
  8302. cmdline_auth_simple_prompt(
  8303. auth_cred_simple_t ** cred_p,
  8304. void * baton,
  8305. const char * realm,
  8306. const char * username,
  8307. bool may_save,
  8308. apr_pool_t * pool)
  8309. {
  8310. auth_cred_simple_t * ret =
  8311. static_cast<auth_cred_simple_t *>(apr_pcalloc(pool, sizeof(*ret)));
  8312. cmdline_prompt_baton2_t * pb =
  8313. static_cast<cmdline_prompt_baton2_t *>(baton);
  8314. auth_baton_t * ab = static_cast<auth_baton_t *>(pb->cancel_baton);
  8315. assert(ab);
  8316. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(ab->parameters,
  8317. CONST_FS_KEY,
  8318. APR_HASH_KEY_STRING));
  8319. assert(fs);
  8320. unsigned int RequestResult = 0;
  8321. if (username)
  8322. ret->username = apr_pstrdup(pool, username);
  8323. else
  8324. {
  8325. WEBDAV_ERR(fs->AskForUsername(&ret->username, RequestResult, pool));
  8326. if (RequestResult != qaOK) return WEBDAV_NO_ERROR;
  8327. }
  8328. WEBDAV_ERR(fs->AskForUserPassword(&ret->password, RequestResult, pool));
  8329. if (RequestResult != qaOK) return WEBDAV_NO_ERROR;
  8330. ret->may_save = may_save;
  8331. *cred_p = ret;
  8332. return WEBDAV_NO_ERROR;
  8333. }
  8334. // This implements 'auth_username_prompt_func_t'.
  8335. static error_t
  8336. cmdline_auth_username_prompt(
  8337. auth_cred_username_t ** cred_p,
  8338. void * baton,
  8339. const char * realm,
  8340. bool may_save,
  8341. apr_pool_t * pool)
  8342. {
  8343. auth_cred_username_t * ret =
  8344. static_cast<auth_cred_username_t *>(apr_pcalloc(pool, sizeof(*ret)));
  8345. cmdline_prompt_baton2_t * pb =
  8346. static_cast<cmdline_prompt_baton2_t *>(baton);
  8347. auth_baton_t * ab = static_cast<auth_baton_t *>(pb->cancel_baton);
  8348. assert(ab);
  8349. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(ab->parameters,
  8350. CONST_FS_KEY,
  8351. APR_HASH_KEY_STRING));
  8352. assert(fs);
  8353. unsigned int RequestResult = 0;
  8354. WEBDAV_ERR(fs->AskForUsername(&ret->username, RequestResult, pool));
  8355. if (RequestResult != qaOK) return WEBDAV_NO_ERROR;
  8356. ret->may_save = may_save;
  8357. *cred_p = ret;
  8358. return WEBDAV_NO_ERROR;
  8359. }
  8360. //---------------------------------------------------------------------------
  8361. // from cmdline.c
  8362. static error_t
  8363. ssl_trust_unknown_server_cert(
  8364. auth_cred_ssl_server_trust_t ** cred_p,
  8365. void * baton,
  8366. const char * realm,
  8367. apr_uint32_t failures,
  8368. const auth_ssl_server_cert_info_t * cert_info,
  8369. bool may_save,
  8370. apr_pool_t * pool)
  8371. {
  8372. *cred_p = NULL;
  8373. if (failures == 0 || failures == WEBDAV_AUTH_SSL_UNKNOWNCA)
  8374. {
  8375. *cred_p = static_cast<auth_cred_ssl_server_trust_t *>(apr_pcalloc(pool, sizeof(**cred_p)));
  8376. (*cred_p)->may_save = FALSE;
  8377. (*cred_p)->accepted_failures = failures;
  8378. }
  8379. return WEBDAV_NO_ERROR;
  8380. }
  8381. static error_t
  8382. auth_baton_init(
  8383. auth_baton_t * ab,
  8384. bool non_interactive,
  8385. const char * auth_username,
  8386. const char * auth_password,
  8387. bool no_auth_cache,
  8388. bool trust_server_cert,
  8389. TWebDAVFileSystem * fs,
  8390. cancel_func_t cancel_func,
  8391. void * cancel_baton,
  8392. apr_pool_t * pool)
  8393. {
  8394. bool store_password_val = TRUE;
  8395. bool store_auth_creds_val = TRUE;
  8396. auth_provider_object_t * provider = NULL;
  8397. cmdline_prompt_baton2_t * pb = NULL;
  8398. // The whole list of registered providers
  8399. apr_array_header_t * providers = NULL;
  8400. // Populate the registered providers with the platform-specific providers
  8401. WEBDAV_ERR(auth_get_platform_specific_client_providers(&providers,
  8402. pool));
  8403. // If we have a cancellation function, cram it and the stuff it
  8404. // needs into the prompt baton.
  8405. if (cancel_func)
  8406. {
  8407. pb = static_cast<cmdline_prompt_baton2_t *>(apr_pcalloc(pool, sizeof(*pb)));
  8408. pb->cancel_func = cancel_func;
  8409. pb->cancel_baton = cancel_baton;
  8410. }
  8411. if (non_interactive == FALSE)
  8412. {
  8413. // This provider doesn't prompt the user in order to get creds;
  8414. // it prompts the user regarding the caching of creds.
  8415. auth_get_simple_provider2(&provider,
  8416. cmdline_auth_plaintext_prompt,
  8417. pb, pool);
  8418. }
  8419. else
  8420. {
  8421. auth_get_simple_provider2(&provider, NULL, NULL, pool);
  8422. }
  8423. APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
  8424. auth_get_username_provider(&provider, pool);
  8425. APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
  8426. // The server-cert, client-cert, and client-cert-password providers.
  8427. WEBDAV_ERR(auth_get_platform_specific_provider(&provider,
  8428. "windows",
  8429. "ssl_server_trust",
  8430. pool));
  8431. APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
  8432. auth_get_ssl_server_trust_file_provider(&provider, pool);
  8433. APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
  8434. auth_get_ssl_client_cert_file_provider(&provider, pool);
  8435. APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
  8436. if (non_interactive == FALSE)
  8437. {
  8438. // This provider doesn't prompt the user in order to get creds;
  8439. // it prompts the user regarding the caching of creds.
  8440. auth_get_ssl_client_cert_pw_file_provider2(&provider, cmdline_auth_plaintext_passphrase_prompt,
  8441. pb, pool);
  8442. }
  8443. else
  8444. {
  8445. auth_get_ssl_client_cert_pw_file_provider2(&provider, NULL, NULL,
  8446. pool);
  8447. }
  8448. APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
  8449. if (non_interactive == FALSE)
  8450. {
  8451. // Two basic prompt providers: username/password, and just username.
  8452. auth_get_simple_prompt_provider(&provider,
  8453. cmdline_auth_simple_prompt,
  8454. pb,
  8455. 2, // retry limit
  8456. pool);
  8457. APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
  8458. auth_get_username_prompt_provider(&provider, cmdline_auth_username_prompt, pb,
  8459. 2, /* retry limit */ pool);
  8460. APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
  8461. // Three ssl prompt providers, for server-certs, client-certs,
  8462. // and client-cert-passphrases.
  8463. auth_get_ssl_server_trust_prompt_provider(&provider, cmdline_auth_ssl_server_trust_prompt, pb, pool);
  8464. APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
  8465. auth_get_ssl_client_cert_prompt_provider(&provider, cmdline_auth_ssl_client_cert_prompt, pb, 2, pool);
  8466. APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
  8467. auth_get_ssl_client_cert_pw_prompt_provider(&provider, cmdline_auth_ssl_client_cert_pw_prompt, pb, 2, pool);
  8468. APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
  8469. }
  8470. else if (trust_server_cert)
  8471. {
  8472. // Remember, only register this provider if non_interactive.
  8473. auth_get_ssl_server_trust_prompt_provider(&provider, ssl_trust_unknown_server_cert, NULL, pool);
  8474. APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
  8475. }
  8476. // Build an authentication baton to give to libclient.
  8477. create_baton_open(ab, providers, pool);
  8478. auth_baton_set_parameter(ab, CONST_FS_KEY, fs);
  8479. // Place any default username or password credentials into the
  8480. // auth_baton's run-time parameter hash.
  8481. if (auth_username)
  8482. auth_baton_set_parameter(ab, WEBDAV_AUTH_PARAM_DEFAULT_USERNAME,
  8483. auth_username);
  8484. if (auth_password)
  8485. auth_baton_set_parameter(ab, WEBDAV_AUTH_PARAM_DEFAULT_PASSWORD,
  8486. auth_password);
  8487. // Same with the non-interactive option.
  8488. if (non_interactive)
  8489. auth_baton_set_parameter(ab, WEBDAV_AUTH_PARAM_NON_INTERACTIVE, "");
  8490. if (!store_password_val)
  8491. auth_baton_set_parameter(ab, WEBDAV_AUTH_PARAM_DONT_STORE_PASSWORDS, "");
  8492. if (no_auth_cache || !store_auth_creds_val)
  8493. auth_baton_set_parameter(ab, WEBDAV_AUTH_PARAM_NO_AUTH_CACHE, "");
  8494. return WEBDAV_NO_ERROR;
  8495. }
  8496. //---------------------------------------------------------------------------
  8497. // from main.c
  8498. // A flag to see if we've been canceled by the client or not.
  8499. static volatile atomic_t cancelled = FALSE;
  8500. // Our cancellation callback.
  8501. static error_t
  8502. check_cancel(void * baton)
  8503. {
  8504. if (cancelled)
  8505. return error_create(WEBDAV_ERR_CANCELLED, NULL, "Cancelled");
  8506. else
  8507. return WEBDAV_NO_ERROR;
  8508. }
  8509. //---------------------------------------------------------------------------
  8510. // from ra.c
  8511. static error_t
  8512. cancel_callback(void * baton)
  8513. {
  8514. callback_baton_t * cb = static_cast<callback_baton_t *>(baton);
  8515. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(cb->ctx->auth_baton->parameters,
  8516. CONST_FS_KEY,
  8517. APR_HASH_KEY_STRING));
  8518. assert(fs);
  8519. cancelled = static_cast<atomic_t>(fs->GetIsCancelled());
  8520. return error_trace((cb->ctx->cancel_func)(cb->ctx->cancel_baton));
  8521. }
  8522. static error_t
  8523. get_client_string(
  8524. void * baton,
  8525. const char ** name,
  8526. apr_pool_t * pool)
  8527. {
  8528. callback_baton_t * b = static_cast<callback_baton_t *>(baton);
  8529. *name = apr_pstrdup(pool, b->ctx->client_name);
  8530. return WEBDAV_NO_ERROR;
  8531. }
  8532. // see ra.c::client_session_from_path
  8533. static error_t
  8534. init_session_from_path(
  8535. session_t * session,
  8536. const char ** url_p,
  8537. const char * path_or_url,
  8538. apr_pool_t * pool)
  8539. {
  8540. const char * initial_url, *url;
  8541. neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
  8542. assert(ras);
  8543. WEBDAV_ERR(client_url_from_path2(&initial_url, path_or_url,
  8544. ras->url, pool, pool));
  8545. if (!initial_url)
  8546. return error_createf(WEBDAV_ERR_ENTRY_MISSING_URL, NULL,
  8547. "'%s' has no URL", path_or_url);
  8548. url = initial_url;
  8549. // Make the session point to the real URL.
  8550. WEBDAV_ERR(reparent(session, url, pool));
  8551. *url_p = url;
  8552. return WEBDAV_NO_ERROR;
  8553. }
  8554. static error_t
  8555. client_open_session_internal(
  8556. session_t ** ra_session,
  8557. const char ** corrected_url,
  8558. const char * base_url,
  8559. client_ctx_t * ctx,
  8560. apr_pool_t * pool)
  8561. {
  8562. // prepare callbacks, contexts
  8563. callbacks2_t * cbtable = static_cast<callbacks2_t *>(apr_pcalloc(pool, sizeof(*cbtable)));
  8564. callback_baton_t * cb = static_cast<callback_baton_t *>(apr_pcalloc(pool, sizeof(*cb)));
  8565. cbtable->auth_baton = ctx->auth_baton;
  8566. cbtable->progress_func = ctx->progress_func;
  8567. cbtable->progress_baton = ctx->progress_baton;
  8568. cbtable->cancel_func = ctx->cancel_func ? cancel_callback : NULL;
  8569. cbtable->get_client_string = get_client_string;
  8570. cb->pool = pool;
  8571. cb->ctx = ctx;
  8572. if (corrected_url)
  8573. {
  8574. apr_hash_t * attempted = apr_hash_make(pool);
  8575. int attempts_left = MAX_REDIRECT_ATTEMPTS;
  8576. while (attempts_left--)
  8577. {
  8578. const char * corrected = NULL;
  8579. WEBDAV_ERR(session_open(
  8580. ra_session,
  8581. attempts_left == 0 ? NULL : &corrected,
  8582. base_url, cbtable, cb,
  8583. pool));
  8584. // No error and no corrected URL? We're done here.
  8585. if (!corrected)
  8586. break;
  8587. // Our caller will want to know what our final corrected URL was.
  8588. *corrected_url = corrected;
  8589. // Make sure we've not attempted this URL before.
  8590. if (apr_hash_get(attempted, corrected, APR_HASH_KEY_STRING))
  8591. return WEBDAV_ERR_CLIENT_CYCLE_DETECTED;
  8592. // Remember this CORRECTED_URL so we don't wind up in a loop.
  8593. apr_hash_set(attempted, apr_pstrdup(pool, corrected), APR_HASH_KEY_STRING, (void *)1);
  8594. base_url = corrected;
  8595. }
  8596. }
  8597. else
  8598. {
  8599. WEBDAV_ERR(session_open(ra_session, NULL, base_url,
  8600. cbtable, cb,
  8601. pool));
  8602. }
  8603. return WEBDAV_NO_ERROR;
  8604. }
  8605. //---------------------------------------------------------------------------
  8606. // from list.c
  8607. static error_t
  8608. get_dir_contents(
  8609. apr_uint32_t dirent_fields,
  8610. const char * dir,
  8611. session_t * ra_session,
  8612. const char * fs_path,
  8613. depth_t depth,
  8614. client_list_func_t list_func,
  8615. void * baton,
  8616. apr_pool_t * pool)
  8617. {
  8618. apr_hash_t * tmpdirents = NULL;
  8619. apr_pool_t * iterpool = webdav_pool_create(pool);
  8620. apr_array_header_t * array = NULL;
  8621. error_t err = 0;
  8622. if (depth == depth_empty)
  8623. return WEBDAV_NO_ERROR;
  8624. // Get the directory's entries, but not its props. Ignore any
  8625. // not-authorized errors.
  8626. err = get_dir2(ra_session, &tmpdirents,
  8627. dir,
  8628. dirent_fields, pool);
  8629. if (err && ((err == WEBDAV_ERR_NOT_AUTHORIZED) ||
  8630. (err == WEBDAV_ERR_DAV_FORBIDDEN)))
  8631. {
  8632. error_clear(&err);
  8633. return WEBDAV_NO_ERROR;
  8634. }
  8635. WEBDAV_ERR(err);
  8636. neon_session_t * ras = static_cast<neon_session_t *>(ra_session->priv);
  8637. assert(ras);
  8638. if (ras->callbacks->cancel_func)
  8639. WEBDAV_ERR(ras->callbacks->cancel_func(ras->callback_baton));
  8640. // Sort the hash, so we can call the callback in a "deterministic" order.
  8641. array = sort_hash(tmpdirents, sort_compare_items_lexically, pool);
  8642. for (int i = 0; i < array->nelts; ++i)
  8643. {
  8644. sort_item_t * item = &APR_ARRAY_IDX(array, i, sort_item_t);
  8645. dirent_t * the_ent = static_cast<dirent_t *>(apr_hash_get(tmpdirents, item->key, item->klen));
  8646. webdav_pool_clear(iterpool);
  8647. const char * path = relpath_join(dir, static_cast<const char *>(item->key), iterpool);
  8648. if ((the_ent->kind == node_file) ||
  8649. (depth == depth_immediates) ||
  8650. (depth == depth_infinity))
  8651. WEBDAV_ERR(list_func(baton, path,
  8652. the_ent,
  8653. fs_path, iterpool));
  8654. if (depth == depth_infinity && the_ent->kind == node_dir)
  8655. WEBDAV_ERR(get_dir_contents(dirent_fields, path,
  8656. ra_session,
  8657. fs_path, depth,
  8658. list_func, baton, iterpool));
  8659. }
  8660. webdav_pool_destroy(iterpool);
  8661. return WEBDAV_NO_ERROR;
  8662. }
  8663. //------------------------------------------------------------------------------
  8664. // from options.c
  8665. static const neon_xml_elm_t options_elements[] =
  8666. {
  8667. { "DAV:", "href", ELEM_href, NEON_XML_CDATA },
  8668. { "DAV:", "options-response", ELEM_options_response, 0 },
  8669. { NULL }
  8670. };
  8671. typedef struct options_ctx_t
  8672. {
  8673. // WARNING: WANT_CDATA should stay the first element in the baton:
  8674. // neon_xml_collect_cdata() assumes the baton starts with a stringbuf.
  8675. stringbuf_t * want_cdata;
  8676. stringbuf_t * cdata;
  8677. apr_pool_t * pool;
  8678. } options_ctx_t;
  8679. static int
  8680. options_validate_element(
  8681. neon_xml_elmid parent,
  8682. neon_xml_elmid child)
  8683. {
  8684. switch (parent)
  8685. {
  8686. case ELEM_root:
  8687. if (child == ELEM_options_response)
  8688. return child;
  8689. else
  8690. return NEON_XML_INVALID;
  8691. case ELEM_options_response:
  8692. return NEON_XML_DECLINE; // not concerned with other response
  8693. default:
  8694. return NEON_XML_DECLINE;
  8695. }
  8696. // NOTREACHED
  8697. }
  8698. static error_t
  8699. options_start_element(
  8700. int * elem,
  8701. void * baton,
  8702. int parent,
  8703. const char * nspace,
  8704. const char * name,
  8705. const char ** atts)
  8706. {
  8707. options_ctx_t * oc = static_cast<options_ctx_t *>(baton);
  8708. const neon_xml_elm_t * elm = neon_lookup_xml_elem(options_elements, nspace, name);
  8709. *elem = elm ? options_validate_element(parent, elm->id) : NEON_XML_DECLINE;
  8710. if (*elem < 1) // Not a valid element
  8711. return WEBDAV_NO_ERROR;
  8712. if (elm->id == ELEM_href)
  8713. oc->want_cdata = oc->cdata;
  8714. else
  8715. oc->want_cdata = NULL;
  8716. return WEBDAV_NO_ERROR;
  8717. }
  8718. static error_t
  8719. options_end_element(
  8720. void * baton,
  8721. int state,
  8722. const char * nspace,
  8723. const char * name)
  8724. {
  8725. return WEBDAV_NO_ERROR;
  8726. }
  8727. static error_t
  8728. neon_exchange_capabilities(
  8729. neon_session_t * ras,
  8730. const char ** relocation_location,
  8731. apr_pool_t * pool)
  8732. {
  8733. neon_request_t * req = NULL;
  8734. error_t err = WEBDAV_NO_ERROR;
  8735. ne_xml_parser * parser = NULL;
  8736. options_ctx_t oc = { 0 };
  8737. int status_code = 0;
  8738. oc.pool = pool;
  8739. oc.cdata = stringbuf_create("", pool);
  8740. if (relocation_location)
  8741. *relocation_location = NULL;
  8742. WEBDAV_ERR(neon_request_create(&req, ras,
  8743. "OPTIONS", ras->url->data, pool));
  8744. // Use a symbolic name somewhere for this MIME type?
  8745. ne_add_request_header(req->ne_req, "Content-Type", "text/xml");
  8746. apr_hash_t * extra_headers = apr_hash_make(pool);
  8747. neon_add_depth_header(extra_headers, NEON_DEPTH_ZERO);
  8748. // Create a parser to read the normal response body
  8749. parser = neon_xml_parser_create(req, ne_accept_2xx, options_start_element,
  8750. neon_xml_collect_cdata,
  8751. options_end_element, &oc);
  8752. // Run the request and get the resulting status code.
  8753. if ((err = neon_request_dispatch(&status_code, req, extra_headers,
  8754. "<?xml version=\"1.0\" "
  8755. "encoding=\"utf-8\"?>"
  8756. "<D:options xmlns:D=\"DAV:\">"
  8757. "<D:resourcetype/>"
  8758. "</D:options>",
  8759. 200,
  8760. relocation_location ? 301 : 0,
  8761. false,
  8762. pool)) != WEBDAV_NO_ERROR)
  8763. goto cleanup;
  8764. if (req->code == 301)
  8765. {
  8766. *relocation_location = neon_request_get_location(req, pool);
  8767. goto cleanup;
  8768. }
  8769. // Was there an XML parse error somewhere?
  8770. err = neon_check_parse_error("OPTIONS", parser, ras->url->data);
  8771. if (err)
  8772. goto cleanup;
  8773. cleanup:
  8774. neon_request_destroy(req);
  8775. return err;
  8776. }
  8777. //------------------------------------------------------------------------------
  8778. // from props.c
  8779. typedef struct propfind_ctx_t
  8780. {
  8781. // WARNING: WANT_CDATA should stay the first element in the baton:
  8782. // neon_xml_collect_cdata() assumes the baton starts with a stringbuf.
  8783. stringbuf_t * cdata;
  8784. apr_hash_t * props; // const char *URL-PATH -> neon_resource_t
  8785. neon_resource_t * rsrc; // the current resource.
  8786. const char * encoding; // property encoding (or NULL)
  8787. int status; // status for the current <propstat> (or 0 if unknown).
  8788. apr_hash_t * propbuffer; // holds properties until their status is known.
  8789. neon_xml_elmid last_open_id; // the id of the last opened tag.
  8790. ne_xml_parser * parser; // xml parser handling the PROPSET request.
  8791. apr_pool_t * pool;
  8792. } propfind_ctx_t;
  8793. // When we begin a checkout, we fetch these from the "public" resources.
  8794. // We fetch the resourcetype to
  8795. // verify that we're accessing a collection.
  8796. static const ne_propname starting_props[] =
  8797. {
  8798. { "DAV:", "resourcetype" },
  8799. { "DAV:", "creationdate" },
  8800. { "DAV:", "getlastmodified" },
  8801. { "DAV:", "getcontentlength" },
  8802. { NULL }
  8803. };
  8804. static error_t
  8805. neon_get_starting_props(
  8806. neon_resource_t ** rsrc,
  8807. neon_session_t * sess,
  8808. const char * url,
  8809. bool check_errors,
  8810. apr_pool_t * pool)
  8811. {
  8812. WEBDAV_ERR(neon_get_props_resource(rsrc, sess, url,
  8813. starting_props, check_errors, pool));
  8814. // Cache some of the resource information.
  8815. if (!sess->webdav_root)
  8816. {
  8817. string_t * propval = NULL;
  8818. if (propval)
  8819. {
  8820. ne_uri uri = {0};
  8821. stringbuf_t * urlbuf = stringbuf_create(url, pool);
  8822. path_remove_components(urlbuf,
  8823. path_component_count(propval->data));
  8824. uri = sess->root;
  8825. uri.path = urlbuf->data;
  8826. sess->webdav_root = neon_uri_unparse(&uri, sess->pool);
  8827. }
  8828. }
  8829. return WEBDAV_NO_ERROR;
  8830. }
  8831. // Propfind Implementation
  8832. typedef struct elem_defn
  8833. {
  8834. neon_xml_elmid id;
  8835. const char * name;
  8836. int is_property; // is it a property, or part of some structure?
  8837. } elem_defn;
  8838. static const elem_defn elem_definitions[] =
  8839. {
  8840. // NOTE: Make sure that every item in here is also represented in
  8841. // propfind_elements[]
  8842. // DAV elements
  8843. { ELEM_multistatus, "DAV:multistatus", 0 },
  8844. { ELEM_response, "DAV:response", 0 },
  8845. { ELEM_href, "DAV:href", NEON_XML_CDATA },
  8846. { ELEM_propstat, "DAV:propstat", 0 },
  8847. { ELEM_prop, "DAV:prop", 0 },
  8848. { ELEM_status, "DAV:status", NEON_XML_CDATA },
  8849. { ELEM_collection, "DAV:collection", NEON_XML_CDATA },
  8850. { ELEM_resourcetype, "DAV:resourcetype", 0 },
  8851. { ELEM_get_content_length, NEON_PROP_GETCONTENTLENGTH, 1 },
  8852. { ELEM_creationdate, NEON_PROP_CREATIONDATE, 1 },
  8853. { 0 }
  8854. };
  8855. static const neon_xml_elm_t propfind_elements[] =
  8856. {
  8857. // NOTE: Make sure that every item in here is also represented in
  8858. // elem_definitions[]
  8859. // DAV elements
  8860. { "DAV:", "multistatus", ELEM_multistatus, 0 },
  8861. { "DAV:", "response", ELEM_response, 0 },
  8862. { "DAV:", "href", ELEM_href, NEON_XML_CDATA },
  8863. { "DAV:", "propstat", ELEM_propstat, 0 },
  8864. { "DAV:", "prop", ELEM_prop, 0 },
  8865. { "DAV:", "status", ELEM_status, NEON_XML_CDATA },
  8866. { "DAV:", "collection", ELEM_collection, NEON_XML_CDATA },
  8867. { "DAV:", "resourcetype", ELEM_resourcetype, 0 },
  8868. { "DAV:", "getcontentlength", ELEM_get_content_length, NEON_XML_CDATA },
  8869. { "DAV:", "getlastmodified", ELEM_get_last_modified, NEON_XML_CDATA },
  8870. {
  8871. "DAV:", "creator-displayname", ELEM_creator_displayname,
  8872. NEON_XML_CDATA
  8873. },
  8874. // Unknowns
  8875. { "", "", ELEM_unknown, NEON_XML_COLLECT },
  8876. { NULL }
  8877. };
  8878. // Look up an element definition ID. May return NULL if the elem is
  8879. // not recognized.
  8880. static const elem_defn *
  8881. defn_from_id(
  8882. neon_xml_elmid id)
  8883. {
  8884. for (const elem_defn * defn = elem_definitions; defn->name != NULL; ++defn)
  8885. {
  8886. if (id == defn->id)
  8887. return defn;
  8888. }
  8889. return NULL;
  8890. }
  8891. // Assign URL to RSRC. Use POOL for any allocations.
  8892. static error_t
  8893. assign_rsrc_url(
  8894. neon_resource_t * rsrc,
  8895. const char * url,
  8896. apr_pool_t * pool)
  8897. {
  8898. char * url_path = NULL;
  8899. apr_size_t len = 0;
  8900. ne_uri parsed_url = {0};
  8901. // Parse the PATH element out of the URL.
  8902. // NOTE: mod_dav does not (currently) use an absolute URL, but simply a
  8903. // server-relative path (i.e. this uri_parse is effectively a no-op).
  8904. if (ne_uri_parse(url, &parsed_url) != 0)
  8905. {
  8906. ne_uri_free(&parsed_url);
  8907. return error_createf(WEBDAV_ERR_DAV_MALFORMED_DATA, NULL,
  8908. "Unable to parse URL '%s'", url);
  8909. }
  8910. url_path = apr_pstrdup(pool, parsed_url.path);
  8911. ne_uri_free(&parsed_url);
  8912. // Clean up trailing slashes from the URL.
  8913. len = strlen(url_path);
  8914. if ((len > 1) && (url_path[len - 1] == '/'))
  8915. url_path[len - 1] = '\0';
  8916. rsrc->url = url_path;
  8917. return WEBDAV_NO_ERROR;
  8918. }
  8919. // Determine whether we're receiving the expected XML response.
  8920. // Return CHILD when interested in receiving the child's contents
  8921. // or one of NEON_XML_INVALID and NEON_XML_DECLINE
  8922. // when respectively this is the incorrect response or
  8923. // the element (and its children) are uninteresting
  8924. static int
  8925. props_validate_element(
  8926. neon_xml_elmid parent,
  8927. neon_xml_elmid child)
  8928. {
  8929. switch (parent)
  8930. {
  8931. case ELEM_root:
  8932. if (child == ELEM_multistatus)
  8933. return child;
  8934. else
  8935. return NEON_XML_INVALID;
  8936. case ELEM_multistatus:
  8937. if (child == ELEM_response)
  8938. return child;
  8939. else
  8940. return NEON_XML_DECLINE;
  8941. case ELEM_response:
  8942. if ((child == ELEM_href) || (child == ELEM_propstat))
  8943. return child;
  8944. else
  8945. return NEON_XML_DECLINE;
  8946. case ELEM_propstat:
  8947. if ((child == ELEM_prop) || (child == ELEM_status))
  8948. return child;
  8949. else
  8950. return NEON_XML_DECLINE;
  8951. case ELEM_prop:
  8952. return child; // handle all children of <prop>
  8953. case ELEM_resourcetype:
  8954. if (child == ELEM_collection)
  8955. return child;
  8956. else
  8957. return NEON_XML_DECLINE; // not concerned with other types (now)
  8958. default:
  8959. return NEON_XML_DECLINE;
  8960. }
  8961. // NOTREACHED
  8962. }
  8963. static error_t
  8964. props_start_element(
  8965. int * elem,
  8966. void * baton,
  8967. int parent,
  8968. const char * nspace,
  8969. const char * name,
  8970. const char ** atts)
  8971. {
  8972. propfind_ctx_t * pc = static_cast<propfind_ctx_t *>(baton);
  8973. const neon_xml_elm_t * elm = neon_lookup_xml_elem(propfind_elements, nspace, name);
  8974. *elem = elm ? props_validate_element(parent, elm->id) : NEON_XML_DECLINE;
  8975. if (*elem < 1) // not a valid element
  8976. return WEBDAV_NO_ERROR;
  8977. stringbuf_setempty(pc->cdata);
  8978. *elem = elm ? elm->id : ELEM_unknown;
  8979. switch (*elem)
  8980. {
  8981. case ELEM_response:
  8982. if (pc->rsrc)
  8983. return error_create(WEBDAV_ERR_XML_MALFORMED, NULL, NULL);
  8984. // Create a new resource.
  8985. pc->rsrc = static_cast<neon_resource_t *>(apr_pcalloc(pc->pool, sizeof(*(pc->rsrc))));
  8986. pc->rsrc->pool = pc->pool;
  8987. pc->rsrc->propset = apr_hash_make(pc->pool);
  8988. pc->status = 0;
  8989. break;
  8990. case ELEM_propstat:
  8991. pc->status = 0;
  8992. break;
  8993. case ELEM_href:
  8994. pc->rsrc->href_parent = pc->last_open_id;
  8995. break;
  8996. case ELEM_collection:
  8997. pc->rsrc->is_collection = 1;
  8998. break;
  8999. case ELEM_unknown:
  9000. // these are our user-visible properties, presumably.
  9001. if (pc->encoding)
  9002. pc->encoding = apr_pstrdup(pc->pool, pc->encoding);
  9003. break;
  9004. default:
  9005. // nothing to do for these
  9006. break;
  9007. }
  9008. // Remember the last tag we opened.
  9009. pc->last_open_id = *elem;
  9010. return WEBDAV_NO_ERROR;
  9011. }
  9012. static error_t
  9013. props_end_element(
  9014. void * baton,
  9015. int state,
  9016. const char * nspace,
  9017. const char * name)
  9018. {
  9019. propfind_ctx_t * pc = static_cast<propfind_ctx_t *>(baton);
  9020. neon_resource_t * rsrc = pc->rsrc;
  9021. const string_t * value = NULL;
  9022. const elem_defn * parent_defn = NULL;
  9023. const elem_defn * defn = NULL;
  9024. ne_status status = {0};
  9025. const char * cdata = pc->cdata->data;
  9026. switch (state)
  9027. {
  9028. case ELEM_response:
  9029. // Verify that we've received a URL for this resource.
  9030. if (!pc->rsrc->url)
  9031. return error_create(WEBDAV_ERR_XML_MALFORMED, NULL, NULL);
  9032. // Store the resource in the top-level hash table.
  9033. apr_hash_set(pc->props, pc->rsrc->url, APR_HASH_KEY_STRING, pc->rsrc);
  9034. pc->rsrc = NULL;
  9035. return WEBDAV_NO_ERROR;
  9036. case ELEM_propstat:
  9037. // We're at the end of a set of properties. Do the right thing status-wise.
  9038. if (pc->status)
  9039. {
  9040. for (apr_hash_index_t * hi = apr_hash_first(pc->pool, pc->propbuffer); hi;
  9041. hi = apr_hash_next(hi))
  9042. {
  9043. const void * key;
  9044. apr_ssize_t klen;
  9045. void * val;
  9046. apr_hash_this(hi, &key, &klen, &val);
  9047. if (pc->status == 200)
  9048. apr_hash_set(rsrc->propset, key, klen, val);
  9049. apr_hash_set(pc->propbuffer, key, klen, NULL);
  9050. }
  9051. }
  9052. else if (!pc->status)
  9053. {
  9054. // No status at all? Bogosity.
  9055. return error_create(WEBDAV_ERR_XML_MALFORMED, NULL, NULL);
  9056. }
  9057. return WEBDAV_NO_ERROR;
  9058. case ELEM_status:
  9059. // Parse the <status> tag's CDATA for a status code.
  9060. if (ne_parse_statusline(cdata, &status))
  9061. return error_create(WEBDAV_ERR_XML_MALFORMED, NULL, NULL);
  9062. ne_free(status.reason_phrase);
  9063. pc->status = status.code;
  9064. return WEBDAV_NO_ERROR;
  9065. case ELEM_href:
  9066. // Special handling for <href> that belongs to the <response> tag.
  9067. if (rsrc->href_parent == ELEM_response)
  9068. return assign_rsrc_url(pc->rsrc,
  9069. urlpath_canonicalize(cdata, pc->pool),
  9070. pc->pool);
  9071. // Use the parent element's name, not the href.
  9072. parent_defn = defn_from_id(rsrc->href_parent);
  9073. // No known parent? Get outta here.
  9074. if (!parent_defn)
  9075. return WEBDAV_NO_ERROR;
  9076. // All other href's we'll treat as property values.
  9077. name = parent_defn->name;
  9078. value = string_create(urlpath_canonicalize(cdata, pc->pool),
  9079. pc->pool);
  9080. break;
  9081. default:
  9082. if (state == ELEM_unknown)
  9083. {
  9084. name = apr_pstrcat(pc->pool, nspace, name, (char *)NULL);
  9085. }
  9086. else
  9087. {
  9088. defn = defn_from_id(state);
  9089. if (!(defn && defn->is_property))
  9090. return WEBDAV_NO_ERROR;
  9091. name = defn->name;
  9092. }
  9093. // Check for encoding attribute.
  9094. if (pc->encoding == NULL)
  9095. {
  9096. // Handle the property value by converting it to string.
  9097. value = string_create(cdata, pc->pool);
  9098. break;
  9099. }
  9100. // Check for known encoding type
  9101. if (strcmp(pc->encoding, "base64") != 0)
  9102. return error_create(WEBDAV_ERR_XML_MALFORMED, NULL, NULL);
  9103. pc->encoding = NULL; // Reset encoding for future attribute(s).
  9104. }
  9105. // Handling resource properties from here out.
  9106. // Add properties to the temporary propbuffer. At the end of the
  9107. // <propstat>, we'll either dump the props as invalid or move them
  9108. // into the resource's property hash.
  9109. apr_hash_set(pc->propbuffer, name, APR_HASH_KEY_STRING, value);
  9110. return WEBDAV_NO_ERROR;
  9111. }
  9112. static void
  9113. props_set_parser(
  9114. ne_xml_parser * parser,
  9115. void * baton)
  9116. {
  9117. propfind_ctx_t * pc = static_cast<propfind_ctx_t *>(baton);
  9118. pc->parser = parser;
  9119. }
  9120. static error_t
  9121. neon_get_props(
  9122. apr_hash_t ** results,
  9123. neon_session_t * sess,
  9124. const char * url,
  9125. int depth,
  9126. const ne_propname * which_props,
  9127. bool check_errors,
  9128. apr_pool_t * pool)
  9129. {
  9130. apr_hash_t * extra_headers = apr_hash_make(pool);
  9131. neon_add_depth_header(extra_headers, depth);
  9132. // It's easier to roll our own PROPFIND here than use neon's current interfaces.
  9133. // The start of the request body is fixed:
  9134. stringbuf_t * body = stringbuf_create("<?xml version=\"1.0\" encoding=\"utf-8\"?>" DEBUG_CR
  9135. "<propfind xmlns=\"DAV:\">" DEBUG_CR, pool);
  9136. // Are we asking for specific propert(y/ies), or just all of them?
  9137. if (which_props)
  9138. {
  9139. apr_pool_t * iterpool = webdav_pool_create(pool);
  9140. stringbuf_appendcstr(body, "<prop>" DEBUG_CR);
  9141. for (int n = 0; which_props[n].name != NULL; n++)
  9142. {
  9143. webdav_pool_clear(iterpool);
  9144. stringbuf_appendcstr(body, apr_pstrcat(iterpool, "<", which_props[n].name,
  9145. " xmlns=\"", which_props[n].nspace, "\"/>" DEBUG_CR,
  9146. (char *)NULL));
  9147. }
  9148. stringbuf_appendcstr(body, "</prop></propfind>" DEBUG_CR);
  9149. webdav_pool_destroy(iterpool);
  9150. }
  9151. else
  9152. {
  9153. stringbuf_appendcstr(body, "<allprop/></propfind>" DEBUG_CR);
  9154. }
  9155. // Initialize our baton.
  9156. propfind_ctx_t pc;
  9157. memset(&pc, 0, sizeof(pc));
  9158. pc.pool = pool;
  9159. pc.propbuffer = apr_hash_make(pool);
  9160. pc.props = apr_hash_make(pool);
  9161. pc.cdata = stringbuf_create("", pool);
  9162. // Create and dispatch the request!
  9163. WEBDAV_ERR(neon_parsed_request(sess, "PROPFIND", url,
  9164. body->data, 0,
  9165. props_set_parser,
  9166. props_start_element,
  9167. neon_xml_collect_cdata,
  9168. props_end_element,
  9169. &pc, extra_headers, NULL,
  9170. check_errors,
  9171. pool));
  9172. *results = pc.props;
  9173. return WEBDAV_NO_ERROR;
  9174. }
  9175. static error_t
  9176. neon_get_props_resource(
  9177. neon_resource_t ** rsrc,
  9178. neon_session_t * sess,
  9179. const char * url,
  9180. const ne_propname * which_props,
  9181. bool check_errors,
  9182. apr_pool_t * pool)
  9183. {
  9184. apr_hash_t * props = NULL;
  9185. char * url_path = apr_pstrdup(pool, url);
  9186. apr_size_t len = strlen(url);
  9187. // Clean up any trailing slashes.
  9188. if ((len > 1) && (url[len - 1] == '/'))
  9189. url_path[len - 1] = '\0';
  9190. WEBDAV_ERR(neon_get_props(&props, sess, url_path, NEON_DEPTH_ZERO,
  9191. which_props, check_errors, pool));
  9192. // HACK. We need to have the client canonicalize paths, get rid
  9193. // of double slashes and such. This check is just a check against
  9194. // non-SVN servers; in the long run we want to re-enable this.
  9195. {
  9196. // pick out the first response: the URL requested will not match
  9197. // the response href.
  9198. apr_hash_index_t * hi = apr_hash_first(pool, props);
  9199. if (hi)
  9200. {
  9201. void * ent;
  9202. apr_hash_this(hi, NULL, NULL, &ent);
  9203. *rsrc = static_cast<neon_resource_t *>(ent);
  9204. }
  9205. else
  9206. *rsrc = NULL;
  9207. }
  9208. if (*rsrc == NULL)
  9209. {
  9210. // hmmm, should have been in there...
  9211. return error_createf(APR_EGENERAL, NULL,
  9212. "Failed to find label '%s' for URL '%s'",
  9213. "NULL", url_path);
  9214. }
  9215. return WEBDAV_NO_ERROR;
  9216. }
  9217. //------------------------------------------------------------------------------
  9218. static error_t
  9219. client_list2(
  9220. session_t * session,
  9221. const char * path_or_url,
  9222. depth_t depth,
  9223. apr_uint32_t dirent_fields,
  9224. client_list_func_t list_func,
  9225. void * baton,
  9226. apr_pool_t * pool)
  9227. {
  9228. dirent_t * dirent = NULL;
  9229. const char * url = NULL;
  9230. const char * webdav_root = NULL;
  9231. const char * fs_path = NULL;
  9232. error_t err = 0;
  9233. assert(session);
  9234. // We use the kind field to determine if we should recurse, so we
  9235. // always need it.
  9236. dirent_fields |= WEBDAV_DIRENT_KIND;
  9237. WEBDAV_ERR(init_session_from_path(session,
  9238. &url, path_or_url,
  9239. pool));
  9240. WEBDAV_ERR(get_webdav_resource_root2(session, &webdav_root, pool));
  9241. WEBDAV_ERR(client_path_relative_to_root(&fs_path,
  9242. url,
  9243. webdav_root, TRUE, session,
  9244. pool, pool));
  9245. err = stat(session, "", &dirent, pool);
  9246. if (err)
  9247. return error_trace(err);
  9248. if (!dirent)
  9249. return error_createf(WEBDAV_ERR_FS_NOT_FOUND, NULL,
  9250. "URL '%s' non-existent",
  9251. url);
  9252. // Report the dirent for the target.
  9253. WEBDAV_ERR(list_func(baton, "", dirent, fs_path, pool));
  9254. if (dirent->kind == node_dir && (depth == depth_files ||
  9255. depth == depth_immediates ||
  9256. depth == depth_infinity))
  9257. {
  9258. WEBDAV_ERR(get_dir_contents(dirent_fields, "",
  9259. session,
  9260. fs_path, depth,
  9261. list_func, baton, pool));
  9262. }
  9263. return WEBDAV_NO_ERROR;
  9264. }
  9265. static error_t
  9266. client_get_file(
  9267. session_t * session,
  9268. const char * remote_path,
  9269. apr_os_file_t * thefile,
  9270. apr_pool_t * pool)
  9271. {
  9272. const char * remote_url = NULL;
  9273. WEBDAV_ERR(init_session_from_path(session,
  9274. &remote_url, path_uri_encode(remote_path, pool),
  9275. pool));
  9276. stream_t * fstream = NULL;
  9277. WEBDAV_ERR(stream_open_writable(&fstream, thefile,
  9278. pool, pool));
  9279. const char * src_rel = NULL;
  9280. WEBDAV_ERR(get_path_relative_to_session(session, &src_rel,
  9281. remote_url,
  9282. pool));
  9283. WEBDAV_ERR(get_file(session, src_rel, fstream, NULL, pool));
  9284. WEBDAV_ERR(stream_close(fstream));
  9285. return WEBDAV_NO_ERROR;
  9286. }
  9287. static error_t
  9288. client_put_file(
  9289. session_t * session,
  9290. const char * remote_path,
  9291. const char * local_path,
  9292. apr_pool_t * pool)
  9293. {
  9294. neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
  9295. assert(ras);
  9296. error_t err = 0;
  9297. int code = 0;
  9298. apr_hash_t * extra_headers = NULL; // apr_hash_make(pool);
  9299. neon_request_t * request = NULL;
  9300. const char * put_target = path_uri_encode(remote_path, pool);
  9301. apr_file_t * body_file = NULL;
  9302. WEBDAV_ERR(io_file_open(&body_file, local_path, APR_READ | APR_BUFFERED | APR_BINARY,
  9303. APR_OS_DEFAULT, pool));
  9304. // create/prep the request
  9305. WEBDAV_ERR(neon_request_create(&request, ras, "PUT",
  9306. put_target, pool));
  9307. // Give the file to neon. The provider will rewind the file.
  9308. err = neon_set_neon_body_provider(request, body_file);
  9309. if (err)
  9310. goto cleanup;
  9311. // run the request and get the resulting status code (and error_t)
  9312. err = neon_request_dispatch(&code, request, extra_headers, NULL,
  9313. 201 /* Created */,
  9314. 204 /* No Content */,
  9315. false,
  9316. pool);
  9317. if (err && (err == WEBDAV_ERR_DAV_REQUEST_FAILED))
  9318. {
  9319. err = error_createf(WEBDAV_ERR_CANNOT_PUT_FILE, NULL,
  9320. "Cannot create '%s'"
  9321. " (Status %d on PUT Request)",
  9322. put_target, code);
  9323. }
  9324. cleanup:
  9325. neon_request_destroy(request);
  9326. WEBDAV_ERR(err);
  9327. return WEBDAV_NO_ERROR;
  9328. }
  9329. static error_t
  9330. client_move_file_or_directory(
  9331. session_t * session,
  9332. const char * remote_path_from,
  9333. const char * remote_path_to,
  9334. void * baton,
  9335. apr_pool_t * pool)
  9336. {
  9337. neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
  9338. assert(ras);
  9339. error_t err = 0;
  9340. const char * target_from = path_uri_encode(remote_path_from, pool);
  9341. const char * target_to = path_uri_encode(remote_path_to, pool);
  9342. int code = 0;
  9343. apr_hash_t * extra_headers = apr_hash_make(pool);
  9344. apr_hash_set(extra_headers, "Destination", APR_HASH_KEY_STRING, target_to);
  9345. neon_add_depth_header(extra_headers, NEON_DEPTH_INFINITE);
  9346. err = neon_simple_request(&code, ras, "MOVE", target_from,
  9347. extra_headers, NULL,
  9348. 201 /* Created */,
  9349. 204 /* No Content */,
  9350. pool);
  9351. if (err && (err == WEBDAV_ERR_DAV_REQUEST_FAILED))
  9352. {
  9353. err = error_createf(WEBDAV_ERR_CANNOT_MOVE, NULL,
  9354. "Cannot move '%s' to '%s'"
  9355. " (Status %d on MOVE Request)",
  9356. target_from, target_to, code);
  9357. }
  9358. return err;
  9359. }
  9360. static error_t
  9361. client_delete_file(
  9362. session_t * session,
  9363. const char * remote_path,
  9364. void * baton,
  9365. apr_pool_t * pool)
  9366. {
  9367. neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
  9368. assert(ras);
  9369. error_t err = 0;
  9370. const char * target = path_uri_encode(remote_path, pool);
  9371. int code = 0;
  9372. err = neon_simple_request(&code, ras, "DELETE", target,
  9373. NULL, NULL,
  9374. 200,
  9375. 204, // No Content
  9376. pool);
  9377. if (err && (err == WEBDAV_ERR_DAV_REQUEST_FAILED))
  9378. {
  9379. err = error_createf(WEBDAV_ERR_CANNOT_DELETE_FILE, NULL,
  9380. "Cannot delete '%s'"
  9381. " (Status %d on DELETE Request)",
  9382. target, code);
  9383. }
  9384. return err;
  9385. }
  9386. static error_t
  9387. client_check_path(
  9388. session_t * session,
  9389. const char * remote_path,
  9390. node_kind_t * kind,
  9391. apr_pool_t * pool)
  9392. {
  9393. neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
  9394. assert(ras);
  9395. *kind = node_none;
  9396. error_t err = 0;
  9397. char * target = apr_pstrdup(pool, path_uri_encode(remote_path, pool));
  9398. const char * rel_path = NULL;
  9399. apr_size_t len = strlen(target);
  9400. if ((len > 1) && ((target)[len - 1] == '/'))
  9401. {
  9402. (target)[len - 1] = '\0';
  9403. }
  9404. if (*target == '/')
  9405. {
  9406. // check if root has trailing slash
  9407. apr_size_t len = strlen(ras->webdav_root);
  9408. if ((len > 1) && ((ras->webdav_root)[len - 1] == '/'))
  9409. {
  9410. target++;
  9411. }
  9412. const char * abs_path = apr_pstrcat(pool, ras->webdav_root, target, NULL);
  9413. err = get_path_relative_to_root(
  9414. session,
  9415. &rel_path,
  9416. abs_path,
  9417. pool);
  9418. WEBDAV_ERR(err);
  9419. }
  9420. else
  9421. {
  9422. rel_path = target;
  9423. }
  9424. err = check_path(
  9425. session,
  9426. rel_path,
  9427. kind,
  9428. pool
  9429. );
  9430. return err;
  9431. }
  9432. static error_t
  9433. client_make_directory(
  9434. session_t * session,
  9435. const char * remote_path,
  9436. void * baton,
  9437. apr_pool_t * pool)
  9438. {
  9439. neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
  9440. assert(ras);
  9441. error_t err = 0;
  9442. const char * target = path_uri_encode(remote_path, pool);
  9443. int code = 0;
  9444. err = neon_simple_request(
  9445. &code, ras, "MKCOL", target,
  9446. NULL, NULL,
  9447. 201, 207, pool);
  9448. if (err && (err == WEBDAV_ERR_DAV_REQUEST_FAILED))
  9449. {
  9450. err = error_createf(WEBDAV_ERR_CANNOT_MKCOL, NULL,
  9451. "Cannot create directory '%s'"
  9452. " (Status %d on MKCOL Request)",
  9453. target, code);
  9454. }
  9455. return err;
  9456. }
  9457. static error_t
  9458. client_send_propfind_request(
  9459. session_t * session,
  9460. const char * remote_path,
  9461. int * response_code,
  9462. apr_pool_t * pool)
  9463. {
  9464. neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
  9465. assert(ras);
  9466. error_t err = 0;
  9467. int code = 0;
  9468. apr_hash_t * props = NULL;
  9469. const char * target = path_uri_encode(remote_path, pool);
  9470. char * url_path = apr_pstrdup(pool, target);
  9471. WEBDAV_ERR(neon_get_props(&props, ras, url_path, NEON_DEPTH_ZERO,
  9472. starting_props,
  9473. false,
  9474. pool));
  9475. if (err && (err == WEBDAV_ERR_DAV_REQUEST_FAILED))
  9476. {
  9477. err = error_createf(WEBDAV_ERR_CANNOT_PROPFIND, NULL,
  9478. "Cannot execute PROPFIND on '%s'"
  9479. " (Status %d on PROPFIND Request)",
  9480. target, code);
  9481. }
  9482. if (response_code)
  9483. *response_code = code;
  9484. return err;
  9485. }
  9486. //------------------------------------------------------------------------------
  9487. // from session.c
  9488. typedef struct neonprogress_baton_t
  9489. {
  9490. neon_session_t * ras;
  9491. apr_off_t last_progress;
  9492. apr_time_t last_progress_time;
  9493. apr_pool_t * pool;
  9494. } neonprogress_baton_t;
  9495. // Callback invoked to enter PKCS#11 PIN code.
  9496. static int
  9497. client_ssl_pkcs11_pin_entry(
  9498. void * userdata,
  9499. int attempt,
  9500. const char * slot_descr,
  9501. const char * token_label,
  9502. unsigned int flags,
  9503. char * pin)
  9504. {
  9505. neon_session_t * ras = static_cast<neon_session_t *>(userdata);
  9506. void * creds = NULL;
  9507. auth_cred_ssl_client_cert_pw_t * pw_creds = NULL;
  9508. // Always prevent PIN caching.
  9509. auth_baton_set_parameter(ras->callbacks->auth_baton,
  9510. AUTH_PARAM_NO_AUTH_CACHE, "");
  9511. error_t err = 0;
  9512. if (attempt == 0)
  9513. {
  9514. const char * realmstring;
  9515. realmstring = apr_psprintf(ras->pool,
  9516. "PIN for token \"%s\" in slot \"%s\"",
  9517. token_label, slot_descr);
  9518. err = auth_first_credentials(&creds,
  9519. &(ras->auth_iterstate),
  9520. AUTH_CRED_SSL_CLIENT_CERT_PW,
  9521. realmstring,
  9522. ras->callbacks->auth_baton,
  9523. ras->pool);
  9524. }
  9525. else
  9526. {
  9527. err = auth_next_credentials(&creds, ras->auth_iterstate, ras->pool);
  9528. }
  9529. if (err || !creds)
  9530. {
  9531. error_clear(&err);
  9532. return -1;
  9533. }
  9534. pw_creds = static_cast<auth_cred_ssl_client_cert_pw_t *>(creds);
  9535. strncpy(pin, pw_creds->password, NE_SSL_P11PINLEN);
  9536. return 0;
  9537. }
  9538. static bool
  9539. client_ssl_decrypt_cert(
  9540. neon_session_t * ras,
  9541. const char * cert_file,
  9542. ne_ssl_client_cert * clicert)
  9543. {
  9544. auth_iterstate_t * state = NULL;
  9545. error_t error = 0;
  9546. apr_pool_t * pool = NULL;
  9547. bool ok = false;
  9548. void * creds = NULL;
  9549. int try_count = 0;
  9550. apr_pool_create(&pool, ras->pool);
  9551. for (try_count = 0; TRUE; ++try_count)
  9552. {
  9553. if (try_count == 0)
  9554. {
  9555. error = auth_first_credentials(&creds, &state,
  9556. AUTH_CRED_SSL_CLIENT_CERT_PW,
  9557. cert_file,
  9558. ras->callbacks->auth_baton,
  9559. pool);
  9560. }
  9561. else
  9562. {
  9563. error = auth_next_credentials(&creds, state, pool);
  9564. }
  9565. if (error || !creds)
  9566. {
  9567. // Failure or too many attempts
  9568. error_clear(&error);
  9569. break;
  9570. }
  9571. else
  9572. {
  9573. auth_cred_ssl_client_cert_pw_t * pw_creds = static_cast<auth_cred_ssl_client_cert_pw_t *>(creds);
  9574. if (ne_ssl_clicert_decrypt(clicert, pw_creds->password) == 0)
  9575. {
  9576. error = auth_save_credentials(state, pool);
  9577. if (error)
  9578. error_clear(&error);
  9579. // Success
  9580. ok = TRUE;
  9581. break;
  9582. }
  9583. }
  9584. }
  9585. webdav_pool_destroy(pool);
  9586. return ok;
  9587. }
  9588. static void
  9589. client_ssl_callback(
  9590. void * userdata,
  9591. ne_session * sess,
  9592. const ne_ssl_dname * const * dnames,
  9593. int dncount)
  9594. {
  9595. neon_session_t * ras = static_cast<neon_session_t *>(userdata);
  9596. ne_ssl_client_cert * clicert = NULL;
  9597. void * creds = NULL;
  9598. auth_iterstate_t * state = NULL;
  9599. const char * realmstring = NULL;
  9600. apr_pool_t * pool = NULL;
  9601. error_t error = 0;
  9602. int try_count = 0;
  9603. apr_pool_create(&pool, ras->pool);
  9604. realmstring = apr_psprintf(pool, "%s://%s:%d", ras->root.scheme,
  9605. ras->root.host, ras->root.port);
  9606. for (try_count = 0; TRUE; ++try_count)
  9607. {
  9608. if (try_count == 0)
  9609. {
  9610. error = auth_first_credentials(&creds, &state,
  9611. AUTH_CRED_SSL_CLIENT_CERT,
  9612. realmstring,
  9613. ras->callbacks->auth_baton,
  9614. pool);
  9615. }
  9616. else
  9617. {
  9618. error = auth_next_credentials(&creds, state, pool);
  9619. }
  9620. if (error || !creds)
  9621. {
  9622. // Failure or too many attempts
  9623. error_clear(&error);
  9624. break;
  9625. }
  9626. else
  9627. {
  9628. auth_cred_ssl_client_cert_t * client_creds = static_cast<auth_cred_ssl_client_cert_t *>(creds);
  9629. clicert = ne_ssl_clicert_read(client_creds->cert_file);
  9630. if (clicert)
  9631. {
  9632. if (!ne_ssl_clicert_encrypted(clicert) ||
  9633. client_ssl_decrypt_cert(ras, client_creds->cert_file,
  9634. clicert))
  9635. {
  9636. ne_ssl_set_clicert(sess, clicert);
  9637. }
  9638. ne_ssl_clicert_free(clicert);
  9639. clicert = NULL;
  9640. break;
  9641. }
  9642. }
  9643. }
  9644. webdav_pool_destroy(pool);
  9645. }
  9646. static const apr_uint32_t neon_failure_map[][2] =
  9647. {
  9648. { NE_SSL_NOTYETVALID, WEBDAV_AUTH_SSL_NOTYETVALID },
  9649. { NE_SSL_EXPIRED, WEBDAV_AUTH_SSL_EXPIRED },
  9650. { NE_SSL_IDMISMATCH, WEBDAV_AUTH_SSL_CNMISMATCH },
  9651. { NE_SSL_UNTRUSTED, WEBDAV_AUTH_SSL_UNKNOWNCA }
  9652. };
  9653. // Convert neon's SSL failure mask to our own failure mask.
  9654. static apr_uint32_t
  9655. convert_neon_failures(
  9656. int neon_failures)
  9657. {
  9658. apr_uint32_t failures = 0;
  9659. for (apr_size_t i = 0; i < sizeof(neon_failure_map) / (2 * sizeof(int)); ++i)
  9660. {
  9661. if (neon_failures & neon_failure_map[i][0])
  9662. {
  9663. failures |= neon_failure_map[i][1];
  9664. neon_failures &= ~neon_failure_map[i][0];
  9665. }
  9666. }
  9667. // Map any remaining neon failure bits to our OTHER bit.
  9668. if (neon_failures)
  9669. {
  9670. failures |= WEBDAV_AUTH_SSL_OTHER;
  9671. }
  9672. return failures;
  9673. }
  9674. // A neon-session callback to validate the SSL certificate when the CA
  9675. // is unknown (e.g. a self-signed cert), or there are other SSL
  9676. // certificate problems.
  9677. static int
  9678. server_ssl_callback(
  9679. void * userdata,
  9680. int failures,
  9681. const ne_ssl_certificate * cert)
  9682. {
  9683. neon_session_t * ras = static_cast<neon_session_t *>(userdata);
  9684. auth_cred_ssl_server_trust_t * server_creds = NULL;
  9685. void * creds = NULL;
  9686. auth_iterstate_t * state = NULL;
  9687. apr_pool_t * pool = NULL;
  9688. error_t error = 0;
  9689. char * ascii_cert = ne_ssl_cert_export(cert);
  9690. char * issuer_dname = ne_ssl_readable_dname(ne_ssl_cert_issuer(cert));
  9691. auth_ssl_server_cert_info_t cert_info = {0};
  9692. char fingerprint[NE_SSL_DIGESTLEN] = {0};
  9693. char valid_from[NE_SSL_VDATELEN] = {0}, valid_until[NE_SSL_VDATELEN] = {0};
  9694. apr_uint32_t * webdav_failures = static_cast<apr_uint32_t *>(apr_pcalloc(ras->pool, sizeof(*webdav_failures)));
  9695. // Construct the realmstring, e.g. https://svn.collab.net:80
  9696. const char * realmstring = apr_pstrdup(ras->pool, Format("%s://%s:%d", ras->root.scheme,
  9697. ras->root.host, ras->root.port).c_str());
  9698. *webdav_failures = convert_neon_failures(failures);
  9699. auth_baton_set_parameter(ras->callbacks->auth_baton,
  9700. AUTH_PARAM_SSL_SERVER_FAILURES,
  9701. webdav_failures);
  9702. // Extract the info from the certificate
  9703. cert_info.hostname = ne_ssl_cert_identity(cert);
  9704. if (ne_ssl_cert_digest(cert, fingerprint) != 0)
  9705. {
  9706. strcpy(fingerprint, "<unknown>");
  9707. }
  9708. cert_info.fingerprint = fingerprint;
  9709. ne_ssl_cert_validity(cert, valid_from, valid_until);
  9710. cert_info.valid_from = valid_from;
  9711. cert_info.valid_until = valid_until;
  9712. cert_info.issuer_dname = issuer_dname;
  9713. cert_info.ascii_cert = ascii_cert;
  9714. auth_baton_set_parameter(ras->callbacks->auth_baton,
  9715. AUTH_PARAM_SSL_SERVER_CERT_INFO,
  9716. &cert_info);
  9717. apr_pool_create(&pool, ras->pool);
  9718. error = auth_first_credentials(&creds, &state,
  9719. AUTH_CRED_SSL_SERVER_TRUST,
  9720. realmstring,
  9721. ras->callbacks->auth_baton,
  9722. pool);
  9723. if (error || !creds)
  9724. {
  9725. error_clear(&error);
  9726. }
  9727. else
  9728. {
  9729. server_creds = static_cast<auth_cred_ssl_server_trust_t *>(creds);
  9730. error = auth_save_credentials(state, pool);
  9731. if (error)
  9732. {
  9733. // It would be nice to show the error to the user somehow...
  9734. error_clear(&error);
  9735. }
  9736. }
  9737. free(issuer_dname);
  9738. free(ascii_cert);
  9739. auth_baton_set_parameter(ras->callbacks->auth_baton,
  9740. AUTH_PARAM_SSL_SERVER_CERT_INFO, NULL);
  9741. webdav_pool_destroy(pool);
  9742. return !server_creds;
  9743. }
  9744. // An `ne_request_auth' callback, see ne_auth.h. USERDATA is a struct proxy_auth_baton_t *
  9745. // If ATTEMPT < 10, copy USERDATA->username and USERDATA->password
  9746. // into USERNAME and PASSWORD respectively (but do not copy more than
  9747. // NE_ABUFSIZ bytes of either), and return zero to indicate to Neon
  9748. // that authentication should be attempted.
  9749. // If ATTEMPT >= 10, copy nothing into USERNAME and PASSWORD and
  9750. // return 1, to cancel further authentication attempts.
  9751. // Ignore REALM.
  9752. static int
  9753. proxy_auth(
  9754. void * userdata,
  9755. const char * realm,
  9756. int attempt,
  9757. char * username,
  9758. char * password)
  9759. {
  9760. proxy_auth_baton_t * pab = static_cast<proxy_auth_baton_t *>(userdata);
  9761. if (attempt >= 10)
  9762. return 1;
  9763. // Else.
  9764. strncpy(username, pab->username, NE_ABUFSIZ);
  9765. strncpy(password, pab->password, NE_ABUFSIZ);
  9766. return 0;
  9767. }
  9768. // A neon-session callback to 'pull' authentication data when
  9769. // challenged. In turn, this routine 'pulls' the data from the client
  9770. // callbacks if needed.
  9771. static int
  9772. request_auth(
  9773. void * userdata,
  9774. const char * realm,
  9775. int attempt,
  9776. char * username,
  9777. char * password)
  9778. {
  9779. error_t err = 0;
  9780. neon_session_t * ras = static_cast<neon_session_t *>(userdata);
  9781. void * creds = NULL;
  9782. auth_cred_simple_t * simple_creds = NULL;
  9783. // Start by marking the current credentials invalid.
  9784. ras->auth_used = false;
  9785. // No auth_baton? Give up.
  9786. if (!ras->callbacks->auth_baton)
  9787. return -1;
  9788. // Neon automatically tries some auth protocols and bumps the attempt
  9789. // count without using our callbacks, so we can't depend
  9790. // on attempt == 0 the first time we are called -- we need to check
  9791. // if the auth state has been initted as well.
  9792. if (attempt == 0 || ras->auth_iterstate == NULL)
  9793. {
  9794. const char * realmstring = apr_psprintf(ras->pool, "<%s://%s:%d> %s",
  9795. ras->root.scheme, ras->root.host,
  9796. ras->root.port, realm);
  9797. err = auth_first_credentials(&creds,
  9798. &(ras->auth_iterstate),
  9799. AUTH_CRED_SIMPLE,
  9800. realmstring,
  9801. ras->callbacks->auth_baton,
  9802. ras->pool);
  9803. }
  9804. else // attempt > 0
  9805. // TODO: if the http realm changed this time around, we
  9806. // should be calling first_creds(), not next_creds().
  9807. err = auth_next_credentials(&creds,
  9808. ras->auth_iterstate,
  9809. ras->pool);
  9810. if (err || !creds)
  9811. {
  9812. error_clear(&err);
  9813. return -1;
  9814. }
  9815. simple_creds = static_cast<auth_cred_simple_t *>(creds);
  9816. // Make neon_request_dispatch store the credentials after it
  9817. // sees a successful response
  9818. ras->auth_used = true;
  9819. // silently truncates username/password to 256 chars.
  9820. if (simple_creds->username) strncpy(username, simple_creds->username, NE_ABUFSIZ);
  9821. if (simple_creds->password) strncpy(password, simple_creds->password, NE_ABUFSIZ);
  9822. return 0;
  9823. }
  9824. // a cleanup routine attached to the pool that contains the RA session baton.
  9825. static apr_status_t
  9826. cleanup_session(
  9827. void * sess)
  9828. {
  9829. ne_session_destroy(static_cast<ne_session *>(sess));
  9830. return APR_SUCCESS;
  9831. }
  9832. // a cleanup routine attached to the pool that contains the PKCS#11
  9833. // provider object.
  9834. static apr_status_t
  9835. cleanup_p11provider(
  9836. void * provider)
  9837. {
  9838. ne_ssl_pkcs11_provider * prov = static_cast<ne_ssl_pkcs11_provider *>(provider);
  9839. ne_ssl_pkcs11_provider_destroy(prov);
  9840. return APR_SUCCESS;
  9841. }
  9842. #ifdef NETBOX_DEBUG
  9843. typedef struct debug_file_baton_t
  9844. {
  9845. FILE * file;
  9846. } debug_file_baton_t;
  9847. // a cleanup routine
  9848. static apr_status_t
  9849. cleanup_neon_debug_file(
  9850. void * debug_file_baton)
  9851. {
  9852. debug_file_baton_t * baton = static_cast<debug_file_baton_t *>(debug_file_baton);
  9853. if (baton->file) fclose(baton->file);
  9854. return APR_SUCCESS;
  9855. }
  9856. #endif
  9857. static void
  9858. progress_func(
  9859. apr_off_t progress,
  9860. apr_off_t total,
  9861. void * baton,
  9862. apr_pool_t * pool)
  9863. {
  9864. client_ctx_t * ctx = static_cast<client_ctx_t *>(baton);
  9865. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(ctx->auth_baton->parameters,
  9866. CONST_FS_KEY,
  9867. APR_HASH_KEY_STRING));
  9868. assert(fs);
  9869. if (total == -1)
  9870. fs->ReadDirectoryProgress(progress);
  9871. else
  9872. fs->FileTransferProgress(total, progress);
  9873. }
  9874. static void
  9875. ra_neon_neonprogress(
  9876. void * baton,
  9877. apr_off_t progress,
  9878. apr_off_t total)
  9879. {
  9880. neonprogress_baton_t * pb = static_cast<neonprogress_baton_t *>(baton);
  9881. neon_session_t * ras = pb->ras;
  9882. if (ras->progress_func)
  9883. {
  9884. apr_time_t now = apr_time_now();
  9885. if (now - pb->last_progress_time > 200000) // 0.2 sec
  9886. {
  9887. if (total < 0)
  9888. {
  9889. // Neon sends the total number of bytes sent for this specific
  9890. // session and there are two sessions active at once.
  9891. // For this case we combine the totals to allow clients to provide
  9892. // a better progress indicator.
  9893. if (progress >= pb->last_progress)
  9894. ras->total_progress += (progress - pb->last_progress);
  9895. else
  9896. // Session total has been reset. A new stream started
  9897. ras->total_progress += pb->last_progress;
  9898. pb->last_progress = progress;
  9899. ras->progress_func(ras->total_progress, -1, ras->progress_baton, pb->pool);
  9900. }
  9901. else
  9902. {
  9903. // Neon provides total bytes to receive information. Pass literally
  9904. // to allow providing a percentage.
  9905. ras->progress_func(progress, total, ras->progress_baton, pb->pool);
  9906. }
  9907. pb->last_progress_time = now;
  9908. }
  9909. }
  9910. }
  9911. static atomic_t neon_initialized = 0;
  9912. static error_t
  9913. initialize_neon(
  9914. void * baton,
  9915. apr_pool_t * scratch_pool)
  9916. {
  9917. if (ne_sock_init() != 0)
  9918. return error_create(WEBDAV_ERR_DAV_SOCK_INIT, NULL,
  9919. "Network socket initialization failed");
  9920. return WEBDAV_NO_ERROR;
  9921. }
  9922. static error_t
  9923. ensure_neon_initialized()
  9924. {
  9925. return atomic_init_once(&neon_initialized, initialize_neon, NULL, NULL);
  9926. }
  9927. static const char * const *
  9928. ra_neon_get_schemes(apr_pool_t * pool)
  9929. {
  9930. static const char * schemes_no_ssl[] = { "http", NULL };
  9931. static const char * schemes_ssl[] = { "http", "https", NULL };
  9932. return ne_has_support(NE_FEATURE_SSL) ? schemes_ssl : schemes_no_ssl;
  9933. }
  9934. static error_t
  9935. neon_open(
  9936. session_t * session,
  9937. const char ** corrected_url,
  9938. const char * session_URL,
  9939. const callbacks2_t * callbacks,
  9940. void * callback_baton,
  9941. apr_pool_t * pool)
  9942. {
  9943. assert(callback_baton);
  9944. callback_baton_t * cb = static_cast<callback_baton_t *>(callback_baton);
  9945. *corrected_url = NULL;
  9946. ne_uri * uri = NULL;
  9947. WEBDAV_ERR(parse_ne_uri(&uri, session_URL, pool));
  9948. // Initialize neon if required
  9949. WEBDAV_ERR(ensure_neon_initialized());
  9950. int is_ssl_session = (strcmp(uri->scheme, "https") == 0);
  9951. if (is_ssl_session)
  9952. {
  9953. if (ne_has_support(NE_FEATURE_SSL) == 0)
  9954. return error_create(WEBDAV_ERR_DAV_SOCK_INIT, NULL,
  9955. "TLS is not supported");
  9956. }
  9957. ne_session * sess = ne_session_create(uri->scheme, uri->host, uri->port);
  9958. apr_pool_cleanup_register(pool, sess, cleanup_session, apr_pool_cleanup_null);
  9959. bool compression = FALSE;
  9960. unsigned int neon_auth_types = 0;
  9961. const char * pkcs11_provider = NULL;
  9962. const char * ssl_authority_file = NULL;
  9963. {
  9964. int proxy_method = 0;
  9965. const char * proxy_host = NULL;
  9966. unsigned int proxy_port = 0;
  9967. const char * proxy_username = NULL;
  9968. const char * proxy_password = NULL;
  9969. int timeout = 0;
  9970. int debug = 0;
  9971. const char * neon_debug_file_name = NULL;
  9972. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(cb->ctx->auth_baton->parameters,
  9973. CONST_FS_KEY,
  9974. APR_HASH_KEY_STRING));
  9975. assert(fs);
  9976. WEBDAV_ERR(fs->GetServerSettings(
  9977. &proxy_method,
  9978. &proxy_host,
  9979. &proxy_port,
  9980. &proxy_username,
  9981. &proxy_password,
  9982. &timeout,
  9983. &debug,
  9984. &neon_debug_file_name,
  9985. &compression,
  9986. &pkcs11_provider,
  9987. &ssl_authority_file,
  9988. pool));
  9989. if (neon_auth_types == 0)
  9990. {
  9991. // If there were no auth types specified in the configuration
  9992. // file, provide the appropriate defaults.
  9993. neon_auth_types = NE_AUTH_BASIC | NE_AUTH_DIGEST;
  9994. if (is_ssl_session)
  9995. neon_auth_types |= NE_AUTH_NEGOTIATE;
  9996. }
  9997. if (debug && neon_debug_file_name)
  9998. {
  9999. #ifdef NETBOX_DEBUG
  10000. debug_file_baton_t * baton = static_cast<debug_file_baton_t *>(apr_pcalloc(pool, sizeof(*baton)));
  10001. neon_debug_file_name = apr_pstrcat(pool, neon_debug_file_name, ".neondebug.log", NULL);
  10002. baton->file = _fsopen(neon_debug_file_name, "w", SH_DENYWR);
  10003. if (baton->file)
  10004. {
  10005. debug = NE_DBG_HTTP |
  10006. // NE_DBG_XML | NE_DBG_HTTPAUTH |
  10007. NE_DBG_HTTPPLAIN |
  10008. // NE_DBG_XMLPARSE |
  10009. NE_DBG_HTTPBODY |
  10010. // NE_DBG_SSL |
  10011. NE_DBG_FLUSH;
  10012. ne_debug_init(baton->file, debug);
  10013. }
  10014. apr_pool_cleanup_register(pool, baton,
  10015. cleanup_neon_debug_file,
  10016. apr_pool_cleanup_null);
  10017. #else
  10018. ne_debug_init(NULL, 0);
  10019. #endif // #ifdef NETBOX_DEBUG
  10020. }
  10021. TProxyMethod method = (TProxyMethod)proxy_method;
  10022. if (method != ::pmNone)
  10023. {
  10024. if ((method == pmSocks4) || (method == pmSocks5))
  10025. {
  10026. enum ne_sock_sversion vers = method == pmSocks4 ? NE_SOCK_SOCKSV4A : NE_SOCK_SOCKSV5;
  10027. ne_session_socks_proxy(sess, vers, proxy_host, proxy_port, proxy_username, proxy_password);
  10028. }
  10029. else if (proxy_host)
  10030. {
  10031. ne_session_proxy(sess, proxy_host, proxy_port);
  10032. if (proxy_username)
  10033. {
  10034. proxy_auth_baton_t * pab = static_cast<proxy_auth_baton_t *>(apr_pcalloc(pool, sizeof(*pab)));
  10035. pab->username = proxy_username;
  10036. pab->password = proxy_password ? proxy_password : "";
  10037. ne_set_proxy_auth(sess, proxy_auth, pab);
  10038. }
  10039. else
  10040. {
  10041. // Enable (only) the Negotiate scheme for proxy
  10042. // authentication, if no username/password is
  10043. // configured.
  10044. ne_add_proxy_auth(sess, NE_AUTH_NEGOTIATE, NULL, NULL);
  10045. }
  10046. }
  10047. }
  10048. if (!timeout)
  10049. timeout = DEFAULT_HTTP_TIMEOUT;
  10050. ne_set_read_timeout(sess, timeout);
  10051. ne_set_connect_timeout(sess, timeout);
  10052. }
  10053. {
  10054. static std::string useragent = "WinSCP";
  10055. ne_set_useragent(sess, useragent.c_str());
  10056. }
  10057. // Create and fill a session_baton.
  10058. neon_session_t * ras = static_cast<neon_session_t *>(apr_pcalloc(pool, sizeof(*ras)));
  10059. ras->pool = pool;
  10060. {
  10061. // canonicalize url
  10062. const char * remote_url = urlpath_canonicalize(session_URL, pool);
  10063. ras->url = stringbuf_create(remote_url, pool);
  10064. }
  10065. // copies uri pointer members, they get free'd in __close.
  10066. ras->root = *uri;
  10067. ras->ne_sess = sess;
  10068. ras->callbacks = callbacks;
  10069. ras->callback_baton = callback_baton;
  10070. ras->compression = compression;
  10071. ras->progress_baton = callbacks->progress_baton;
  10072. ras->progress_func = callbacks->progress_func;
  10073. ras->capabilities = apr_hash_make(ras->pool);
  10074. // note that ras->username and ras->password are still NULL at this point.
  10075. // Register an authentication 'pull' callback with the neon sessions
  10076. ne_add_server_auth(sess, neon_auth_types, request_auth, ras);
  10077. if (is_ssl_session)
  10078. {
  10079. bool trust_default_ca = false;
  10080. // PEM-encoded Certificate Authority (CA) SSL certificate
  10081. const char * authorities = ssl_authority_file;
  10082. if (authorities != NULL && *authorities)
  10083. {
  10084. const char * file = authorities;
  10085. ne_ssl_certificate * ca_cert = NULL;
  10086. ca_cert = ne_ssl_cert_read(file);
  10087. if (ca_cert == NULL)
  10088. {
  10089. return error_createf(
  10090. WEBDAV_ERR_BAD_CONFIG_VALUE, NULL,
  10091. "Invalid config: unable to load certificate file '%s'", file);
  10092. }
  10093. ne_ssl_trust_cert(sess, ca_cert);
  10094. ne_ssl_cert_free(ca_cert);
  10095. ca_cert = NULL;
  10096. }
  10097. // When the CA certificate or server certificate has
  10098. // verification problems, neon will call our verify function before
  10099. // outright rejection of the connection.*/
  10100. ne_ssl_set_verify(sess, server_ssl_callback, ras);
  10101. // For client connections, we register a callback for if the server
  10102. // wants to authenticate the client via client certificate.
  10103. if (pkcs11_provider && *pkcs11_provider)
  10104. {
  10105. ne_ssl_pkcs11_provider * provider;
  10106. int rv;
  10107. // Initialize the PKCS#11 provider.
  10108. rv = ne_ssl_pkcs11_provider_init(&provider, pkcs11_provider);
  10109. if (rv != NE_PK11_OK)
  10110. {
  10111. return error_createf(WEBDAV_ERR_BAD_CONFIG_VALUE, NULL,
  10112. "Invalid config: unable to load PKCS#11 provider '%s'",
  10113. pkcs11_provider);
  10114. }
  10115. // Share the provider between the two sessions.
  10116. ne_ssl_set_pkcs11_provider(sess, provider);
  10117. ne_ssl_pkcs11_provider_pin(provider, client_ssl_pkcs11_pin_entry, ras);
  10118. apr_pool_cleanup_register(pool, provider, cleanup_p11provider,
  10119. apr_pool_cleanup_null);
  10120. }
  10121. // Note the "else"; if a PKCS#11 provider is set up, a client
  10122. // cert callback is already configured, so don't displace it
  10123. // with the normal one here.
  10124. else
  10125. {
  10126. ne_ssl_provide_clicert(sess, client_ssl_callback, ras);
  10127. }
  10128. // See if the user wants us to trust "default" openssl CAs.
  10129. // TODO: option "trust default CA"
  10130. trust_default_ca = true;
  10131. if (trust_default_ca)
  10132. {
  10133. ne_ssl_trust_default_ca(sess);
  10134. }
  10135. }
  10136. if (ras->progress_func)
  10137. {
  10138. neonprogress_baton_t * progress1 = static_cast<neonprogress_baton_t *>(apr_pcalloc(pool, sizeof(*progress1)));
  10139. neonprogress_baton_t * progress2 = static_cast<neonprogress_baton_t *>(apr_pcalloc(pool, sizeof(*progress2)));
  10140. progress1->pool = pool;
  10141. progress1->ras = ras;
  10142. progress1->last_progress = 0;
  10143. progress2->pool = pool;
  10144. progress2->ras = ras;
  10145. progress2->last_progress = 0;
  10146. ne_set_progress(sess, ra_neon_neonprogress, progress1);
  10147. }
  10148. session->priv = ras;
  10149. const char * corrected = NULL;
  10150. error_t err = neon_exchange_capabilities(ras, &corrected, pool);
  10151. if (corrected)
  10152. *corrected_url = corrected;
  10153. return err;
  10154. }
  10155. static error_t
  10156. neon_reparent(
  10157. session_t * session,
  10158. const char * url,
  10159. apr_pool_t * pool)
  10160. {
  10161. neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
  10162. ne_uri * uri = NULL;
  10163. WEBDAV_ERR(parse_ne_uri(&uri, url, session->pool));
  10164. ras->root = *uri;
  10165. stringbuf_set(ras->url, url);
  10166. ras->webdav_root = neon_uri_unparse(uri, session->pool);
  10167. return WEBDAV_NO_ERROR;
  10168. }
  10169. static error_t
  10170. neon_get_session_url(
  10171. session_t * session,
  10172. const char ** url,
  10173. apr_pool_t * pool)
  10174. {
  10175. neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
  10176. assert(ras);
  10177. *url = apr_pstrmemdup(pool, ras->url->data, ras->url->len);
  10178. return WEBDAV_NO_ERROR;
  10179. }
  10180. static const ne_propname restype_props[] =
  10181. {
  10182. { "DAV:", "resourcetype" },
  10183. { NULL }
  10184. };
  10185. static error_t
  10186. neon_get_file(
  10187. session_t * session,
  10188. const char * path,
  10189. stream_t * stream,
  10190. apr_hash_t ** props,
  10191. apr_pool_t * pool)
  10192. {
  10193. neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
  10194. assert(ras);
  10195. const char * url = path_url_add_component2(ras->url->data, path, pool);
  10196. const ne_propname * which_props = NULL;
  10197. const char * final_url = url;
  10198. if (props)
  10199. {
  10200. // Request all properties if caller requested them.
  10201. which_props = starting_props;
  10202. }
  10203. else
  10204. {
  10205. // Request only resource type on other cases.
  10206. which_props = restype_props;
  10207. }
  10208. neon_resource_t * rsrc = NULL;
  10209. WEBDAV_ERR(neon_get_props_resource(&rsrc, ras, final_url,
  10210. which_props,
  10211. false,
  10212. pool));
  10213. if (rsrc->is_collection)
  10214. {
  10215. return error_create(WEBDAV_ERR_FS_NOT_FILE, NULL,
  10216. "Can't get text contents of a directory");
  10217. }
  10218. if (stream)
  10219. {
  10220. file_write_ctx_t fwc = {0};
  10221. fwc.stream = stream;
  10222. // Fetch the file, shoving it at the provided stream.
  10223. WEBDAV_ERR(custom_get_request(ras, final_url, path,
  10224. get_file_reader, &fwc,
  10225. ras->callback_baton,
  10226. pool));
  10227. }
  10228. return WEBDAV_NO_ERROR;
  10229. }
  10230. static error_t
  10231. neon_get_dir(
  10232. session_t * session,
  10233. apr_hash_t ** dirents,
  10234. const char * path,
  10235. apr_uint32_t dirent_fields,
  10236. apr_pool_t * pool)
  10237. {
  10238. neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
  10239. const char * url = path_url_add_component2(ras->url->data, path, pool);
  10240. const char * final_url = url;
  10241. if (dirents)
  10242. {
  10243. // Just like Nautilus, Cadaver, or any other browser, we do a
  10244. // PROPFIND on the directory of depth 1.
  10245. apr_hash_t * resources = NULL;
  10246. WEBDAV_ERR(neon_get_props(&resources, ras,
  10247. final_url, NEON_DEPTH_ONE,
  10248. starting_props,
  10249. false,
  10250. pool));
  10251. // Count the number of path components in final_url.
  10252. apr_size_t final_url_n_components = path_component_count(final_url);
  10253. // Now we have a hash that maps a bunch of url children to resource
  10254. // objects. Each resource object contains the properties of the
  10255. // child. Parse these resources into dirent_t structs.
  10256. *dirents = apr_hash_make(pool);
  10257. for (apr_hash_index_t * hi = apr_hash_first(pool, resources); hi;
  10258. hi = apr_hash_next(hi))
  10259. {
  10260. const void * key = NULL;
  10261. void * val = NULL;
  10262. const char * childname = NULL;
  10263. neon_resource_t * resource = NULL;
  10264. const string_t * propval = NULL;
  10265. dirent_t * entry = NULL;
  10266. apr_hash_this(hi, &key, NULL, &val);
  10267. childname = relpath_canonicalize(static_cast<const char *>(key), pool);
  10268. resource = static_cast<neon_resource_t *>(val);
  10269. // Skip the effective '.' entry that comes back from
  10270. // NEON_DEPTH_ONE. The children must have one more
  10271. // component then final_url.
  10272. // Note that we can't just strcmp the URLs because of URL encoding
  10273. // differences (i.e. %3c vs. %3C etc.)
  10274. if (path_component_count(childname) < final_url_n_components - 1)
  10275. continue;
  10276. entry = static_cast<dirent_t *>(apr_pcalloc(pool, sizeof(*entry)));
  10277. if (dirent_fields & WEBDAV_DIRENT_KIND)
  10278. {
  10279. // node kind
  10280. entry->kind = resource->is_collection ? node_dir : node_file;
  10281. }
  10282. if (dirent_fields & WEBDAV_DIRENT_SIZE)
  10283. {
  10284. // size
  10285. propval = static_cast<const string_t *>(apr_hash_get(resource->propset,
  10286. NEON_PROP_GETCONTENTLENGTH,
  10287. APR_HASH_KEY_STRING));
  10288. if (propval == NULL)
  10289. entry->size = 0;
  10290. else
  10291. entry->size = atoui64(propval->data);
  10292. }
  10293. if (dirent_fields & WEBDAV_DIRENT_TIME)
  10294. {
  10295. propval = static_cast<const string_t *>(apr_hash_get(resource->propset,
  10296. NEON_PROP_CREATIONDATE,
  10297. APR_HASH_KEY_STRING));
  10298. if (propval != NULL)
  10299. WEBDAV_ERR(time_from_cstring(&(entry->time),
  10300. propval->data, pool));
  10301. }
  10302. apr_hash_set(*dirents,
  10303. path_uri_decode(relpath_basename(childname,
  10304. pool),
  10305. pool),
  10306. APR_HASH_KEY_STRING, entry);
  10307. }
  10308. }
  10309. return WEBDAV_NO_ERROR;
  10310. }
  10311. static error_t
  10312. neon_check_path(
  10313. session_t * session,
  10314. const char * path,
  10315. node_kind_t * kind,
  10316. apr_pool_t * pool)
  10317. {
  10318. neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
  10319. assert(ras);
  10320. const char * url = ras->url->data;
  10321. error_t err = 0;
  10322. bool is_dir = FALSE;
  10323. // If we were given a relative path to append, append it.
  10324. if (path)
  10325. url = path_url_add_component2(url, path, pool);
  10326. if (!err)
  10327. {
  10328. neon_resource_t * rsrc;
  10329. const char * full_bc_url = url;
  10330. // query the DAV:resourcetype of the full, assembled URL.
  10331. err = neon_get_starting_props(&rsrc, ras, full_bc_url, true, pool);
  10332. if (!err)
  10333. is_dir = rsrc->is_collection != 0;
  10334. }
  10335. if (err == WEBDAV_NO_ERROR)
  10336. {
  10337. if (is_dir)
  10338. *kind = node_dir;
  10339. else
  10340. *kind = node_file;
  10341. }
  10342. else if (err == WEBDAV_ERR_FS_NOT_FOUND)
  10343. {
  10344. error_clear(&err);
  10345. err = WEBDAV_NO_ERROR;
  10346. *kind = node_none;
  10347. }
  10348. return err;
  10349. }
  10350. static error_t
  10351. neon_stat(
  10352. session_t * session,
  10353. const char * path,
  10354. dirent_t ** dirent,
  10355. apr_pool_t * pool)
  10356. {
  10357. neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
  10358. assert(ras);
  10359. const char * url = ras->url->data;
  10360. // If we were given a relative path to append, append it.
  10361. if (path)
  10362. url = path_url_add_component2(url, path, pool);
  10363. const char * final_url = url;
  10364. // Depth-zero PROPFIND is the One True DAV Way.
  10365. apr_hash_t * resources = NULL;
  10366. error_t err = neon_get_props(&resources, ras, final_url,
  10367. NEON_DEPTH_ZERO,
  10368. starting_props,
  10369. false,
  10370. pool);
  10371. if (err)
  10372. {
  10373. if (err == WEBDAV_ERR_FS_NOT_FOUND)
  10374. {
  10375. // easy out:
  10376. error_clear(&err);
  10377. *dirent = NULL;
  10378. return WEBDAV_NO_ERROR;
  10379. }
  10380. else
  10381. return err;
  10382. }
  10383. // Copying parsing code from neon_get_dir() here. The hash
  10384. // of resources only contains one item, but there's no other way to
  10385. // get the item.
  10386. for (apr_hash_index_t * hi = apr_hash_first(pool, resources); hi;
  10387. hi = apr_hash_next(hi))
  10388. {
  10389. void * val = NULL;
  10390. apr_hash_this(hi, NULL, NULL, &val);
  10391. neon_resource_t * resource = static_cast<neon_resource_t *>(val);
  10392. dirent_t * entry = static_cast<dirent_t *>(apr_pcalloc(pool, sizeof(*entry)));
  10393. entry->kind = resource->is_collection ? node_dir : node_file;
  10394. const string_t * propval = NULL;
  10395. // entry->size is already 0 by virtue of pcalloc().
  10396. if (entry->kind == node_file)
  10397. {
  10398. propval = static_cast<const string_t *>(apr_hash_get(resource->propset,
  10399. NEON_PROP_GETCONTENTLENGTH,
  10400. APR_HASH_KEY_STRING));
  10401. if (propval)
  10402. entry->size = atoui64(propval->data);
  10403. }
  10404. propval = static_cast<const string_t *>(apr_hash_get(resource->propset,
  10405. NEON_PROP_CREATIONDATE,
  10406. APR_HASH_KEY_STRING));
  10407. if (propval != NULL)
  10408. WEBDAV_ERR(time_from_cstring(&(entry->time),
  10409. propval->data, pool));
  10410. *dirent = entry;
  10411. }
  10412. return WEBDAV_NO_ERROR;
  10413. }
  10414. static error_t
  10415. neon_get_webdav_resource_root(
  10416. session_t * session,
  10417. const char ** url,
  10418. apr_pool_t * pool)
  10419. {
  10420. neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
  10421. assert(ras);
  10422. *url = ras->webdav_root;
  10423. return WEBDAV_NO_ERROR;
  10424. }
  10425. static const vtable_t neon_vtable =
  10426. {
  10427. NULL, // get_description
  10428. ra_neon_get_schemes, // get_schemes
  10429. neon_open, // open_session
  10430. neon_reparent, // reparent
  10431. neon_get_session_url, // get_session_url
  10432. neon_get_file, // get_file
  10433. neon_get_dir, // get_dir
  10434. neon_check_path, // check_path
  10435. neon_stat, // stat
  10436. neon_get_webdav_resource_root, // get_webdav_resource_root
  10437. };
  10438. static error_t
  10439. neon_init(
  10440. const vtable_t ** vtable,
  10441. apr_pool_t * pool)
  10442. {
  10443. *vtable = &neon_vtable;
  10444. return WEBDAV_NO_ERROR;
  10445. }
  10446. } // namespace webdav
  10447. //---------------------------------------------------------------------------
  10448. class TSessionData;
  10449. //---------------------------------------------------------------------------
  10450. class TWebDAVFileListHelper
  10451. {
  10452. public:
  10453. explicit TWebDAVFileListHelper(TWebDAVFileSystem * FileSystem, TRemoteFileList * FileList,
  10454. bool IgnoreFileList) :
  10455. FFileSystem(FileSystem),
  10456. FFileList(FFileSystem->FFileList),
  10457. FIgnoreFileList(FFileSystem->FIgnoreFileList)
  10458. {
  10459. FFileSystem->FFileList = FileList;
  10460. FFileSystem->FIgnoreFileList = IgnoreFileList;
  10461. }
  10462. ~TWebDAVFileListHelper()
  10463. {
  10464. FFileSystem->FFileList = FFileList;
  10465. FFileSystem->FIgnoreFileList = FIgnoreFileList;
  10466. }
  10467. private:
  10468. TWebDAVFileSystem * FFileSystem;
  10469. TRemoteFileList * FFileList;
  10470. bool FIgnoreFileList;
  10471. };
  10472. //---------------------------------------------------------------------------
  10473. #undef FILE_OPERATION_LOOP_EX
  10474. #define FILE_OPERATION_LOOP_EX(ALLOW_SKIP, MESSAGE, OPERATION) \
  10475. FILE_OPERATION_LOOP_CUSTOM(FTerminal, ALLOW_SKIP, MESSAGE, OPERATION, L"")
  10476. //---------------------------------------------------------------------------
  10477. static const UnicodeString CONST_WEBDAV_PROTOCOL_BASE_NAME = L"WebDAV";
  10478. //===========================================================================
  10479. TWebDAVFileSystem::TWebDAVFileSystem(TTerminal * ATerminal) :
  10480. TCustomFileSystem(ATerminal),
  10481. FFileList(NULL),
  10482. FOnCaptureOutput(NULL),
  10483. FPasswordFailed(false),
  10484. FActive(false),
  10485. FFileTransferAbort(ftaNone),
  10486. FIgnoreFileList(false),
  10487. FFileTransferCancelled(false),
  10488. FFileTransferResumed(0),
  10489. FFileTransferPreserveTime(false),
  10490. FHasTrailingSlash(false),
  10491. FFileTransferCPSLimit(0),
  10492. FLastReadDirectoryProgress(0),
  10493. FCurrentOperationProgress(NULL),
  10494. FTransferStatusCriticalSection(new TCriticalSection()),
  10495. webdav_pool(NULL),
  10496. FSession(NULL)
  10497. {
  10498. FFileSystemInfo.ProtocolBaseName = CONST_WEBDAV_PROTOCOL_BASE_NAME;
  10499. FFileSystemInfo.ProtocolName = FFileSystemInfo.ProtocolBaseName;
  10500. if (apr_initialize() != APR_SUCCESS)
  10501. throw ExtException(UnicodeString(L"Cannot init APR"), NULL);
  10502. apr_pool_create(&webdav_pool, NULL);
  10503. }
  10504. //---------------------------------------------------------------------------
  10505. __fastcall TWebDAVFileSystem::~TWebDAVFileSystem()
  10506. {
  10507. delete FTransferStatusCriticalSection;
  10508. FTransferStatusCriticalSection = NULL;
  10509. webdav_pool_destroy(webdav_pool);
  10510. apr_terminate();
  10511. webdav_pool = NULL;
  10512. ne_sock_exit();
  10513. }
  10514. //---------------------------------------------------------------------------
  10515. void __fastcall TWebDAVFileSystem::Open()
  10516. {
  10517. FCurrentDirectory = L"";
  10518. FHasTrailingSlash = false;
  10519. TSessionData * Data = FTerminal->SessionData;
  10520. FSessionInfo.LoginTime = Now();
  10521. bool Ssl = (FTerminal->SessionData->Ftps != ftpsNone);
  10522. if (Ssl)
  10523. {
  10524. FSessionInfo.SecurityProtocolName = LoadStr(FTPS_IMPLICIT);
  10525. }
  10526. UnicodeString HostName = Data->HostName;
  10527. size_t Port = Data->PortNumber;
  10528. UnicodeString ProtocolName = !Ssl ? L"http" : L"https";
  10529. UnicodeString UserName = Data->UserName;
  10530. UnicodeString Path = Data->RemoteDirectory;
  10531. UnicodeString Url = FORMAT(L"%s://%s:%d%s", (ProtocolName.c_str(), HostName.c_str(), Port, Path.c_str()));
  10532. FPasswordFailed = false;
  10533. FTerminal->Information(LoadStr(STATUS_CONNECT), true);
  10534. for (int I = 0; I < 5; I++)
  10535. {
  10536. FActive = false;
  10537. try
  10538. {
  10539. FActive = (WEBDAV_NO_ERROR == OpenURL(Url, webdav_pool));
  10540. if (FActive)
  10541. {
  10542. break;
  10543. }
  10544. }
  10545. catch (...)
  10546. {
  10547. if (FFileTransferCancelled)
  10548. break;
  10549. apr_sleep(200000); // 0.2 sec
  10550. }
  10551. }
  10552. if (!FActive)
  10553. {
  10554. FTerminal->Closed();
  10555. throw Exception(LoadStr(CONNECTION_FAILED));
  10556. }
  10557. }
  10558. //---------------------------------------------------------------------------
  10559. void __fastcall TWebDAVFileSystem::Close()
  10560. {
  10561. assert(FActive);
  10562. FTerminal->Closed();
  10563. FActive = false;
  10564. }
  10565. //---------------------------------------------------------------------------
  10566. bool __fastcall TWebDAVFileSystem::GetActive()
  10567. {
  10568. return FActive;
  10569. }
  10570. //---------------------------------------------------------------------------
  10571. const TSessionInfo & __fastcall TWebDAVFileSystem::GetSessionInfo()
  10572. {
  10573. return FSessionInfo;
  10574. }
  10575. //---------------------------------------------------------------------------
  10576. const TFileSystemInfo & __fastcall TWebDAVFileSystem::GetFileSystemInfo(bool Retrieve)
  10577. {
  10578. return FFileSystemInfo;
  10579. }
  10580. //---------------------------------------------------------------------------
  10581. bool __fastcall TWebDAVFileSystem::TemporaryTransferFile(const UnicodeString & /*FileName*/)
  10582. {
  10583. return false;
  10584. }
  10585. //---------------------------------------------------------------------------
  10586. bool __fastcall TWebDAVFileSystem::GetStoredCredentialsTried()
  10587. {
  10588. return false;
  10589. }
  10590. //---------------------------------------------------------------------------
  10591. UnicodeString __fastcall TWebDAVFileSystem::GetUserName()
  10592. {
  10593. return FUserName;
  10594. }
  10595. //---------------------------------------------------------------------------
  10596. void __fastcall TWebDAVFileSystem::Idle()
  10597. {
  10598. // TODO: Keep session alive
  10599. return;
  10600. }
  10601. //---------------------------------------------------------------------------
  10602. UnicodeString __fastcall TWebDAVFileSystem::AbsolutePath(const UnicodeString Path, bool /*Local*/)
  10603. {
  10604. return ::AbsolutePath(GetCurrentDirectory(), Path);
  10605. }
  10606. //---------------------------------------------------------------------------
  10607. bool __fastcall TWebDAVFileSystem::IsCapable(int Capability) const
  10608. {
  10609. assert(FTerminal);
  10610. switch (Capability)
  10611. {
  10612. case fcUserGroupListing:
  10613. case fcModeChanging:
  10614. case fcModeChangingUpload:
  10615. case fcPreservingTimestampUpload:
  10616. case fcGroupChanging:
  10617. case fcOwnerChanging:
  10618. case fcAnyCommand:
  10619. case fcShellAnyCommand:
  10620. case fcHardLink:
  10621. case fcSymbolicLink:
  10622. case fcResolveSymlink:
  10623. return false;
  10624. case fcRename:
  10625. case fcRemoteMove:
  10626. case fcRemoteCopy:
  10627. return true;
  10628. case fcTextMode:
  10629. case fcNativeTextMode:
  10630. case fcNewerOnlyUpload:
  10631. case fcTimestampChanging:
  10632. case fcLoadingAdditionalProperties:
  10633. case fcCheckingSpaceAvailable:
  10634. case fcIgnorePermErrors:
  10635. case fcCalculatingChecksum:
  10636. case fcSecondaryShell: // has fcShellAnyCommand
  10637. case fcGroupOwnerChangingByID: // by name
  10638. return false;
  10639. default:
  10640. assert(false);
  10641. return false;
  10642. }
  10643. }
  10644. //---------------------------------------------------------------------------
  10645. void __fastcall TWebDAVFileSystem::EnsureLocation()
  10646. {
  10647. if (!FCachedDirectoryChange.IsEmpty())
  10648. {
  10649. FTerminal->LogEvent(FORMAT(L"Locating to cached directory \"%s\".",
  10650. (FCachedDirectoryChange.c_str())));
  10651. UnicodeString Directory = FCachedDirectoryChange;
  10652. FCachedDirectoryChange = L"";
  10653. try
  10654. {
  10655. ChangeDirectory(Directory);
  10656. }
  10657. catch (...)
  10658. {
  10659. // when location to cached directory fails, pretend again
  10660. // location in cached directory
  10661. // here used to be check (CurrentDirectory != Directory), but it is
  10662. // false always (currentdirectory is already set to cached directory),
  10663. // making the condition below useless. check removed.
  10664. if (FTerminal->GetActive())
  10665. {
  10666. FCachedDirectoryChange = Directory;
  10667. }
  10668. throw;
  10669. }
  10670. }
  10671. }
  10672. //---------------------------------------------------------------------------
  10673. UnicodeString __fastcall TWebDAVFileSystem::GetCurrentDirectory()
  10674. {
  10675. return FCurrentDirectory;
  10676. }
  10677. //---------------------------------------------------------------------------
  10678. void __fastcall TWebDAVFileSystem::DoStartup()
  10679. {
  10680. FTerminal->SetExceptionOnFail(true);
  10681. // retrieve initialize working directory to save it as home directory
  10682. ReadCurrentDirectory();
  10683. FTerminal->SetExceptionOnFail(false);
  10684. }
  10685. //---------------------------------------------------------------------------
  10686. //---------------------------------------------------------------------------
  10687. void __fastcall TWebDAVFileSystem::LookupUsersGroups()
  10688. {
  10689. }
  10690. //---------------------------------------------------------------------------
  10691. void __fastcall TWebDAVFileSystem::ReadCurrentDirectory()
  10692. {
  10693. if (FCachedDirectoryChange.IsEmpty())
  10694. {
  10695. FCurrentDirectory = FCurrentDirectory.IsEmpty() ? UnicodeString(L"/") : FCurrentDirectory;
  10696. }
  10697. else
  10698. {
  10699. FCurrentDirectory = FCachedDirectoryChange;
  10700. }
  10701. }
  10702. //---------------------------------------------------------------------------
  10703. void __fastcall TWebDAVFileSystem::HomeDirectory()
  10704. {
  10705. }
  10706. //---------------------------------------------------------------------------
  10707. void __fastcall TWebDAVFileSystem::AnnounceFileListOperation()
  10708. {
  10709. // noop
  10710. }
  10711. //---------------------------------------------------------------------------
  10712. void __fastcall TWebDAVFileSystem::DoChangeDirectory(const UnicodeString Directory)
  10713. {
  10714. }
  10715. //---------------------------------------------------------------------------
  10716. void __fastcall TWebDAVFileSystem::ChangeDirectory(const UnicodeString ADirectory)
  10717. {
  10718. UnicodeString Directory = ADirectory;
  10719. bool HasTrailingSlash = (Directory.Length() > 0) && (Directory[Directory.Length()] == L'/');
  10720. try
  10721. {
  10722. // For changing directory, we do not make paths absolute, instead we
  10723. // delegate this to the server, hence we synchronize current working
  10724. // directory with the server and only then we ask for the change with
  10725. // relative path.
  10726. // But if synchronization fails, typically because current working directory
  10727. // no longer exists, we fall back to out own resolution, to give
  10728. // user chance to leave the non-existing directory.
  10729. EnsureLocation();
  10730. }
  10731. catch (...)
  10732. {
  10733. if (FTerminal->GetActive())
  10734. {
  10735. Directory = AbsolutePath(Directory, false);
  10736. if (HasTrailingSlash)
  10737. Directory = ::UnixIncludeTrailingBackslash(Directory);
  10738. }
  10739. else
  10740. {
  10741. throw;
  10742. }
  10743. }
  10744. FCurrentDirectory = AbsolutePath(Directory, false);
  10745. if (HasTrailingSlash)
  10746. FCurrentDirectory = ::UnixIncludeTrailingBackslash(FCurrentDirectory);
  10747. // make next ReadCurrentDirectory retrieve actual server-side current directory
  10748. FCachedDirectoryChange = L"";
  10749. }
  10750. //---------------------------------------------------------------------------
  10751. void __fastcall TWebDAVFileSystem::CachedChangeDirectory(const UnicodeString Directory)
  10752. {
  10753. FCachedDirectoryChange = UnixExcludeTrailingBackslash(Directory);
  10754. }
  10755. void __fastcall TWebDAVFileSystem::DoReadDirectory(TRemoteFileList * FileList)
  10756. {
  10757. FileList->Reset();
  10758. // add parent directory
  10759. FileList->AddFile(new TRemoteParentDirectory(FTerminal));
  10760. FLastReadDirectoryProgress = 0;
  10761. TWebDAVFileListHelper Helper(this, FileList, false);
  10762. // always specify path to list, do not attempt to
  10763. // list "current" dir as:
  10764. // 1) List() lists again the last listed directory, not the current working directory
  10765. // 2) we handle this way the cached directory change
  10766. UnicodeString Directory = AbsolutePath(FileList->Directory, false);
  10767. if (FHasTrailingSlash)
  10768. Directory = ::UnixIncludeTrailingBackslash(Directory);
  10769. WebDAVGetList(Directory);
  10770. }
  10771. //---------------------------------------------------------------------------
  10772. void __fastcall TWebDAVFileSystem::ReadDirectory(TRemoteFileList * FileList)
  10773. {
  10774. assert(FileList);
  10775. bool Repeat = false;
  10776. do
  10777. {
  10778. Repeat = false;
  10779. try
  10780. {
  10781. DoReadDirectory(FileList);
  10782. }
  10783. catch (Exception &)
  10784. {
  10785. if (!FTerminal->GetActive())
  10786. {
  10787. FTerminal->Reopen(ropNoReadDirectory);
  10788. Repeat = true;
  10789. }
  10790. else
  10791. {
  10792. throw;
  10793. }
  10794. }
  10795. }
  10796. while (Repeat);
  10797. }
  10798. //---------------------------------------------------------------------------
  10799. void __fastcall TWebDAVFileSystem::ReadSymlink(TRemoteFile * SymlinkFile,
  10800. TRemoteFile *& File)
  10801. {
  10802. CustomReadFile(SymlinkFile->LinkTo, File, SymlinkFile);
  10803. }
  10804. //---------------------------------------------------------------------------
  10805. void __fastcall TWebDAVFileSystem::ReadFile(const UnicodeString FileName,
  10806. TRemoteFile *& File)
  10807. {
  10808. CustomReadFile(FileName, File, NULL);
  10809. }
  10810. //---------------------------------------------------------------------------
  10811. void __fastcall TWebDAVFileSystem::CustomReadFile(const UnicodeString FileName,
  10812. TRemoteFile *& File, TRemoteFile * ALinkedByFile)
  10813. {
  10814. File = NULL;
  10815. bool isExist = false;
  10816. int is_dir = 0;
  10817. isExist = WebDAVCheckExisting(FileName.c_str(), is_dir);
  10818. if (isExist)
  10819. {
  10820. File = new TRemoteFile();
  10821. if (is_dir)
  10822. File->Type = FILETYPE_DIRECTORY;
  10823. }
  10824. }
  10825. //---------------------------------------------------------------------------
  10826. void __fastcall TWebDAVFileSystem::DeleteFile(const UnicodeString FileName,
  10827. const TRemoteFile * File, int Params, TRmSessionAction & Action)
  10828. {
  10829. USEDPARAM(File);
  10830. USEDPARAM(Params);
  10831. UnicodeString FullFileName = File->FullFileName;
  10832. bool res = WebDAVDeleteFile(FullFileName.c_str());
  10833. if (!res)
  10834. {
  10835. THROW_SKIP_FILE(NULL, L"");
  10836. }
  10837. }
  10838. //---------------------------------------------------------------------------
  10839. void __fastcall TWebDAVFileSystem::RenameFile(const UnicodeString FileName,
  10840. const UnicodeString NewName)
  10841. {
  10842. UnicodeString FullFileName = ::UnixIncludeTrailingBackslash(FCurrentDirectory) + FileName;
  10843. bool res = WebDAVRenameFile(FullFileName.c_str(), NewName.c_str());
  10844. if (!res)
  10845. {
  10846. THROW_SKIP_FILE(NULL, L"");
  10847. }
  10848. }
  10849. //---------------------------------------------------------------------------
  10850. void __fastcall TWebDAVFileSystem::CopyFile(const UnicodeString FileName,
  10851. const UnicodeString NewName)
  10852. {
  10853. }
  10854. //---------------------------------------------------------------------------
  10855. void __fastcall TWebDAVFileSystem::CreateDirectory(const UnicodeString DirName)
  10856. {
  10857. UnicodeString FullDirName = AbsolutePath(DirName, true);
  10858. bool res = WebDAVMakeDirectory(FullDirName.c_str());
  10859. if (!res)
  10860. {
  10861. TStringList * Strings = new TStringList();
  10862. Strings->Delimiter = L'/';
  10863. Strings->DelimitedText = DirName;
  10864. UnicodeString CurDir;
  10865. for (int i = 0; i < Strings->Count; i++)
  10866. {
  10867. if (Strings->Strings[i].IsEmpty())
  10868. {
  10869. continue;
  10870. }
  10871. CurDir += L"/" + Strings->Strings[i];
  10872. res = WebDAVMakeDirectory(CurDir.c_str());
  10873. }
  10874. if (!res)
  10875. {
  10876. THROW_SKIP_FILE(NULL, L"");
  10877. }
  10878. }
  10879. }
  10880. //---------------------------------------------------------------------------
  10881. void __fastcall TWebDAVFileSystem::CreateLink(const UnicodeString FileName,
  10882. const UnicodeString PointTo, bool Symbolic)
  10883. {
  10884. }
  10885. //---------------------------------------------------------------------------
  10886. void __fastcall TWebDAVFileSystem::ChangeFileProperties(const UnicodeString FileName,
  10887. const TRemoteFile * File, const TRemoteProperties * Properties,
  10888. TChmodSessionAction & Action)
  10889. {
  10890. assert(Properties);
  10891. }
  10892. //---------------------------------------------------------------------------
  10893. bool __fastcall TWebDAVFileSystem::LoadFilesProperties(TStrings * /*FileList*/)
  10894. {
  10895. assert(false);
  10896. return false;
  10897. }
  10898. //---------------------------------------------------------------------------
  10899. void __fastcall TWebDAVFileSystem::CalculateFilesChecksum(const UnicodeString & /*Alg*/,
  10900. TStrings * /*FileList*/, TStrings * /*Checksums*/,
  10901. TCalculatedChecksumEvent /*OnCalculatedChecksum*/)
  10902. {
  10903. assert(false);
  10904. }
  10905. //---------------------------------------------------------------------------
  10906. bool __fastcall TWebDAVFileSystem::ConfirmOverwrite(UnicodeString & FileName,
  10907. TOverwriteMode & OverwriteMode, TFileOperationProgressType * OperationProgress,
  10908. const TOverwriteFileParams * FileParams, const TCopyParamType * CopyParam,
  10909. int Params, bool AutoResume, unsigned int &Answer)
  10910. {
  10911. bool Result;
  10912. bool CanAutoResume = FLAGSET(Params, cpNoConfirmation) && AutoResume;
  10913. bool CanResume = false; // disable resume
  10914. Answer = 0;
  10915. if (CanAutoResume && CanResume)
  10916. {
  10917. Answer = qaRetry;
  10918. }
  10919. else
  10920. {
  10921. // retry = "resume"
  10922. // all = "yes to newer"
  10923. // ignore = "rename"
  10924. int Answers = qaYes | qaNo | qaCancel | qaYesToAll | qaNoToAll | qaAll | qaIgnore;
  10925. if (CanResume)
  10926. {
  10927. Answers |= qaRetry;
  10928. }
  10929. TQueryButtonAlias Aliases[3];
  10930. Aliases[0].Button = qaRetry;
  10931. Aliases[0].Alias = LoadStr(RESUME_BUTTON);
  10932. Aliases[1].Button = qaAll;
  10933. Aliases[1].Alias = LoadStr(YES_TO_NEWER_BUTTON);
  10934. Aliases[2].Button = qaIgnore;
  10935. Aliases[2].Alias = LoadStr(RENAME_BUTTON);
  10936. TQueryParams QueryParams(qpNeverAskAgainCheck);
  10937. QueryParams.Aliases = Aliases;
  10938. QueryParams.AliasesCount = LENOF(Aliases);
  10939. SUSPEND_OPERATION (
  10940. Answer = FTerminal->ConfirmFileOverwrite(FileName, FileParams,
  10941. Answers, &QueryParams,
  10942. OperationProgress->Side == osLocal ? osRemote : osLocal,
  10943. CopyParam, Params, OperationProgress);
  10944. )
  10945. }
  10946. Result = true;
  10947. switch (Answer)
  10948. {
  10949. // resume
  10950. case qaRetry:
  10951. OverwriteMode = omResume;
  10952. assert(FileParams != NULL);
  10953. assert(CanResume);
  10954. FFileTransferResumed = FileParams->DestSize;
  10955. break;
  10956. // rename
  10957. case qaIgnore:
  10958. if (FTerminal->PromptUser(FTerminal->SessionData, pkFileName,
  10959. LoadStr(RENAME_TITLE), L"", LoadStr(RENAME_PROMPT2), true, 0, FileName))
  10960. {
  10961. OverwriteMode = omOverwrite;
  10962. }
  10963. else
  10964. {
  10965. if (!OperationProgress->Cancel)
  10966. {
  10967. OperationProgress->Cancel = csCancel;
  10968. }
  10969. FFileTransferAbort = ftaCancel;
  10970. Result = false;
  10971. }
  10972. break;
  10973. case qaYes:
  10974. OverwriteMode = omOverwrite;
  10975. break;
  10976. case qaNo:
  10977. FFileTransferAbort = ftaSkip;
  10978. Result = false;
  10979. break;
  10980. case qaCancel:
  10981. if (!OperationProgress->Cancel)
  10982. {
  10983. OperationProgress->Cancel = csCancel;
  10984. }
  10985. FFileTransferAbort = ftaCancel;
  10986. Result = false;
  10987. break;
  10988. default:
  10989. assert(false);
  10990. Result = false;
  10991. break;
  10992. }
  10993. return Result;
  10994. }
  10995. //---------------------------------------------------------------------------
  10996. void __fastcall TWebDAVFileSystem::CustomCommandOnFile(const UnicodeString FileName,
  10997. const TRemoteFile * File, UnicodeString Command, int Params, TCaptureOutputEvent OutputEvent)
  10998. {
  10999. assert(File);
  11000. bool Dir = File->IsDirectory && !File->IsSymLink;
  11001. if (Dir && (Params & ccRecursive))
  11002. {
  11003. TCustomCommandParams AParams;
  11004. AParams.Command = Command;
  11005. AParams.Params = Params;
  11006. AParams.OutputEvent = OutputEvent;
  11007. FTerminal->ProcessDirectory(FileName, FTerminal->CustomCommandOnFile, &AParams);
  11008. }
  11009. if (!Dir || (Params & ccApplyToDirectories))
  11010. {
  11011. TCustomCommandData Data(FTerminal);
  11012. UnicodeString Cmd = TRemoteCustomCommand(
  11013. Data, FTerminal->GetCurrentDirectory(), FileName, L"").
  11014. Complete(Command, true);
  11015. }
  11016. }
  11017. //---------------------------------------------------------------------------
  11018. void __fastcall TWebDAVFileSystem::AnyCommand(const UnicodeString Command,
  11019. TCaptureOutputEvent OutputEvent)
  11020. {
  11021. }
  11022. //---------------------------------------------------------------------------
  11023. UnicodeString __fastcall TWebDAVFileSystem::FileUrl(const UnicodeString FileName)
  11024. {
  11025. return FTerminal->FileUrl(FTerminal->SessionData->Ftps == ftpsNone ?
  11026. L"http" : L"https", FileName);
  11027. }
  11028. //---------------------------------------------------------------------------
  11029. TStrings * __fastcall TWebDAVFileSystem::GetFixedPaths()
  11030. {
  11031. return NULL;
  11032. }
  11033. //---------------------------------------------------------------------------
  11034. void __fastcall TWebDAVFileSystem::SpaceAvailable(const UnicodeString Path,
  11035. TSpaceAvailable & /*ASpaceAvailable*/)
  11036. {
  11037. assert(false);
  11038. }
  11039. //---------------------------------------------------------------------------
  11040. void __fastcall TWebDAVFileSystem::CopyToRemote(TStrings * FilesToCopy,
  11041. const UnicodeString ATargetDir, const TCopyParamType * CopyParam,
  11042. int Params, TFileOperationProgressType * OperationProgress,
  11043. TOnceDoneOperation & OnceDoneOperation)
  11044. {
  11045. assert((FilesToCopy != NULL) && (OperationProgress != NULL));
  11046. Params &= ~cpAppend;
  11047. UnicodeString FileName, FileNameOnly;
  11048. UnicodeString TargetDir = AbsolutePath(ATargetDir, false);
  11049. UnicodeString FullTargetDir = ::UnixIncludeTrailingBackslash(TargetDir);
  11050. intptr_t Index = 0;
  11051. while ((Index < FilesToCopy->Count) && !OperationProgress->Cancel)
  11052. {
  11053. bool Success = false;
  11054. FileName = FilesToCopy->Strings[Index];
  11055. FileNameOnly = ExtractFileName(FileName, false);
  11056. try
  11057. {
  11058. try
  11059. {
  11060. if (FTerminal->SessionData->CacheDirectories)
  11061. {
  11062. FTerminal->DirectoryModified(TargetDir, false);
  11063. if (::DirectoryExists(::ExtractFilePath(FileName)))
  11064. {
  11065. FTerminal->DirectoryModified(FullTargetDir + FileNameOnly, true);
  11066. }
  11067. }
  11068. WebDAVSourceRobust(FileName, FullTargetDir, CopyParam, Params, OperationProgress,
  11069. tfFirstLevel);
  11070. Success = true;
  11071. }
  11072. catch (EScpSkipFile & E)
  11073. {
  11074. SUSPEND_OPERATION (
  11075. if (!FTerminal->HandleException(&E))
  11076. {
  11077. throw;
  11078. }
  11079. );
  11080. }
  11081. }
  11082. __finally
  11083. {
  11084. OperationProgress->Finish(FileName, Success, OnceDoneOperation);
  11085. }
  11086. Index++;
  11087. }
  11088. }
  11089. //---------------------------------------------------------------------------
  11090. void __fastcall TWebDAVFileSystem::WebDAVSourceRobust(const UnicodeString FileName,
  11091. const UnicodeString TargetDir, const TCopyParamType * CopyParam, int Params,
  11092. TFileOperationProgressType * OperationProgress, unsigned int Flags)
  11093. {
  11094. bool Retry = false;
  11095. TUploadSessionAction Action(FTerminal->ActionLog);
  11096. do
  11097. {
  11098. Retry = false;
  11099. try
  11100. {
  11101. WebDAVSource(FileName, TargetDir, CopyParam, Params, OperationProgress,
  11102. Flags, Action);
  11103. }
  11104. catch (Exception & E)
  11105. {
  11106. Retry = true;
  11107. if (FTerminal->GetActive() ||
  11108. !FTerminal->QueryReopen(&E, ropNoReadDirectory, OperationProgress))
  11109. {
  11110. FTerminal->RollbackAction(Action, OperationProgress, &E);
  11111. throw;
  11112. }
  11113. }
  11114. if (Retry)
  11115. {
  11116. OperationProgress->RollbackTransfer();
  11117. Action.Restart();
  11118. // prevent overwrite confirmations
  11119. // (should not be set for directories!)
  11120. Params |= cpNoConfirmation;
  11121. Flags |= tfAutoResume;
  11122. }
  11123. }
  11124. while (Retry);
  11125. }
  11126. //---------------------------------------------------------------------------
  11127. void __fastcall TWebDAVFileSystem::WebDAVSource(const UnicodeString FileName,
  11128. const UnicodeString TargetDir, const TCopyParamType * CopyParam, int Params,
  11129. TFileOperationProgressType * OperationProgress, unsigned int Flags,
  11130. TUploadSessionAction & Action)
  11131. {
  11132. bool CheckExistence = UnixComparePaths(TargetDir, FTerminal->GetCurrentDirectory()) &&
  11133. (FTerminal->FFiles != NULL) && FTerminal->FFiles->Loaded;
  11134. FTerminal->LogEvent(FORMAT(L"File: \"%s\"", (FileName.c_str())));
  11135. bool CanProceed = false;
  11136. UnicodeString FileNameOnly =
  11137. CopyParam->ChangeFileName(ExtractFileName(FileName, false), osLocal, true);
  11138. if (CheckExistence)
  11139. {
  11140. TRemoteFile * File = FTerminal->FFiles->FindFile(FileNameOnly);
  11141. if (File != NULL)
  11142. {
  11143. unsigned int Answer = 0;
  11144. if (File->IsDirectory)
  11145. {
  11146. UnicodeString Message = FMTLOAD(DIRECTORY_OVERWRITE, (FileNameOnly.c_str()));
  11147. TQueryParams QueryParams(qpNeverAskAgainCheck);
  11148. SUSPEND_OPERATION (
  11149. Answer = FTerminal->ConfirmFileOverwrite(
  11150. FileNameOnly /*not used*/, NULL,
  11151. qaYes | qaNo | qaCancel | qaYesToAll | qaNoToAll,
  11152. &QueryParams, osRemote, CopyParam, Params, OperationProgress, Message);
  11153. );
  11154. switch (Answer)
  11155. {
  11156. case qaYes:
  11157. CanProceed = true;
  11158. break;
  11159. case qaCancel:
  11160. OperationProgress->Cancel = csCancel; // continue on next case
  11161. // FALLTHROUGH
  11162. case qaNo:
  11163. CanProceed = false;
  11164. break;
  11165. default:
  11166. break;
  11167. }
  11168. }
  11169. else
  11170. {
  11171. __int64 Size;
  11172. __int64 MTime;
  11173. TOverwriteFileParams FileParams;
  11174. FTerminal->OpenLocalFile(FileName, GENERIC_READ,
  11175. NULL, NULL, NULL, &MTime, NULL,
  11176. &Size);
  11177. FileParams.SourceSize = Size;
  11178. FileParams.SourceTimestamp = UnixToDateTime(MTime,
  11179. FTerminal->SessionData->DSTMode);
  11180. FileParams.DestSize = File->Size;
  11181. FileParams.DestTimestamp = File->Modification;
  11182. TOverwriteMode OverwriteMode = omOverwrite;
  11183. bool AutoResume = false;
  11184. ConfirmOverwrite(FileNameOnly, OverwriteMode, OperationProgress,
  11185. &FileParams, CopyParam, Params, AutoResume, Answer);
  11186. switch (Answer)
  11187. {
  11188. case qaYes:
  11189. CanProceed = true;
  11190. break;
  11191. case qaCancel:
  11192. OperationProgress->Cancel = csCancel; // continue on next case
  11193. // FALLTHROUGH
  11194. case qaNo:
  11195. CanProceed = false;
  11196. break;
  11197. default:
  11198. break;
  11199. }
  11200. }
  11201. }
  11202. else
  11203. {
  11204. CanProceed = true;
  11205. }
  11206. }
  11207. else
  11208. {
  11209. CanProceed = true;
  11210. }
  11211. if (CanProceed)
  11212. {
  11213. Action.FileName(ExpandUNCFileName(FileName));
  11214. OperationProgress->SetFile(FileName, false);
  11215. if (!FTerminal->AllowLocalFileTransfer(FileName, CopyParam))
  11216. {
  11217. FTerminal->LogEvent(FORMAT(L"File \"%s\" excluded from transfer", (FileName.c_str())));
  11218. THROW_SKIP_FILE_NULL;
  11219. }
  11220. __int64 Size;
  11221. int Attrs;
  11222. FTerminal->OpenLocalFile(FileName, GENERIC_READ, &Attrs,
  11223. NULL, NULL, NULL, NULL, &Size);
  11224. OperationProgress->SetFileInProgress();
  11225. bool Dir = FLAGSET(Attrs, faDirectory);
  11226. if (Dir)
  11227. {
  11228. Action.Cancel();
  11229. WebDAVDirectorySource(IncludeTrailingBackslash(FileName), TargetDir,
  11230. Attrs, CopyParam, Params, OperationProgress, Flags);
  11231. }
  11232. else
  11233. {
  11234. UnicodeString DestFileName = CopyParam->ChangeFileName(ExtractFileName(FileName, false),
  11235. osLocal, FLAGSET(Flags, tfFirstLevel));
  11236. FTerminal->LogEvent(FORMAT(L"Copying \"%s\" to remote directory started.", (FileName.c_str())));
  11237. OperationProgress->SetLocalSize(Size);
  11238. // Suppose same data size to transfer as to read
  11239. // (not true with ASCII transfer)
  11240. OperationProgress->SetTransferSize(OperationProgress->LocalSize);
  11241. OperationProgress->TransferingFile = false;
  11242. // Will we use ASCII of BINARY file transfer?
  11243. TFileMasks::TParams MaskParams;
  11244. MaskParams.Size = Size;
  11245. ResetFileTransfer();
  11246. TFileTransferData UserData;
  11247. {
  11248. unsigned int TransferType = 2;
  11249. // ignore file list
  11250. TWebDAVFileListHelper Helper(this, NULL, true);
  11251. FFileTransferCPSLimit = OperationProgress->CPSLimit;
  11252. // not used for uploads anyway
  11253. FFileTransferPreserveTime = CopyParam->PreserveTime;
  11254. // not used for uploads, but we get new name (if any) back in this field
  11255. UserData.FileName = DestFileName;
  11256. UserData.Params = Params;
  11257. UserData.AutoResume = FLAGSET(Flags, tfAutoResume);
  11258. UserData.CopyParam = CopyParam;
  11259. FileTransfer(FileName, FileName, DestFileName,
  11260. TargetDir, false, Size, TransferType, UserData, OperationProgress);
  11261. }
  11262. UnicodeString DestFullName = TargetDir + UserData.FileName;
  11263. // only now, we know the final destination
  11264. Action.Destination(DestFullName);
  11265. }
  11266. // TODO : Delete also read-only files.
  11267. if (FLAGSET(Params, cpDelete))
  11268. {
  11269. if (!Dir)
  11270. {
  11271. FILE_OPERATION_LOOP (FMTLOAD(DELETE_LOCAL_FILE_ERROR, (FileName.c_str())),
  11272. THROWOSIFFALSE(::DeleteFile(FileName.c_str()));
  11273. )
  11274. }
  11275. }
  11276. else if (CopyParam->ClearArchive && FLAGSET(Attrs, faArchive))
  11277. {
  11278. FILE_OPERATION_LOOP (FMTLOAD(CANT_SET_ATTRS, (FileName.c_str())),
  11279. THROWOSIFFALSE(FileSetAttr(FileName, Attrs & ~faArchive) == 0);
  11280. )
  11281. }
  11282. }
  11283. }
  11284. //---------------------------------------------------------------------------
  11285. void __fastcall TWebDAVFileSystem::WebDAVDirectorySource(const UnicodeString DirectoryName,
  11286. const UnicodeString TargetDir, int Attrs, const TCopyParamType * CopyParam,
  11287. int Params, TFileOperationProgressType * OperationProgress, unsigned int Flags)
  11288. {
  11289. UnicodeString DestDirectoryName = CopyParam->ChangeFileName(
  11290. ExtractFileName(ExcludeTrailingBackslash(DirectoryName), false), osLocal,
  11291. FLAGSET(Flags, tfFirstLevel));
  11292. UnicodeString DestFullName = UnixIncludeTrailingBackslash(TargetDir + DestDirectoryName);
  11293. // create DestFullName if it does not exist
  11294. int IsDir = 0;
  11295. bool Exists = WebDAVCheckExisting(DestFullName.c_str(), IsDir);
  11296. if (!Exists)
  11297. {
  11298. CreateDirectory(DestFullName);
  11299. }
  11300. OperationProgress->SetFile(DirectoryName);
  11301. WIN32_FIND_DATA SearchRec;
  11302. bool FindOK = false;
  11303. HANDLE findHandle = 0;
  11304. FILE_OPERATION_LOOP (FMTLOAD(LIST_DIR_ERROR, (DirectoryName.c_str())),
  11305. UnicodeString path = DirectoryName + L"*.*";
  11306. findHandle = FindFirstFile(path.c_str(), &SearchRec);
  11307. FindOK = (findHandle != 0);
  11308. if (!FindOK)
  11309. {
  11310. FindCheck(GetLastError());
  11311. }
  11312. );
  11313. bool CreateDir = true;
  11314. try
  11315. {
  11316. while (FindOK && !OperationProgress->Cancel)
  11317. {
  11318. UnicodeString FileName = DirectoryName + SearchRec.cFileName;
  11319. try
  11320. {
  11321. if ((wcscmp(SearchRec.cFileName, THISDIRECTORY) != 0) && (wcscmp(SearchRec.cFileName, PARENTDIRECTORY) != 0))
  11322. {
  11323. WebDAVSourceRobust(FileName, DestFullName, CopyParam, Params, OperationProgress,
  11324. Flags & ~(tfFirstLevel | tfAutoResume));
  11325. // if any file got uploaded (i.e. there were any file in the
  11326. // directory and at least one was not skipped),
  11327. // do not try to create the directory,
  11328. // as it should be already created by FZAPI during upload
  11329. CreateDir = false;
  11330. }
  11331. }
  11332. catch (EScpSkipFile & E)
  11333. {
  11334. // If ESkipFile occurs, just log it and continue with next file
  11335. SUSPEND_OPERATION (
  11336. // here a message to user was displayed, which was not appropriate
  11337. // when user refused to overwrite the file in subdirectory.
  11338. // hopefully it won't be missing in other situations.
  11339. if (!FTerminal->HandleException(&E))
  11340. {
  11341. throw;
  11342. }
  11343. );
  11344. }
  11345. FILE_OPERATION_LOOP (FMTLOAD(LIST_DIR_ERROR, (DirectoryName.c_str())),
  11346. FindOK = (::FindNextFile(findHandle, &SearchRec) != 0);
  11347. if (!FindOK)
  11348. {
  11349. FindCheck(GetLastError());
  11350. }
  11351. );
  11352. }
  11353. }
  11354. __finally
  11355. {
  11356. ::FindClose(findHandle);
  11357. }
  11358. if (CreateDir)
  11359. {
  11360. TRemoteProperties Properties;
  11361. if (CopyParam->PreserveRights)
  11362. {
  11363. Properties.Valid = TValidProperties() << vpRights;
  11364. Properties.Rights = CopyParam->RemoteFileRights(Attrs);
  11365. }
  11366. try
  11367. {
  11368. FTerminal->SetExceptionOnFail(true);
  11369. try
  11370. {
  11371. FTerminal->CreateDirectory(DestFullName, &Properties);
  11372. }
  11373. __finally
  11374. {
  11375. FTerminal->SetExceptionOnFail(false);
  11376. }
  11377. }
  11378. catch (...)
  11379. {
  11380. TRemoteFile * File = NULL;
  11381. // ignore non-fatal error when the directory already exists
  11382. UnicodeString fn = UnixExcludeTrailingBackslash(DestFullName);
  11383. if (fn.IsEmpty())
  11384. {
  11385. fn = L"/";
  11386. }
  11387. bool Rethrow =
  11388. !FTerminal->GetActive() ||
  11389. !FTerminal->FileExists(fn, &File) ||
  11390. (File && !File->IsDirectory);
  11391. delete File;
  11392. if (Rethrow)
  11393. {
  11394. throw;
  11395. }
  11396. }
  11397. }
  11398. // TODO : Delete also read-only directories.
  11399. // TODO : Show error message on failure.
  11400. if (!OperationProgress->Cancel)
  11401. {
  11402. if (FLAGSET(Params, cpDelete))
  11403. {
  11404. RemoveDir(DirectoryName);
  11405. }
  11406. else if (CopyParam->ClearArchive && FLAGSET(Attrs, faArchive))
  11407. {
  11408. FILE_OPERATION_LOOP (FMTLOAD(CANT_SET_ATTRS, (DirectoryName.c_str())),
  11409. THROWOSIFFALSE(FileSetAttr(DirectoryName, Attrs & ~faArchive) == 0);
  11410. )
  11411. }
  11412. }
  11413. }
  11414. //---------------------------------------------------------------------------
  11415. void __fastcall TWebDAVFileSystem::CopyToLocal(TStrings * FilesToCopy,
  11416. const UnicodeString TargetDir, const TCopyParamType * CopyParam,
  11417. int Params, TFileOperationProgressType * OperationProgress,
  11418. TOnceDoneOperation & OnceDoneOperation)
  11419. {
  11420. Params &= ~cpAppend;
  11421. UnicodeString FullTargetDir = ::IncludeTrailingBackslash(TargetDir);
  11422. int Index = 0;
  11423. while (Index < FilesToCopy->Count && !OperationProgress->Cancel)
  11424. {
  11425. UnicodeString FileName = FilesToCopy->Strings[Index];
  11426. const TRemoteFile * File = dynamic_cast<const TRemoteFile *>(FilesToCopy->Objects[Index]);
  11427. bool Success = false;
  11428. FTerminal->SetExceptionOnFail(true);
  11429. try
  11430. {
  11431. try
  11432. {
  11433. SinkRobust(AbsolutePath(FileName, false), File, FullTargetDir, CopyParam, Params,
  11434. OperationProgress, tfFirstLevel);
  11435. Success = true;
  11436. }
  11437. catch (EScpSkipFile & E)
  11438. {
  11439. SUSPEND_OPERATION (
  11440. if (!FTerminal->HandleException(&E))
  11441. {
  11442. throw;
  11443. }
  11444. );
  11445. }
  11446. }
  11447. __finally
  11448. {
  11449. OperationProgress->Finish(FileName, Success, OnceDoneOperation);
  11450. FTerminal->SetExceptionOnFail(false);
  11451. }
  11452. Index++;
  11453. }
  11454. }
  11455. //---------------------------------------------------------------------------
  11456. void __fastcall TWebDAVFileSystem::SinkRobust(const UnicodeString FileName,
  11457. const TRemoteFile * File, const UnicodeString TargetDir,
  11458. const TCopyParamType * CopyParam, int Params,
  11459. TFileOperationProgressType * OperationProgress, unsigned int Flags)
  11460. {
  11461. // the same in TSFTPFileSystem
  11462. bool Retry;
  11463. TDownloadSessionAction Action(FTerminal->ActionLog);
  11464. do
  11465. {
  11466. Retry = false;
  11467. try
  11468. {
  11469. Sink(FileName, File, TargetDir, CopyParam, Params, OperationProgress,
  11470. Flags, Action);
  11471. }
  11472. catch (Exception & E)
  11473. {
  11474. Retry = true;
  11475. if (FTerminal->GetActive() ||
  11476. !FTerminal->QueryReopen(&E, ropNoReadDirectory, OperationProgress))
  11477. {
  11478. FTerminal->RollbackAction(Action, OperationProgress, &E);
  11479. throw;
  11480. }
  11481. }
  11482. if (Retry)
  11483. {
  11484. OperationProgress->RollbackTransfer();
  11485. Action.Restart();
  11486. assert(File != NULL);
  11487. if (!File->IsDirectory)
  11488. {
  11489. // prevent overwrite confirmations
  11490. Params |= cpNoConfirmation;
  11491. Flags |= tfAutoResume;
  11492. }
  11493. }
  11494. }
  11495. while (Retry);
  11496. }
  11497. //---------------------------------------------------------------------------
  11498. void __fastcall TWebDAVFileSystem::Sink(const UnicodeString FileName,
  11499. const TRemoteFile * File, const UnicodeString TargetDir,
  11500. const TCopyParamType * CopyParam, int Params,
  11501. TFileOperationProgressType * OperationProgress, unsigned int Flags,
  11502. TDownloadSessionAction & Action)
  11503. {
  11504. UnicodeString FileNameOnly = UnixExtractFileName(FileName);
  11505. Action.FileName(FileName);
  11506. assert(File);
  11507. TFileMasks::TParams MaskParams;
  11508. MaskParams.Size = File->Size;
  11509. if (!CopyParam->AllowTransfer(FileName, osRemote, File->IsDirectory, MaskParams))
  11510. {
  11511. FTerminal->LogEvent(FORMAT(L"File \"%s\" excluded from transfer", (FileName.c_str())));
  11512. THROW_SKIP_FILE_NULL;
  11513. }
  11514. FTerminal->LogEvent(FORMAT(L"File: \"%s\"", (FileName.c_str())));
  11515. OperationProgress->SetFile(FileNameOnly);
  11516. UnicodeString DestFileName = CopyParam->ChangeFileName(FileNameOnly,
  11517. osRemote, FLAGSET(Flags, tfFirstLevel));
  11518. UnicodeString DestFullName = TargetDir + DestFileName;
  11519. if (File->IsDirectory)
  11520. {
  11521. bool CanProceed = true;
  11522. if (::DirectoryExists(DestFullName))
  11523. {
  11524. unsigned int Answer = 0;
  11525. UnicodeString Message = FMTLOAD(DIRECTORY_OVERWRITE, (FileNameOnly.c_str()));
  11526. TQueryParams QueryParams(qpNeverAskAgainCheck);
  11527. SUSPEND_OPERATION (
  11528. Answer = FTerminal->ConfirmFileOverwrite(
  11529. FileNameOnly /*not used*/, NULL,
  11530. qaYes | qaNo | qaCancel | qaYesToAll | qaNoToAll,
  11531. &QueryParams, osRemote, CopyParam, Params, OperationProgress, Message);
  11532. );
  11533. switch (Answer)
  11534. {
  11535. case qaCancel:
  11536. OperationProgress->Cancel = csCancel; // continue on next case
  11537. // FALLTHROUGH
  11538. case qaNo:
  11539. CanProceed = false;
  11540. default:
  11541. break;
  11542. }
  11543. }
  11544. if (CanProceed)
  11545. {
  11546. Action.Cancel();
  11547. if (!File->IsSymLink)
  11548. {
  11549. FILE_OPERATION_LOOP (FMTLOAD(NOT_DIRECTORY_ERROR, (DestFullName.c_str())),
  11550. int Attrs = FileGetAttr(DestFullName);
  11551. if (FLAGCLEAR(Attrs, faDirectory)) { EXCEPTION; }
  11552. );
  11553. FILE_OPERATION_LOOP (FMTLOAD(CREATE_DIR_ERROR, (DestFullName.c_str())),
  11554. if (!ForceDirectories(DestFullName)) { RaiseLastOSError(); }
  11555. );
  11556. TSinkFileParams SinkFileParams;
  11557. SinkFileParams.TargetDir = ::IncludeTrailingBackslash(DestFullName);
  11558. SinkFileParams.CopyParam = CopyParam;
  11559. SinkFileParams.Params = Params;
  11560. SinkFileParams.OperationProgress = OperationProgress;
  11561. SinkFileParams.Skipped = false;
  11562. SinkFileParams.Flags = Flags & ~(tfFirstLevel | tfAutoResume);
  11563. FTerminal->ProcessDirectory(FileName, SinkFile, &SinkFileParams);
  11564. // Do not delete directory if some of its files were skip.
  11565. // Throw "skip file" for the directory to avoid attempt to deletion
  11566. // of any parent directory
  11567. if (FLAGSET(Params, cpDelete) && SinkFileParams.Skipped)
  11568. {
  11569. THROW_SKIP_FILE_NULL;
  11570. }
  11571. }
  11572. else
  11573. {
  11574. // file is symlink to directory, currently do nothing, but it should be
  11575. // reported to user
  11576. }
  11577. }
  11578. }
  11579. else
  11580. {
  11581. FTerminal->LogEvent(FORMAT(L"Copying \"%s\" to local directory started.", (FileName.c_str())));
  11582. bool CanProceed = true;
  11583. if (FileExists(DestFullName))
  11584. {
  11585. __int64 Size;
  11586. __int64 MTime;
  11587. FTerminal->OpenLocalFile(DestFullName, GENERIC_READ, NULL,
  11588. NULL, NULL, &MTime, NULL, &Size);
  11589. TOverwriteFileParams FileParams;
  11590. FileParams.SourceSize = File->Size;
  11591. FileParams.SourceTimestamp = File->Modification;
  11592. FileParams.DestSize = Size;
  11593. FileParams.DestTimestamp = UnixToDateTime(MTime,
  11594. FTerminal->SessionData->DSTMode);
  11595. unsigned int Answer = 0;
  11596. TOverwriteMode OverwriteMode = omOverwrite;
  11597. bool AutoResume = false;
  11598. ConfirmOverwrite(DestFullName, OverwriteMode, OperationProgress,
  11599. &FileParams, CopyParam, Params, AutoResume, Answer);
  11600. switch (Answer)
  11601. {
  11602. case qaCancel:
  11603. OperationProgress->Cancel = csCancel; // continue on next case
  11604. // FALLTHROUGH
  11605. case qaNo:
  11606. CanProceed = false;
  11607. default:
  11608. break;
  11609. }
  11610. }
  11611. if (CanProceed)
  11612. {
  11613. // Suppose same data size to transfer as to write
  11614. OperationProgress->SetTransferSize(File->Size);
  11615. OperationProgress->SetLocalSize(OperationProgress->TransferSize);
  11616. int Attrs = -1;
  11617. FILE_OPERATION_LOOP (FMTLOAD(NOT_FILE_ERROR, (DestFullName.c_str())),
  11618. Attrs = FileGetAttr(DestFullName);
  11619. if ((Attrs >= 0) && FLAGSET(Attrs, faDirectory)) { EXCEPTION; }
  11620. );
  11621. OperationProgress->TransferingFile = false; // not set with FTP protocol
  11622. ResetFileTransfer();
  11623. TFileTransferData UserData;
  11624. UnicodeString FilePath = ::UnixExtractFilePath(FileName);
  11625. if (FilePath.IsEmpty())
  11626. {
  11627. FilePath = L"/";
  11628. }
  11629. {
  11630. unsigned int TransferType = 2;
  11631. // ignore file list
  11632. TWebDAVFileListHelper Helper(this, NULL, true);
  11633. FFileTransferCPSLimit = OperationProgress->CPSLimit;
  11634. FFileTransferPreserveTime = CopyParam->PreserveTime;
  11635. UserData.FileName = DestFileName;
  11636. UserData.Params = Params;
  11637. UserData.AutoResume = FLAGSET(Flags, tfAutoResume);
  11638. UserData.CopyParam = CopyParam;
  11639. FileTransfer(FileName, DestFullName, FileNameOnly,
  11640. FilePath, true, File->Size, TransferType, UserData, OperationProgress);
  11641. }
  11642. // in case dest filename is changed from overwrite dialog
  11643. if (DestFileName != UserData.FileName)
  11644. {
  11645. DestFullName = TargetDir + UserData.FileName;
  11646. Attrs = FileGetAttr(DestFullName);
  11647. }
  11648. Action.Destination(ExpandUNCFileName(DestFullName));
  11649. if (Attrs == -1)
  11650. {
  11651. Attrs = faArchive;
  11652. }
  11653. int NewAttrs = CopyParam->LocalFileAttrs(*File->Rights);
  11654. if ((NewAttrs & Attrs) != NewAttrs)
  11655. {
  11656. FILE_OPERATION_LOOP (FMTLOAD(CANT_SET_ATTRS, (DestFullName.c_str())),
  11657. THROWOSIFFALSE(FileSetAttr(DestFullName, Attrs | NewAttrs) == 0);
  11658. );
  11659. }
  11660. // set time
  11661. {
  11662. FILE_OPERATION_LOOP (FMTLOAD(CANT_SET_ATTRS, (DestFullName.c_str())),
  11663. HANDLE Handle;
  11664. Handle = CreateFile(DestFullName.c_str(), GENERIC_WRITE,
  11665. FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
  11666. FILETIME WrTime = DateTimeToFileTime(File->Modification,
  11667. FTerminal->SessionData->DSTMode);
  11668. bool Result = SetFileTime(Handle, &WrTime, &WrTime, &WrTime) > 0;
  11669. CloseHandle(Handle);
  11670. if (!Result)
  11671. {
  11672. Abort();
  11673. }
  11674. );
  11675. }
  11676. }
  11677. }
  11678. if (FLAGSET(Params, cpDelete))
  11679. {
  11680. // If file is directory, do not delete it recursively, because it should be
  11681. // empty already. If not, it should not be deleted (some files were
  11682. // skipped or some new files were copied to it, while we were downloading)
  11683. int Params = dfNoRecursive;
  11684. FTerminal->DeleteFile(FileName, File, &Params);
  11685. }
  11686. }
  11687. //---------------------------------------------------------------------------
  11688. void __fastcall TWebDAVFileSystem::SinkFile(const UnicodeString FileName,
  11689. const TRemoteFile * File, void * Param)
  11690. {
  11691. TSinkFileParams * Params = static_cast<TSinkFileParams *>(Param);
  11692. assert(Params->OperationProgress);
  11693. try
  11694. {
  11695. SinkRobust(FileName, File, Params->TargetDir, Params->CopyParam,
  11696. Params->Params, Params->OperationProgress, Params->Flags);
  11697. }
  11698. catch (EScpSkipFile & E)
  11699. {
  11700. TFileOperationProgressType * OperationProgress = Params->OperationProgress;
  11701. Params->Skipped = true;
  11702. SUSPEND_OPERATION (
  11703. if (!FTerminal->HandleException(&E))
  11704. {
  11705. throw;
  11706. }
  11707. );
  11708. if (OperationProgress->Cancel)
  11709. {
  11710. Abort();
  11711. }
  11712. }
  11713. }
  11714. //---------------------------------------------------------------------------
  11715. bool __fastcall TWebDAVFileSystem::HandleListData(const wchar_t * Path,
  11716. const TListDataEntry * Entries, unsigned int Count)
  11717. {
  11718. if (!FActive)
  11719. {
  11720. return false;
  11721. }
  11722. else if (FIgnoreFileList)
  11723. {
  11724. // directory listing provided implicitly by FZAPI during certain operations is ignored
  11725. assert(FFileList == NULL);
  11726. return false;
  11727. }
  11728. else
  11729. {
  11730. assert(FFileList != NULL);
  11731. // this can actually fail in real life,
  11732. // when connected to server with case insensitive paths
  11733. assert(UnixComparePaths(AbsolutePath(FFileList->Directory, false), Path));
  11734. USEDPARAM(Path);
  11735. for (size_t Index = 0; Index < Count; Index++)
  11736. {
  11737. const TListDataEntry * Entry = &Entries[Index];
  11738. TRemoteFile * File = new TRemoteFile();
  11739. try
  11740. {
  11741. File->Terminal = FTerminal;
  11742. File->FileName = UnicodeString(Entry->Name);
  11743. if (wcslen(Entry->Permissions) >= 10)
  11744. {
  11745. try
  11746. {
  11747. File->Rights->Text = Entry->Permissions + 1;
  11748. }
  11749. catch (...)
  11750. {
  11751. // ignore permissions errors with WebDAV
  11752. }
  11753. }
  11754. // FIXME
  11755. UnicodeString own = Entry->OwnerGroup;
  11756. const wchar_t * Space = wcschr(own.c_str(), ' ');
  11757. if (Space != NULL)
  11758. {
  11759. File->Owner.Name = UnicodeString(own.c_str(), Space - own.c_str());
  11760. File->Group.Name = Space + 1;
  11761. }
  11762. else
  11763. {
  11764. File->Owner.Name = Entry->OwnerGroup;
  11765. }
  11766. File->Size = Entry->Size;
  11767. if (Entry->Link)
  11768. {
  11769. File->Type = FILETYPE_SYMLINK;
  11770. }
  11771. else if (Entry->Dir)
  11772. {
  11773. File->Type = FILETYPE_DIRECTORY;
  11774. }
  11775. else
  11776. {
  11777. File->Type = L'-';
  11778. }
  11779. // ModificationFmt must be set after Modification
  11780. if (Entry->Time.HasDate)
  11781. {
  11782. // should be the same as ConvertRemoteTimestamp
  11783. TDateTime Modification =
  11784. EncodeDateVerbose(static_cast<unsigned short>(Entry->Time.Year), static_cast<unsigned short>(Entry->Time.Month),
  11785. static_cast<unsigned short>(Entry->Time.Day));
  11786. if (Entry->Time.HasTime)
  11787. {
  11788. unsigned short seconds = 0;
  11789. if (Entry->Time.HasSeconds)
  11790. seconds = static_cast<unsigned short>(Entry->Time.Second);
  11791. File->Modification = Modification +
  11792. EncodeTimeVerbose(static_cast<unsigned short>(Entry->Time.Hour),
  11793. static_cast<unsigned short>(Entry->Time.Minute),
  11794. seconds, 0);
  11795. // not exact as we got year as well, but it is most probably
  11796. // guessed by FZAPI anyway
  11797. File->ModificationFmt = mfMDHM;
  11798. }
  11799. else
  11800. {
  11801. File->Modification = Modification;
  11802. File->ModificationFmt = mfMDY;
  11803. }
  11804. }
  11805. else
  11806. {
  11807. // We estimate date to be today, if we have at least time
  11808. File->Modification = TDateTime(0.0);
  11809. File->ModificationFmt = mfNone;
  11810. }
  11811. File->LastAccess = File->Modification;
  11812. File->LinkTo = Entry->LinkTarget;
  11813. File->Complete();
  11814. }
  11815. catch (Exception & E)
  11816. {
  11817. delete File;
  11818. UnicodeString EntryData =
  11819. FORMAT(L"%s/%s/%s/%lld/%d/%d/%d/%d/%d/%d/%d/%d/%d",
  11820. (Entry->Name,
  11821. Entry->Permissions,
  11822. Entry->OwnerGroup,
  11823. Entry->Size,
  11824. int(Entry->Dir), int(Entry->Link), Entry->Time.Year, Entry->Time.Month, Entry->Time.Day,
  11825. Entry->Time.Hour, Entry->Time.Minute, int(Entry->Time.HasTime), int(Entry->Time.HasDate)));
  11826. throw ETerminal(&E, FMTLOAD(LIST_LINE_ERROR, (EntryData.c_str())), HELP_LIST_LINE_ERROR);
  11827. }
  11828. FFileList->AddFile(File);
  11829. }
  11830. return true;
  11831. }
  11832. }
  11833. //---------------------------------------------------------------------------
  11834. void __fastcall TWebDAVFileSystem::ResetFileTransfer()
  11835. {
  11836. FFileTransferAbort = ftaNone;
  11837. FFileTransferCancelled = false;
  11838. FFileTransferResumed = 0;
  11839. webdav::cancelled = FALSE;
  11840. }
  11841. //---------------------------------------------------------------------------
  11842. void __fastcall TWebDAVFileSystem::ReadDirectoryProgress(__int64 Bytes)
  11843. {
  11844. // with WebDAV we do not know exactly how many entries we have received,
  11845. // instead we know number of bytes received only.
  11846. // so we report approximation based on average size of entry.
  11847. size_t Progress = static_cast<size_t>(Bytes / 80);
  11848. if (Progress - FLastReadDirectoryProgress >= 10)
  11849. {
  11850. bool Cancel = false;
  11851. FLastReadDirectoryProgress = Progress;
  11852. FTerminal->DoReadDirectoryProgress(Progress, Cancel);
  11853. if (Cancel)
  11854. {
  11855. FTerminal->DoReadDirectoryProgress(-2, Cancel);
  11856. }
  11857. }
  11858. }
  11859. //---------------------------------------------------------------------------
  11860. void __fastcall TWebDAVFileSystem::DoFileTransferProgress(__int64 TransferSize,
  11861. __int64 Bytes)
  11862. {
  11863. TFileOperationProgressType * OperationProgress = FTerminal->OperationProgress;
  11864. if (!OperationProgress) return;
  11865. OperationProgress->SetTransferSize(TransferSize);
  11866. if (FFileTransferResumed > 0)
  11867. {
  11868. OperationProgress->AddResumed(FFileTransferResumed);
  11869. FFileTransferResumed = 0;
  11870. }
  11871. __int64 Diff = Bytes - OperationProgress->TransferedSize;
  11872. if (Diff >= 0)
  11873. {
  11874. OperationProgress->AddTransfered(Diff);
  11875. }
  11876. if (OperationProgress->Cancel == csCancel)
  11877. {
  11878. FFileTransferCancelled = true;
  11879. FFileTransferAbort = ftaCancel;
  11880. }
  11881. if (FFileTransferCPSLimit != OperationProgress->CPSLimit)
  11882. {
  11883. FFileTransferCPSLimit = OperationProgress->CPSLimit;
  11884. }
  11885. }
  11886. //---------------------------------------------------------------------------
  11887. void __fastcall TWebDAVFileSystem::FileTransferProgress(__int64 TransferSize,
  11888. __int64 Bytes)
  11889. {
  11890. TGuard Guard(FTransferStatusCriticalSection);
  11891. DoFileTransferProgress(TransferSize, Bytes);
  11892. }
  11893. //---------------------------------------------------------------------------
  11894. void __fastcall TWebDAVFileSystem::FileTransfer(const UnicodeString FileName,
  11895. const UnicodeString LocalFile, const UnicodeString RemoteFile,
  11896. const UnicodeString RemotePath, bool Get, __int64 Size, int Type,
  11897. TFileTransferData & UserData, TFileOperationProgressType * OperationProgress)
  11898. {
  11899. FCurrentOperationProgress = OperationProgress;
  11900. FILE_OPERATION_LOOP (FMTLOAD(TRANSFER_ERROR, (FileName.c_str())),
  11901. UnicodeString FullRemoteFileName = RemotePath + RemoteFile;
  11902. bool Result = false;
  11903. if (Get)
  11904. {
  11905. HANDLE LocalFileHandle = 0;
  11906. FTerminal->CreateLocalFile(LocalFile,
  11907. OperationProgress, &LocalFileHandle, true);
  11908. Result = WebDAVGetFile(FullRemoteFileName.c_str(), &LocalFileHandle);
  11909. if (!Result)
  11910. {
  11911. ::CloseHandle(LocalFileHandle);
  11912. }
  11913. }
  11914. else
  11915. {
  11916. Result = WebDAVPutFile(FullRemoteFileName.c_str(), LocalFile.c_str(), Size);
  11917. }
  11918. if (!Result)
  11919. EXCEPTION;
  11920. );
  11921. switch (FFileTransferAbort)
  11922. {
  11923. case ftaSkip:
  11924. THROW_SKIP_FILE(NULL, L"");
  11925. case ftaCancel:
  11926. Abort();
  11927. break;
  11928. }
  11929. if (!FFileTransferCancelled)
  11930. {
  11931. // show completion of transfer
  11932. // call non-guarded variant to avoid deadlock with keepalives
  11933. // (we are not waiting for reply anymore so keepalives are free to proceed)
  11934. DoFileTransferProgress(OperationProgress->TransferSize, OperationProgress->TransferSize);
  11935. }
  11936. }
  11937. bool TWebDAVFileSystem::SendPropFindRequest(const wchar_t * path, int & responseCode)
  11938. {
  11939. assert(path);
  11940. assert(FSession);
  11941. apr_pool_t * pool = webdav_pool_create(webdav_pool);
  11942. webdav::error_t err = 0;
  11943. const char * remote_path = NULL;
  11944. err = webdav::path_cstring_to_utf8(&remote_path, AnsiString(path).c_str(), pool);
  11945. if (err) return false;
  11946. err = webdav::client_send_propfind_request(
  11947. FSession,
  11948. remote_path,
  11949. &responseCode,
  11950. pool
  11951. );
  11952. webdav_pool_destroy(pool);
  11953. return err == WEBDAV_NO_ERROR;
  11954. }
  11955. bool TWebDAVFileSystem::WebDAVCheckExisting(const wchar_t * path, int & is_dir)
  11956. {
  11957. assert(path);
  11958. is_dir = 0;
  11959. assert(FSession);
  11960. apr_pool_t * pool = webdav_pool_create(webdav_pool);
  11961. webdav::error_t err = 0;
  11962. webdav::node_kind_t kind = webdav::node_none;
  11963. const char * remote_path = NULL;
  11964. err = webdav::path_cstring_to_utf8(&remote_path, AnsiString(path).c_str(), pool);
  11965. if (err) return false;
  11966. err = webdav::client_check_path(
  11967. FSession,
  11968. remote_path,
  11969. &kind,
  11970. pool
  11971. );
  11972. if (kind != webdav::node_none)
  11973. is_dir = kind == webdav::node_dir;
  11974. webdav_pool_destroy(pool);
  11975. return (err == WEBDAV_NO_ERROR) && (kind != webdav::node_none);
  11976. }
  11977. bool TWebDAVFileSystem::WebDAVMakeDirectory(const wchar_t * path)
  11978. {
  11979. assert(path);
  11980. assert(FSession);
  11981. apr_pool_t * pool = webdav_pool_create(webdav_pool);
  11982. webdav::error_t err = 0;
  11983. const char * remote_path = NULL;
  11984. err = webdav::path_cstring_to_utf8(&remote_path, AnsiString(path).c_str(), pool);
  11985. if (err) return false;
  11986. err = webdav::client_make_directory(
  11987. FSession,
  11988. remote_path,
  11989. NULL,
  11990. pool
  11991. );
  11992. webdav_pool_destroy(pool);
  11993. return err == WEBDAV_NO_ERROR;
  11994. }
  11995. bool TWebDAVFileSystem::WebDAVGetList(const UnicodeString Directory)
  11996. {
  11997. webdav::listdataentry_vector_t Entries;
  11998. assert(FSession);
  11999. webdav::list_func_baton_t baton = {0};
  12000. baton.verbose = true;
  12001. baton.entries = &Entries;
  12002. baton.session = FSession;
  12003. baton.pool = webdav_pool_create(webdav_pool);
  12004. webdav::error_t err = 0;
  12005. const char * remote_path = NULL;
  12006. err = webdav::path_cstring_to_utf8(&remote_path, AnsiString(Directory).c_str(), baton.pool);
  12007. if (err) return false;
  12008. err = webdav::client_list2(
  12009. FSession,
  12010. remote_path,
  12011. webdav::depth_immediates,
  12012. WEBDAV_DIRENT_ALL,
  12013. webdav::list_func,
  12014. &baton,
  12015. baton.pool
  12016. );
  12017. TListDataEntry * pEntries = !Entries.empty() ? &Entries[0] : NULL;
  12018. HandleListData(Directory.c_str(), pEntries, Entries.size());
  12019. webdav_pool_destroy(baton.pool);
  12020. return err == WEBDAV_NO_ERROR;
  12021. }
  12022. bool TWebDAVFileSystem::WebDAVGetFile(const wchar_t * remotePath,
  12023. HANDLE * LocalFileHandle)
  12024. {
  12025. assert(remotePath && *remotePath);
  12026. assert(LocalFileHandle);
  12027. assert(FSession);
  12028. apr_pool_t * pool = webdav_pool_create(webdav_pool);
  12029. webdav::error_t err = 0;
  12030. const char * remote_path = NULL;
  12031. err = webdav::path_cstring_to_utf8(&remote_path, AnsiString(remotePath).c_str(), pool);
  12032. if (err) return false;
  12033. err = webdav::client_get_file(
  12034. FSession,
  12035. remote_path,
  12036. LocalFileHandle,
  12037. pool);
  12038. webdav_pool_destroy(pool);
  12039. return err == WEBDAV_NO_ERROR;
  12040. }
  12041. bool TWebDAVFileSystem::WebDAVPutFile(const wchar_t * remotePath, const wchar_t * localPath, const unsigned __int64 /*fileSize*/)
  12042. {
  12043. assert(remotePath && *remotePath);
  12044. assert(localPath && *localPath);
  12045. assert(FSession);
  12046. apr_pool_t * pool = webdav_pool_create(webdav_pool);
  12047. webdav::error_t err = 0;
  12048. const char * remote_path = NULL;
  12049. const char * local_path = NULL;
  12050. err = webdav::path_cstring_to_utf8(&remote_path, AnsiString(remotePath).c_str(), pool);
  12051. if (err) return false;
  12052. err = webdav::path_cstring_to_utf8(&local_path, AnsiString(localPath).c_str(), pool);
  12053. if (err) return false;
  12054. err = webdav::client_put_file(
  12055. FSession,
  12056. remote_path,
  12057. local_path,
  12058. pool
  12059. );
  12060. webdav_pool_destroy(pool);
  12061. return err == WEBDAV_NO_ERROR;
  12062. }
  12063. bool TWebDAVFileSystem::WebDAVRenameFile(const wchar_t * srcPath, const wchar_t * dstPath)
  12064. {
  12065. assert(srcPath && *srcPath);
  12066. assert(dstPath && *dstPath);
  12067. assert(FSession);
  12068. apr_pool_t * pool = webdav_pool_create(webdav_pool);
  12069. webdav::error_t err = 0;
  12070. const char * src_path = NULL;
  12071. const char * dst_path = NULL;
  12072. err = webdav::path_cstring_to_utf8(&src_path, AnsiString(srcPath).c_str(), pool);
  12073. if (err) return false;
  12074. err = webdav::path_cstring_to_utf8(&dst_path, AnsiString(dstPath).c_str(), pool);
  12075. if (err) return false;
  12076. err = webdav::client_move_file_or_directory(
  12077. FSession,
  12078. src_path,
  12079. dst_path,
  12080. NULL,
  12081. pool
  12082. );
  12083. webdav_pool_destroy(pool);
  12084. return err == WEBDAV_NO_ERROR;
  12085. }
  12086. bool TWebDAVFileSystem::WebDAVDeleteFile(const wchar_t * path)
  12087. {
  12088. assert(path);
  12089. assert(FSession);
  12090. apr_pool_t * pool = webdav_pool_create(webdav_pool);
  12091. webdav::error_t err = 0;
  12092. const char * remote_path = NULL;
  12093. err = webdav::path_cstring_to_utf8(&remote_path, AnsiString(path).c_str(), pool);
  12094. if (err) return false;
  12095. err = webdav::client_delete_file(
  12096. FSession,
  12097. remote_path,
  12098. NULL,
  12099. pool
  12100. );
  12101. webdav_pool_destroy(pool);
  12102. return err == WEBDAV_NO_ERROR;
  12103. }
  12104. webdav::error_t TWebDAVFileSystem::OpenURL(const UnicodeString & session_URL,
  12105. apr_pool_t * pool)
  12106. {
  12107. webdav::client_ctx_t * ctx = NULL;
  12108. WEBDAV_ERR(client_create_context(&ctx, pool));
  12109. const char * auth_username = NULL;
  12110. const char * auth_password = NULL;
  12111. WEBDAV_ERR(webdav::utf_cstring_to_utf8(&auth_username,
  12112. AnsiString(FTerminal->SessionData->UserNameExpanded).c_str(), pool));
  12113. WEBDAV_ERR(webdav::utf_cstring_to_utf8(&auth_password,
  12114. AnsiString(FTerminal->SessionData->Password).c_str(), pool));
  12115. webdav::auth_baton_t * ab = NULL;
  12116. webdav::auth_baton_create(&ab, pool);
  12117. webdav::auth_baton_init(ab,
  12118. FALSE, // non_interactive
  12119. auth_username,
  12120. auth_password,
  12121. FALSE, // no_auth_cache
  12122. TRUE, // trust_server_cert
  12123. this,
  12124. webdav::check_cancel, ab,
  12125. pool);
  12126. ctx->auth_baton = ab;
  12127. // Set up our cancellation support.
  12128. ctx->cancel_func = webdav::check_cancel;
  12129. ctx->cancel_baton = ab;
  12130. ctx->progress_func = webdav::progress_func;
  12131. ctx->progress_baton = ctx;
  12132. webdav::session_t * session_p = NULL;
  12133. const char * corrected_url = NULL;
  12134. AnsiString base_url = AnsiString(session_URL).c_str();
  12135. const char * base_url_encoded = webdav::path_uri_encode(base_url.c_str(), pool);
  12136. WEBDAV_ERR(webdav::client_open_session_internal(
  12137. &session_p,
  12138. &corrected_url,
  12139. base_url_encoded,
  12140. ctx,
  12141. pool));
  12142. const char * url = NULL;
  12143. if (corrected_url)
  12144. {
  12145. url = apr_pstrdup(pool, corrected_url);
  12146. }
  12147. else
  12148. {
  12149. url = apr_pstrdup(pool, base_url_encoded);
  12150. }
  12151. ne_uri * uri = NULL;
  12152. if (WEBDAV_NO_ERROR == webdav::parse_ne_uri(&uri, url, pool))
  12153. {
  12154. FCurrentDirectory = uri->path;
  12155. FHasTrailingSlash = (FCurrentDirectory.Length() > 0) && (FCurrentDirectory[FCurrentDirectory.Length()] == L'/');
  12156. }
  12157. FSession = session_p;
  12158. return WEBDAV_NO_ERROR;
  12159. }
  12160. //---------------------------------------------------------------------------
  12161. webdav::error_t TWebDAVFileSystem::GetServerSettings(
  12162. int * proxy_method,
  12163. const char ** proxy_host,
  12164. unsigned int * proxy_port,
  12165. const char ** proxy_username,
  12166. const char ** proxy_password,
  12167. int * timeout_seconds,
  12168. int * neon_debug,
  12169. const char ** neon_debug_file_name,
  12170. bool * compression,
  12171. const char ** pk11_provider,
  12172. const char ** ssl_authority_file,
  12173. apr_pool_t * pool)
  12174. {
  12175. // If we find nothing, default to nulls.
  12176. *proxy_method = 0;
  12177. *proxy_host = NULL;
  12178. *proxy_port = (unsigned int)-1;
  12179. *proxy_username = NULL;
  12180. *proxy_password = NULL;
  12181. *pk11_provider = NULL;
  12182. *ssl_authority_file = NULL;
  12183. TSessionData * Data = FTerminal->SessionData;
  12184. TConfiguration * Configuration = FTerminal->Configuration;
  12185. {
  12186. TProxyMethod ProxyMethod = Data->ProxyMethod;
  12187. *proxy_method = (int)ProxyMethod;
  12188. if (ProxyMethod != (TProxyMethod)::pmNone)
  12189. {
  12190. WEBDAV_ERR(webdav::path_cstring_to_utf8(proxy_host, AnsiString(Data->ProxyHost).c_str(), pool));
  12191. WEBDAV_ERR(webdav::path_cstring_to_utf8(proxy_username, AnsiString(Data->ProxyUsername).c_str(), pool));
  12192. WEBDAV_ERR(webdav::path_cstring_to_utf8(proxy_password, AnsiString(Data->ProxyPassword).c_str(), pool));
  12193. }
  12194. }
  12195. // Apply non-proxy-specific settings regardless of exceptions:
  12196. if (compression)
  12197. *compression = Data->Compression;
  12198. int l_debug = Configuration->ActualLogProtocol >= 1 ? 1 : 0;
  12199. *pk11_provider = "";
  12200. *ssl_authority_file = apr_pstrdup(pool, AnsiString(Data->PublicKeyFile).c_str());
  12201. {
  12202. int l_proxy_port = Data->ProxyPort;
  12203. if (l_proxy_port < 0)
  12204. {
  12205. return webdav::error_create(WEBDAV_ERR_ILLEGAL_URL, NULL,
  12206. "Invalid URL: negative proxy port number");
  12207. }
  12208. if (l_proxy_port > 65535)
  12209. {
  12210. return webdav::error_create(WEBDAV_ERR_ILLEGAL_URL, NULL,
  12211. "Invalid URL: proxy port number greater "
  12212. "than maximum TCP port number 65535");
  12213. }
  12214. *proxy_port = l_proxy_port;
  12215. }
  12216. {
  12217. int l_timeout = Data->Timeout;
  12218. if (l_timeout < 0)
  12219. return webdav::error_create(WEBDAV_ERR_BAD_CONFIG_VALUE, NULL,
  12220. "Invalid config: negative timeout value");
  12221. *timeout_seconds = l_timeout;
  12222. }
  12223. if (l_debug)
  12224. {
  12225. *neon_debug = l_debug;
  12226. if (Configuration->LogToFile)
  12227. {
  12228. WEBDAV_ERR(webdav::path_cstring_to_utf8(neon_debug_file_name,
  12229. AnsiString(GetExpandedLogFileName(
  12230. Configuration->LogFileName,
  12231. Data)).c_str(), pool));
  12232. }
  12233. else
  12234. {
  12235. *neon_debug_file_name = NULL;
  12236. }
  12237. }
  12238. else
  12239. {
  12240. *neon_debug = 0;
  12241. *neon_debug_file_name = NULL;
  12242. }
  12243. return WEBDAV_NO_ERROR;
  12244. }
  12245. webdav::error_t TWebDAVFileSystem::VerifyCertificate(
  12246. const char * Prompt, const char * fingerprint,
  12247. unsigned int & RequestResult)
  12248. {
  12249. RequestResult = 0;
  12250. TClipboardHandler ClipboardHandler;
  12251. ClipboardHandler.Text = fingerprint;
  12252. TQueryButtonAlias Aliases[1];
  12253. Aliases[0].Button = qaRetry;
  12254. Aliases[0].Alias = LoadStr(COPY_KEY_BUTTON);
  12255. Aliases[0].OnClick = &ClipboardHandler.Copy;
  12256. TQueryParams Params;
  12257. Params.HelpKeyword = HELP_VERIFY_CERTIFICATE;
  12258. Params.NoBatchAnswers = qaYes | qaRetry;
  12259. Params.Aliases = Aliases;
  12260. Params.AliasesCount = LENOF(Aliases);
  12261. unsigned int Answer = FTerminal->QueryUser(
  12262. FMTLOAD(VERIFY_CERT_PROMPT2, (UnicodeString(Prompt).c_str())),
  12263. NULL, qaYes | qaNo | qaCancel | qaRetry, &Params, qtWarning);
  12264. RequestResult = Answer;
  12265. switch (RequestResult)
  12266. {
  12267. case qaCancel:
  12268. FFileTransferCancelled = true;
  12269. FFileTransferAbort = ftaCancel;
  12270. break;
  12271. }
  12272. return WEBDAV_NO_ERROR;
  12273. }
  12274. webdav::error_t TWebDAVFileSystem::AskForClientCertificateFilename(
  12275. const char ** cert_file, unsigned int & RequestResult,
  12276. apr_pool_t * pool)
  12277. {
  12278. RequestResult = 0;
  12279. TSessionData * Data = FTerminal->SessionData;
  12280. UnicodeString FileName;
  12281. if (!FTerminal->PromptUser(Data, pkFileName, LoadStr(CERT_FILENAME_PROMPT_TITLE), L"",
  12282. LoadStr(CERT_FILENAME_PROMPT), true, 0, FileName))
  12283. {
  12284. FFileTransferCancelled = true;
  12285. FFileTransferAbort = ftaCancel;
  12286. return WEBDAV_ERR_CANCELLED;
  12287. }
  12288. WEBDAV_ERR(webdav::path_cstring_to_utf8(cert_file, AnsiString(FileName).c_str(), pool));
  12289. RequestResult = qaOK;
  12290. return WEBDAV_NO_ERROR;
  12291. }
  12292. webdav::error_t TWebDAVFileSystem::AskForUsername(
  12293. const char ** user_name, unsigned int & RequestResult,
  12294. apr_pool_t * pool)
  12295. {
  12296. RequestResult = 0;
  12297. TSessionData * Data = FTerminal->SessionData;
  12298. UnicodeString UserName = Data->UserNameExpanded;
  12299. if (!FTerminal->PromptUser(Data, pkUserName, LoadStr(USERNAME_TITLE), L"",
  12300. LoadStr(USERNAME_PROMPT2), true, 0, UserName))
  12301. {
  12302. FFileTransferCancelled = true;
  12303. FFileTransferAbort = ftaCancel;
  12304. return WEBDAV_ERR_CANCELLED;
  12305. }
  12306. WEBDAV_ERR(webdav::path_cstring_to_utf8(user_name, AnsiString(UserName).c_str(), pool));
  12307. RequestResult = qaOK;
  12308. return WEBDAV_NO_ERROR;
  12309. }
  12310. webdav::error_t TWebDAVFileSystem::AskForUserPassword(
  12311. const char ** password,
  12312. unsigned int & RequestResult,
  12313. apr_pool_t * pool)
  12314. {
  12315. RequestResult = 0;
  12316. TSessionData * Data = FTerminal->SessionData;
  12317. UnicodeString Password = Data->Password;
  12318. if (!FTerminal->PromptUser(Data, pkPassword, LoadStr(PASSWORD_TITLE), L"",
  12319. LoadStr(PASSWORD_PROMPT), false, 0, Password))
  12320. {
  12321. FFileTransferCancelled = true;
  12322. FFileTransferAbort = ftaCancel;
  12323. return WEBDAV_ERR_CANCELLED;
  12324. }
  12325. WEBDAV_ERR(webdav::path_cstring_to_utf8(password, AnsiString(Password).c_str(), pool));
  12326. RequestResult = qaOK;
  12327. return WEBDAV_NO_ERROR;
  12328. }
  12329. //------------------------------------------------------------------------------
  12330. webdav::error_t TWebDAVFileSystem::AskForPassphrase(
  12331. const char ** passphrase,
  12332. const char * realm,
  12333. unsigned int & RequestResult,
  12334. apr_pool_t * pool)
  12335. {
  12336. RequestResult = 0;
  12337. TSessionData * Data = FTerminal->SessionData;
  12338. UnicodeString Passphrase = Data->UserNameExpanded;
  12339. UnicodeString Prompt = FORMAT(LoadStr(PROMPT_KEY_PASSPHRASE), (UnicodeString(realm)));
  12340. if (!FTerminal->PromptUser(Data, pkPassphrase, LoadStr(PASSPHRASE_TITLE), L"",
  12341. Prompt, false, 0, Passphrase))
  12342. {
  12343. FFileTransferCancelled = true;
  12344. FFileTransferAbort = ftaCancel;
  12345. return WEBDAV_ERR_CANCELLED;
  12346. }
  12347. WEBDAV_ERR(webdav::path_cstring_to_utf8(passphrase, AnsiString(Passphrase).c_str(), pool));
  12348. RequestResult = qaOK;
  12349. return WEBDAV_NO_ERROR;
  12350. }
  12351. webdav::error_t TWebDAVFileSystem::SimplePrompt(
  12352. const char * prompt_text,
  12353. const char * prompt_string,
  12354. unsigned int & RequestResult)
  12355. {
  12356. RequestResult = 0;
  12357. TStrings * MoreMessages = new TStringList();
  12358. try
  12359. {
  12360. MoreMessages->Add(UnicodeString(prompt_string));
  12361. unsigned int Answer = FTerminal->QueryUser(
  12362. UnicodeString(prompt_text),
  12363. MoreMessages, qaYes | qaNo | qaCancel, NULL, qtConfirmation);
  12364. RequestResult = Answer;
  12365. }
  12366. __finally
  12367. {
  12368. delete MoreMessages;
  12369. }
  12370. return RequestResult == qaCancel ? WEBDAV_ERR_CANCELLED : WEBDAV_NO_ERROR;
  12371. }
  12372. webdav::error_t TWebDAVFileSystem::CreateStorage(
  12373. THierarchicalStorage *& Storage)
  12374. {
  12375. Storage =
  12376. FTerminal->Configuration->CreateScpStorage(false);
  12377. return WEBDAV_NO_ERROR;
  12378. }
  12379. unsigned long TWebDAVFileSystem::AdjustToCPSLimit(unsigned long len)
  12380. {
  12381. return FCurrentOperationProgress ? FCurrentOperationProgress->AdjustToCPSLimit(len) : len;
  12382. }
  12383. bool TWebDAVFileSystem::GetIsCancelled()
  12384. {
  12385. TFileOperationProgressType * OperationProgress = FCurrentOperationProgress;
  12386. return (OperationProgress && OperationProgress->Cancel == csCancel);
  12387. }
  12388. //------------------------------------------------------------------------------