123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226 |
- //---------------------------------------------------------------------------
- #include <vcl.h>
- #pragma hdrstop
- #include <malloc.h>
- #include <stdio.h>
- #include <wincrypt.h>
- #include <apr_hash.h>
- #include <apr_strings.h>
- #include <apr_tables.h>
- #include <apr_file_io.h>
- #include <apr_portable.h>
- #include <apr_atomic.h>
- #include <ne_basic.h>
- #include <ne_auth.h>
- #include <ne_compress.h>
- #include <ne_props.h>
- #include <ne_defs.h>
- #include <ne_uri.h>
- #include <ne_session.h>
- #include <ne_request.h>
- #include <ne_xml.h>
- #include <ne_pkcs11.h>
- #include "WebDAVFileSystem.h"
- #include "Interface.h"
- #include "Common.h"
- #include "Exceptions.h"
- #include "Terminal.h"
- #include "TextsCore.h"
- #include "SecureShell.h"
- #include "FileZillaIntf.h"
- #include "HelpCore.h"
- //---------------------------------------------------------------------------
- #pragma package(smart_init)
- //---------------------------------------------------------------------------
- const int tfFirstLevel = 0x01;
- const int tfAutoResume = 0x02;
- //---------------------------------------------------------------------------
- struct TSinkFileParams
- {
- UnicodeString TargetDir;
- const TCopyParamType * CopyParam;
- int Params;
- TFileOperationProgressType * OperationProgress;
- bool Skipped;
- unsigned int Flags;
- };
- //---------------------------------------------------------------------------
- struct TFileTransferData
- {
- TFileTransferData()
- {
- Params = 0;
- AutoResume = false;
- OverwriteResult = -1;
- CopyParam = NULL;
- }
- UnicodeString FileName;
- int Params;
- bool AutoResume;
- int OverwriteResult;
- const TCopyParamType * CopyParam;
- };
- //---------------------------------------------------------------------------
- struct TClipboardHandler
- {
- UnicodeString Text;
- void __fastcall Copy(TObject * /*Sender*/)
- {
- CopyToClipboard(Text);
- }
- };
- //---------------------------------------------------------------------------
- namespace webdav {
- #pragma warn -8004
- const AnsiString __cdecl Format(const char * format, va_list args)
- {
- int len = AnsiString().vprintf(format, args);
- AnsiString Result;
- Result.SetLength(len + 1);
- vsprintf(&Result[1], format, args);
- return Result.c_str();
- }
- const AnsiString __cdecl Format(const char * format, ...)
- {
- va_list args;
- va_start(args, format);
- AnsiString Result = Format(format, args);
- va_end(args);
- return Result;
- }
- //---------------------------------------------------------------------------
- struct auth_baton_t;
- struct vtable_t;
- struct stream_t;
- struct client_ctx_t;
- struct auth_iterstate_t;
- //---------------------------------------------------------------------------
- typedef enum tristate_t
- {
- tristate_false = 2,
- tristate_true,
- tristate_unknown
- } tristate_t;
- //------------------------------------------------------------------------------
- // Userdata for the `proxy_auth' function.
- struct proxy_auth_baton_t
- {
- const char * username; // Cannot be NULL, but "" is okay.
- const char * password; // Cannot be NULL, but "" is okay.
- };
- //------------------------------------------------------------------------------
- // from svn_types.h
- typedef error_t (*cancel_func_t)(void * cancel_baton);
- //------------------------------------------------------------------------------
- // from svn_ra.h
- typedef void (*progress_notify_func_t)(
- apr_off_t progress,
- apr_off_t total,
- void * baton,
- apr_pool_t * pool);
- typedef error_t (*get_client_string_func_t)(void * baton,
- const char ** name,
- apr_pool_t * pool);
- typedef struct callbacks2_t
- {
- auth_baton_t * auth_baton;
- progress_notify_func_t progress_func;
- void * progress_baton;
- cancel_func_t cancel_func;
- get_client_string_func_t get_client_string;
- } callbacks2_t;
- typedef struct callback_baton_t
- {
- client_ctx_t * ctx;
- apr_pool_t * pool;
- } callback_baton_t;
- //------------------------------------------------------------------------------
- // from ra_loader.h
- typedef error_t (*init_func_t)(const vtable_t ** vtable,
- apr_pool_t * pool);
- //------------------------------------------------------------------------------
- // from svn_string.h
- // A simple counted string.
- typedef struct string_t
- {
- const char * data; //< pointer to the bytestring
- apr_size_t len; //< length of bytestring
- } string_t;
- // A buffered string, capable of appending without an allocation and copy
- // for each append.
- typedef struct stringbuf_t
- {
- apr_pool_t * pool;
- char * data;
- apr_size_t len;
- apr_size_t blocksize;
- } stringbuf_t;
- //------------------------------------------------------------------------------
- // from ra_neon.h
- // Rename these types and constants to abstract from Neon
- #define NEON_XML_DECLINE NE_XML_DECLINE
- #define NEON_XML_INVALID NE_XML_ABORT
- #define NEON_XML_CDATA (1<<1)
- #define NEON_XML_COLLECT ((1<<2) | NEON_XML_CDATA)
- // Related to anonymous enum below?
- typedef int neon_xml_elmid;
- typedef struct neon_xml_elm_t
- {
- const char * nspace;
- const char * name;
- neon_xml_elmid id;
- // Processing flags for this namespace:tag.
- // 0 (zero) - regular element, may have children,
- // NEON_XML_CDATA - child-less element,
- // NEON_XML_COLLECT - complete contents of such element must be
- // collected as CDATA, includes *_CDATA flag.
- unsigned int flags;
- } neon_xml_elm_t;
- typedef struct neon_session_t
- {
- apr_pool_t * pool;
- stringbuf_t * url; // original, unparsed session url
- ne_uri root; // parsed version of above
- const char * webdav_root; // URL for WebDAV resource root
- ne_session * ne_sess; // HTTP session to server
- const callbacks2_t * callbacks; // callbacks to get auth data
- void * callback_baton;
- auth_iterstate_t * auth_iterstate; // state of authentication retries
- bool auth_used; // Save authorization state after
- // successful usage
- auth_iterstate_t * p11pin_iterstate; // state of PKCS#11 pin retries
- bool compression; // should we use http compression?
- progress_notify_func_t progress_func;
- void * progress_baton;
- apr_off_t total_progress; // Total number of bytes sent in this
- // session with a -1 total marker
- apr_hash_t * capabilities;
- } neon_session_t;
- typedef struct neon_request_t
- {
- ne_request * ne_req; // neon request structure
- ne_session * ne_sess; // neon session structure
- neon_session_t * sess; // DAV session structure
- const char * method;
- const char * url;
- int rv; // Return value from
- // ne_request_dispatch() or -1 if
- // not dispatched yet.
- int code; // HTTP return code, or 0 if none
- const char * code_desc; // Textual description of CODE
- error_t err; // error encountered while executing
- // the request
- bool marshalled_error; // TRUE if the error was server-side
- apr_pool_t * pool; // where this struct is allocated
- apr_pool_t * iterpool; // iteration pool
- // for use within callbacks
- } neon_request_t;
- // Related to neon_xml_elmid?
- // add WEBDAV_NEON_ to these to prefix conflicts with (sys) headers?
- enum
- {
- // Redefine Neon elements
- // With the new API, we need to be able to use element id also as a return
- // value from the new `startelm' callback, hence all element ids must be
- // positive. Root element id is the only id that is not positive, it's zero.
- // `Root state' is never returned by a callback, it's only passed into it.
- // Therefore, negative element ids are forbidden from now on.
- ELEM_unknown = 1, // was (-1), see above why it's (1) now
- ELEM_root = NE_XML_STATEROOT, // (0)
- ELEM_UNUSED = 100,
- ELEM_207_first = ELEM_UNUSED,
- ELEM_multistatus = ELEM_207_first,
- ELEM_response = ELEM_207_first + 1,
- ELEM_responsedescription = ELEM_207_first + 2,
- ELEM_href = ELEM_207_first + 3,
- ELEM_propstat = ELEM_207_first + 4,
- ELEM_prop = ELEM_207_first + 5, // `prop' tag in the DAV namespace
- ELEM_status = ELEM_207_first + 6,
- ELEM_207_UNUSED = ELEM_UNUSED + 100,
- ELEM_PROPS_UNUSED = ELEM_207_UNUSED + 100,
- // DAV elements
- ELEM_collection = ELEM_207_UNUSED,
- ELEM_comment,
- ELEM_creationdate,
- ELEM_creator_displayname,
- ELEM_options_response,
- ELEM_set_prop,
- ELEM_remove_prop,
- ELEM_resourcetype,
- ELEM_get_content_length,
- ELEM_get_last_modified,
- ELEM_updated_set,
- ELEM_error,
- ELEM_human_readable,
- };
- // The session object.
- struct session_t
- {
- const vtable_t * vtable;
- // Pool used to manage this session.
- apr_pool_t * pool;
- // Private data for the RA implementation.
- void * priv;
- };
- typedef std::vector<TListDataEntry> listdataentry_vector_t;
- // Baton used when listing directory entries.
- typedef struct list_func_baton_t
- {
- bool verbose;
- listdataentry_vector_t * entries;
- session_t * session;
- apr_pool_t * pool;
- } list_func_baton_t;
- //------------------------------------------------------------------------------
- // timeout (in seconds)
- #define DEFAULT_HTTP_TIMEOUT 10
- #define WEBDAV_ERR_DAV_SOCK_INIT 1000
- #define WEBDAV_ERR_XML_MALFORMED 1001
- #define WEBDAV_ERR_DAV_OPTIONS_REQ_FAILED 1002
- #define WEBDAV_ERR_DAV_REQUEST_FAILED 1003
- #define WEBDAV_ERR_INCORRECT_PARAMS 1004
- #define WEBDAV_ERR_FS_NOT_FOUND 1005
- #define WEBDAV_ERR_FS_PROP_BASEVALUE_MISMATCH 1006
- #define WEBDAV_ERR_DAV_FORBIDDEN 1010
- #define WEBDAV_ERR_DAV_RELOCATED 1011
- #define WEBDAV_ERR_NOT_AUTHORIZED 1012
- #define WEBDAV_ERR_ILLEGAL_URL 1013
- #define WEBDAV_ERR_DAV_NOT_IMPLEMENTED 1014
- #define WEBDAV_ERR_NOT_IMPLEMENTED 1015
- #define WEBDAV_ERR_AUTHN_NO_PROVIDER 1020
- #define WEBDAV_ERR_CLIENT_CYCLE_DETECTED 1021
- #define WEBDAV_ERR_DAV_MALFORMED_DATA 1022
- #define WEBDAV_ERR_IO_PIPE_WRITE_ERROR 1023
- #define WEBDAV_ERR_BAD_DATE 1024
- #define WEBDAV_ERR_CLIENT_UNRELATED_RESOURCES 1025
- #define WEBDAV_ERR_ROOT_URL_MISMATCH 1027
- #define WEBDAV_ERR_BAD_FILENAME 1028
- #define WEBDAV_ERR_ENTRY_MISSING_URL 1029
- #define WEBDAV_ERR_FS_NOT_FILE 1030
- #define WEBDAV_ERR_ATOMIC_INIT_FAILURE 1033
- #define WEBDAV_ERR_IO_UNIQUE_NAMES_EXHAUSTED 1034
- #define WEBDAV_ERR_STREAM_SEEK_NOT_SUPPORTED 1035
- #define WEBDAV_ERR_BAD_CONFIG_VALUE 1040
- #define WEBDAV_ERR_CANCELLED 1050
- #define WEBDAV_ERR_DAV_INVALID_CONFIG_VALUE 1051
- #define WEBDAV_ERR_DAV_PROPPATCH_FAILED 1060
- #define WEBDAV_ERR_CANNOT_PUT_FILE 1061
- #define WEBDAV_ERR_CANNOT_DELETE_FILE 1062
- #define WEBDAV_ERR_CANNOT_MKCOL 1063
- #define WEBDAV_ERR_CANNOT_MOVE 1064
- #define WEBDAV_ERR_CANNOT_PROPFIND 1065
- #define WEBDAV_ERR_BAD_PARAM 1070
- // The application doesn't want any providers to save credentials
- // to disk. Property value is irrelevant; only property's existence
- // matters.
- #define AUTH_PARAM_NO_AUTH_CACHE AUTH_PARAM_PREFIX "no-auth-cache"
- // #define HASH_KEY_STRING ""
- #define MAX_REDIRECT_ATTEMPTS 3 // TODO: Make configurable.
- //---------------------------------------------------------------------------
- // #define WEBDAV_ARRAY_IDX(ary,i,type) ((type)(ary)[i])
- #define WEBDAV_NO_ERROR 0
- #define WEBDAV_UNKNOWN_ERROR 1
- #define WEBDAV_ERR(expr) \
- do { \
- webdav::error_t err__temp = (expr); \
- if (err__temp) \
- return err__temp; \
- } while (0)
- // A statement macro, very similar to WEBDAV_ERR.
- // This macro will wrap the error with the specified text before
- // returning the error.
- #define WEBDAV_ERR_W(expr, wrap_msg) \
- do { \
- webdav::error_t err__temp = (expr); \
- if (err__temp) \
- return webdav::error_create(err__temp, NULL, wrap_msg); \
- } while (0)
- #define WEBDAV_ERR_ASSERT(expr) \
- do { \
- if (!(expr)) \
- WEBDAV_ERR(WEBDAV_UNKNOWN_ERROR); \
- } while (0)
- #define error_trace(expr) (expr)
- // Create a pool as a subpool of parent_pool
- #define webdav_pool_create(parent_pool) webdav::pool_create_ex(parent_pool, NULL)
- #define webdav_pool_clear apr_pool_clear
- // Destroy a pool and all of its children.
- // This define for webdav_pool_destroy exists for symmetry and
- // completeness.
- #define webdav_pool_destroy apr_pool_destroy
- // Destroy request REQ and any associated resources
- #define neon_request_destroy(req) webdav_pool_destroy((req)->pool)
- // Statement macro to set the request error,
- // making sure we don't leak any in case we encounter more than one error.
- // Sets the 'err' field of REQ to the value obtained by evaluating NEW_ERR.
- #define NEON_REQ_ERR(req, new_err) \
- do { \
- error_t err__tmp = (new_err); \
- if ((req)->err && !(req)->marshalled_error) \
- error_clear(&err__tmp); \
- else if (err__tmp) \
- { \
- error_clear(&(req)->err); \
- (req)->err = err__tmp; \
- (req)->marshalled_error = false; \
- } \
- } while (0)
- //===========================================================================
- //------------------------------------------------------------------------------
- // from error.c
- static void
- error_clear(error_t * err)
- {
- if (err) *err = 0;
- }
- static error_t
- make_error_internal(
- apr_status_t apr_err,
- error_t * child)
- {
- error_t new_error = apr_err;
- return new_error;
- }
- static error_t
- error_create(
- apr_status_t apr_err,
- error_t * child,
- const char * message)
- {
- return apr_err;
- }
- static error_t
- error_createf(
- apr_status_t apr_err,
- error_t * child,
- const char * fmt,
- ...)
- {
- va_list args;
- va_start(args, fmt);
- AnsiString Message = Format(fmt, args);
- va_end(args);
- AnsiString Message2 = Format("Error, code: %d, message: %s", apr_err, Message.c_str());
- throw ExtException(UnicodeString(Message2), NULL);
- }
- static error_t
- error_wrap_apr(
- apr_status_t status,
- const char * fmt,
- ...)
- {
- error_t err = 0;
- va_list args;
- err = make_error_internal(status, NULL);
- va_start(args, fmt);
- AnsiString Message = Format(fmt, args);
- va_end(args);
- err = error_create(err, NULL, Message.c_str());
- return err;
- }
- //------------------------------------------------------------------------------
- // from utils.c
- // a cleanup routine attached to the pool that contains the RA session
- // root URI.
- static apr_status_t
- cleanup_uri(void * uri)
- {
- ne_uri_free(static_cast<ne_uri *>(uri));
- return APR_SUCCESS;
- }
- static error_t
- parse_url(
- const char * url, ne_uri * uri)
- {
- if (ne_uri_parse(url, uri) ||
- (uri->host == NULL) || (uri->path == NULL) || (uri->scheme == NULL))
- {
- ne_uri_free(uri);
- return 0;
- }
- if (uri->port == 0)
- uri->port = ne_uri_defaultport(uri->scheme);
- return 1;
- }
- static error_t
- parse_ne_uri(
- ne_uri ** uri,
- const char * webdav_url,
- apr_pool_t * pool)
- {
- // Sanity check the URI
- *uri = static_cast<ne_uri *>(apr_pcalloc(pool, sizeof(**uri)));
- if (!parse_url(webdav_url, *uri))
- {
- return error_createf(WEBDAV_ERR_ILLEGAL_URL, NULL,
- "URL '%s' is malformed or the "
- "scheme or host or path is missing", webdav_url);
- }
- // make sure we eventually destroy the uri
- apr_pool_cleanup_register(pool, *uri, cleanup_uri, apr_pool_cleanup_null);
- return WEBDAV_NO_ERROR;
- }
- //------------------------------------------------------------------------------
- // from svn_types.h
- #define atoui64(X) ((apr_uint64_t) apr_atoi64(X))
- // An indication that you are interested in the kind field
- #define WEBDAV_DIRENT_KIND 0x00001
- // An indication that you are interested in the size field
- #define WEBDAV_DIRENT_SIZE 0x00002
- // An indication that you are interested in the time field
- #define WEBDAV_DIRENT_TIME 0x00010
- // A combination of all the dirent fields
- #define WEBDAV_DIRENT_ALL ~((apr_uint32_t ) 0)
- // The various types of nodes in filesystem.
- typedef enum node_kind_t
- {
- // absent
- node_none,
- // regular file
- node_file,
- // directory
- node_dir,
- // something's here, but we don't know what
- node_unknown
- } node_kind_t;
- // A general directory entry.
- typedef struct dirent_t
- {
- // node kind
- node_kind_t kind;
- // length of file text, or 0 for directories
- apr_int64_t size;
- // time of mod-time
- apr_time_t time;
- } dirent_t;
- typedef enum depth_t
- {
- // Just the named directory D, no entries. Updates will not pull in
- // any files or subdirectories not already present.
- depth_empty = 0,
- // D + its file children, but not subdirs. Updates will pull in any
- // files not already present, but not subdirectories.
- depth_files = 1,
- // D + immediate children (D and its entries). Updates will pull in
- // any files or subdirectories not already present; those
- // subdirectories' this_dir entries will have depth-empty.
- depth_immediates = 2,
- // D + all descendants (full recursion from D). Updates will pull
- // in any files or subdirectories not already present; those
- // subdirectories' this_dir entries will have depth-infinity.
- // Equivalent to the pre-1.5 default update behavior.
- depth_infinity = 3
- } depth_t;
- //------------------------------------------------------------------------------
- // from utf.h
- static error_t
- utf_cstring_to_utf8(
- const char ** dest,
- const char * src,
- apr_pool_t * pool);
- static error_t
- utf_cstring_from_utf8(
- const char ** dest,
- const char * src,
- apr_pool_t * pool);
- // Local wrapper of path_cstring_from_utf8() that does no copying on
- // operating systems where APR always uses utf-8 as native path format
- static error_t
- cstring_from_utf8(
- const char ** path_apr,
- const char * path_utf8,
- apr_pool_t * pool);
- //------------------------------------------------------------------------------
- // from ra_neon.h
- #ifdef WEBDAV_DEBUG
- #define DEBUG_CR "\n"
- #else
- #define DEBUG_CR ""
- #endif
- #define NEON_DEPTH_ZERO 0
- #define NEON_DEPTH_ONE 1
- #define NEON_DEPTH_INFINITE -1
- // NEON_PROP_*: properties that we fetch from the server
- // These are simply symbolic names for some standard properties that we fetch.
- #define NEON_PROP_CREATIONDATE "DAV:creationdate"
- #define NEON_PROP_GETCONTENTLENGTH "DAV:getcontentlength"
- typedef struct neon_resource_t
- {
- // what is the URL for this resource
- const char * url;
- // is this resource a collection? (from the DAV:resourcetype element)
- int is_collection;
- // PROPSET: NAME -> VALUE (const char * -> const string_t *)
- apr_hash_t * propset;
- // --- only used during response processing ---
- // when we see a DAV:href element, what element is the parent?
- int href_parent;
- apr_pool_t * pool;
- } neon_resource_t;
- // Our equivalent of ne_xml_startelm_cb, the difference being that it
- // returns errors in a error_t, and returns the element type via
- // ELEM. To ignore the element *ELEM should be set to
- // NEON_XML_DECLINE and WEBDAV_NO_ERROR should be returned.
- // *ELEM can be set to NEON_XML_INVALID to indicate invalid XML
- // (and abort the parse).
- typedef error_t (*neon_startelm_cb_t)(int * elem,
- void * baton,
- int parent,
- const char * nspace,
- const char * name,
- const char ** atts);
- // Our equivalent of ne_xml_cdata_cb, the difference being that it returns
- // errors in a error_t.
- typedef error_t (*neon_cdata_cb_t)(void * baton,
- int state,
- const char * cdata,
- size_t len);
- // Our equivalent of ne_xml_endelm_cb, the difference being that it returns
- // errors in a error_t.
- typedef error_t (*neon_endelm_cb_t)(void * baton,
- int state,
- const char * nspace,
- const char * name);
- static ne_xml_parser *
- neon_xml_parser_create(
- neon_request_t * req,
- ne_accept_response accpt,
- neon_startelm_cb_t startelm_cb,
- neon_cdata_cb_t cdata_cb,
- neon_endelm_cb_t endelm_cb,
- void * baton);
- static error_t
- neon_request_dispatch(
- int * code_p,
- neon_request_t * req,
- apr_hash_t * extra_headers,
- const char * body,
- int okay_1,
- int okay_2,
- bool check_errors,
- apr_pool_t * pool);
- static error_t
- neon_check_parse_error(
- const char * method,
- ne_xml_parser * xml_parser,
- const char * url);
- static error_t
- neon_request_create(
- neon_request_t ** request,
- neon_session_t * sess,
- const char * method, const char * url,
- apr_pool_t * pool);
- static const neon_xml_elm_t *
- neon_lookup_xml_elem(
- const neon_xml_elm_t * table,
- const char * nspace,
- const char * name);
- static error_t
- neon_xml_collect_cdata(
- void * baton, int state,
- const char * cdata, size_t len);
- static const char *
- neon_request_get_location(
- neon_request_t * request,
- apr_pool_t * pool);
- // Our version of ne_block_reader, which returns an
- // error_t instead of an int.
- typedef error_t (*neon_block_reader)(
- void * baton,
- const char * data,
- size_t len);
- //------------------------------------------------------------------------------
- // from dirent_uri.h
- static bool
- dirent_is_root(
- const char * dirent,
- apr_size_t len);
- //------------------------------------------------------------------------------
- // from svn_props.h
- static error_t
- neon_get_props_resource(
- neon_resource_t ** rsrc,
- neon_session_t * sess,
- const char * url,
- const ne_propname * which_props,
- bool check_errors,
- apr_pool_t * pool);
- //------------------------------------------------------------------------------
- // from ra_loader.h
- // The RA layer vtable.
- typedef struct vtable_t
- {
- // Return a short description of the RA implementation, as a localized
- // string.
- const char * (*get_description)(void);
- // Return a list of actual URI schemes supported by this implementation.
- // The returned array is NULL-terminated.
- const char * const * (*get_schemes)(apr_pool_t * pool);
- // Implementations of the public API functions.
- // See session_open().
- // All fields in SESSION, except priv, have been initialized by the
- // time this is called. SESSION->priv may be set by this function.
- error_t (*open_session)(session_t * session,
- const char ** corrected_url,
- const char * session_URL,
- const callbacks2_t * callbacks,
- void * callback_baton,
- apr_pool_t * pool);
- // See reparent().
- // URL is guaranteed to have what get_webdav_resource_root() returns as a prefix.
- error_t (*reparent)(session_t * session,
- const char * url,
- apr_pool_t * pool);
- // See get_session_url().
- error_t (*get_session_url)(session_t * session,
- const char ** url,
- apr_pool_t * pool);
- // See get_file().
- error_t (*get_file)(session_t * session,
- const char * path,
- stream_t * stream,
- apr_hash_t ** props,
- apr_pool_t * pool);
- // See get_dir2().
- error_t (*get_dir)(session_t * session,
- apr_hash_t ** dirents,
- const char * path,
- apr_uint32_t dirent_fields,
- apr_pool_t * pool);
- // See check_path().
- error_t (*check_path)(session_t * session,
- const char * path,
- node_kind_t * kind,
- apr_pool_t * pool);
- // See stat().
- error_t (*stat)(session_t * session,
- const char * path,
- dirent_t ** dirent,
- apr_pool_t * pool);
- // See get_webdav_resource_root2().
- error_t (*get_webdav_resource_root)(session_t * session,
- const char ** url,
- apr_pool_t * pool);
- // See has_capability().
- // error_t (*has_capability)(session_t *session,
- // bool *has,
- // const char *capability,
- // apr_pool_t *pool);
- } vtable_t;
- static error_t
- get_path_relative_to_root(
- session_t * session,
- const char ** rel_path,
- const char * url,
- apr_pool_t * pool);
- static error_t
- neon_init(
- const vtable_t ** vtable,
- apr_pool_t * pool);
- //------------------------------------------------------------------------------
- // from svn_ctype.h
- // Table of flags for character classification.
- extern const apr_uint32_t * const ctype_table;
- // Check if c is in the character class described by flags.
- // The flags is a bitwise-or combination of WEBDAV_CTYPE_*
- // constants. Uses #ctype_table.
- #define ctype_test(c, flags) \
- (0 != (ctype_table[(unsigned char)(c)] & (flags)))
- // Basic character classes
- #define WEBDAV_CTYPE_CNTRL 0x0001 //< Control character
- #define WEBDAV_CTYPE_SPACE 0x0002 //< Whitespace
- #define WEBDAV_CTYPE_DIGIT 0x0004 //< Decimal digit
- #define WEBDAV_CTYPE_UPPER 0x0008 //< Uppercase letter
- #define WEBDAV_CTYPE_LOWER 0x0010 //< Lowercase letter
- #define WEBDAV_CTYPE_PUNCT 0x0020 //< Punctuation mark
- #define WEBDAV_CTYPE_XALPHA 0x0040 //< Hexadecimal digits A to F
- #define WEBDAV_CTYPE_ASCII 0x0080 //< ASCII subset*/
- // Derived character classes
- // ASCII letter
- #define WEBDAV_CTYPE_ALPHA (WEBDAV_CTYPE_LOWER | WEBDAV_CTYPE_UPPER)
- // ASCII letter or decimal digit
- #define WEBDAV_CTYPE_ALNUM (WEBDAV_CTYPE_ALPHA | WEBDAV_CTYPE_DIGIT)
- // ASCII hexadecimal digit
- #define WEBDAV_CTYPE_XDIGIT (WEBDAV_CTYPE_DIGIT | WEBDAV_CTYPE_XALPHA)
- // Printable ASCII except space
- #define WEBDAV_CTYPE_GRAPH (WEBDAV_CTYPE_PUNCT | WEBDAV_CTYPE_ALNUM)
- // All printable ASCII
- #define WEBDAV_CTYPE_PRINT (WEBDAV_CTYPE_GRAPH | WEBDAV_CTYPE_SPACE)
- // Check if c is an ASCII control character.
- #define ctype_iscntrl(c) ctype_test((c), WEBDAV_CTYPE_CNTRL)
- // Check if c is an ASCII whitespace character.
- #define ctype_isspace(c) ctype_test((c), WEBDAV_CTYPE_SPACE)
- // Check if c is an ASCII digit.
- #define ctype_isdigit(c) ctype_test((c), WEBDAV_CTYPE_DIGIT)
- // Check if c is an ASCII uppercase letter.
- #define ctype_isupper(c) ctype_test((c), WEBDAV_CTYPE_UPPER)
- // Check if c is an ASCII lowercase letter.
- #define ctype_islower(c) ctype_test((c), WEBDAV_CTYPE_LOWER)
- // Check if c is an ASCII punctuation mark.
- #define ctype_ispunct(c) ctype_test((c), WEBDAV_CTYPE_PUNCT)
- // Check if c is an ASCII character.
- #define ctype_isascii(c) ctype_test((c), WEBDAV_CTYPE_ASCII)
- // Check if c is an ASCII letter.
- #define ctype_isalpha(c) ctype_test((c), WEBDAV_CTYPE_ALPHA)
- // Check if c is an ASCII letter or decimal digit.
- #define ctype_isalnum(c) ctype_test((c), WEBDAV_CTYPE_ALNUM)
- // Check if c is an ASCII hexadecimal digit.
- #define ctype_isxdigit(c) ctype_test((c), WEBDAV_CTYPE_XDIGIT)
- // Check if c is an ASCII graphical (visible printable) character.
- #define ctype_isgraph(c) ctype_test((c), WEBDAV_CTYPE_GRAPH)
- // Check if c is an ASCII printable character.
- #define ctype_isprint(c) ctype_test((c), WEBDAV_CTYPE_PRINT)
- // Basic extended character classes
- #define WEBDAV_CTYPE_UTF8LEAD 0x0100 //< UTF-8 multibyte lead byte
- #define WEBDAV_CTYPE_UTF8CONT 0x0200 //< UTF-8 multibyte non-lead byte
- #define WEBDAV_CTYPE_XMLNAME 0x0400
- #define WEBDAV_CTYPE_URISAFE 0x0800
- // Derived extended character classes
- // Part of a UTF-8 multibyte character.
- #define WEBDAV_CTYPE_UTF8MBC (WEBDAV_CTYPE_UTF8LEAD | WEBDAV_CTYPE_UTF8CONT)
- // All valid UTF-8 bytes.
- #define WEBDAV_CTYPE_UTF8 (WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UTF8MBC)
- // Check if c is a UTF-8 multibyte lead byte.
- #define ctype_isutf8lead(c) ctype_test((c), WEBDAV_CTYPE_UTF8LEAD)
- // Check if c is a UTF-8 multibyte continuation (non-lead) byte.
- #define ctype_isutf8cont(c) ctype_test((c), WEBDAV_CTYLE_UTF8CONT)
- // Check if c is part of a UTF-8 multibyte character.
- #define ctype_isutf8mbc(c) ctype_test((c), WEBDAV_CTYPE_UTF8MBC)
- // Check if c is valid in UTF-8.
- #define ctype_isutf8(c) ctype_test((c), WEBDAV_CTYPE_UTF8)
- #define WEBDAV_CTYPE_ASCII_MINUS 45 //< ASCII value of '-'
- #define WEBDAV_CTYPE_ASCII_DOT 46 //< ASCII value of '.'
- #define WEBDAV_CTYPE_ASCII_COLON 58 //< ASCII value of ':'
- #define WEBDAV_CTYPE_ASCII_UNDERSCORE 95 //< ASCII value of '_'
- #define WEBDAV_CTYPE_ASCII_TAB 9 //< ASCII value of a tab
- #define WEBDAV_CTYPE_ASCII_LINEFEED 10 //< ASCII value of a line feed
- #define WEBDAV_CTYPE_ASCII_CARRIAGERETURN 13
- //< ASCII value of a carriage return
- #define WEBDAV_CTYPE_ASCII_DELETE 127
- //< ASCII value of a delete character
- /*
- * Compare two characters a and b, treating case-equivalent
- * unaccented Latin (ASCII subset) letters as equal.
- *
- * Returns in integer greater than, equal to, or less than 0,
- * according to whether a is considered greater than, equal to,
- * or less than b.
- */
- static int
- ctype_casecmp(int a, int b);
- //------------------------------------------------------------------------------
- // from svn_string.c
- static APR_INLINE bool
- string_compare(
- const char * str1,
- const char * str2,
- apr_size_t len1,
- apr_size_t len2)
- {
- // easy way out :)
- if (len1 != len2)
- return FALSE;
- // now the strings must have identical lengths
- if ((memcmp(str1, str2, len1)) == 0)
- return TRUE;
- else
- return FALSE;
- }
- // Our own realloc, since APR doesn't have one. Note: this is a
- // generic realloc for memory pools, *not* for strings.
- static void *
- my_realloc(
- char * data,
- apr_size_t oldsize,
- apr_size_t request,
- apr_pool_t * pool)
- {
- void * new_area = NULL;
- // todo: it's a pity APR doesn't give us this -- sometimes it
- // could realloc the block merely by extending in place, sparing us
- // a memcpy(), but only the pool would know enough to be able to do
- // this. We should add a realloc() to APR if someone hasn't
- // already.
- // malloc new area
- new_area = apr_pcalloc(pool, request);
- // copy data to new area
- memcpy(new_area, data, oldsize);
- // I'm NOT freeing old area here -- cuz we're using pools, ugh.
- // return new area
- return new_area;
- }
- // string functions
- static stringbuf_t *
- stringbuf_create_ensure(
- apr_size_t blocksize,
- apr_pool_t * pool)
- {
- void * mem = NULL;
- stringbuf_t * new_string = NULL;
- // apr_pcalloc will allocate multiples of 8.
- // Thus, we would waste some of that memory if we stuck to the
- // smaller size. Note that this is safe even if apr_pcalloc would
- // use some other alignment or none at all.
- ++blocksize; // + space for '\0'
- blocksize = APR_ALIGN_DEFAULT(blocksize);
- // Allocate memory for string_t and data in one chunk.
- mem = apr_pcalloc(pool, sizeof(*new_string) + blocksize);
- // Initialize header and string
- new_string = static_cast<stringbuf_t *>(mem);
- new_string->data = (char *)mem + sizeof(*new_string);
- new_string->data[0] = '\0';
- new_string->len = 0;
- new_string->blocksize = blocksize;
- new_string->pool = pool;
- return new_string;
- }
- static stringbuf_t *
- stringbuf_ncreate(
- const char * bytes,
- apr_size_t size,
- apr_pool_t * pool)
- {
- stringbuf_t * strbuf = stringbuf_create_ensure(size, pool);
- memcpy(strbuf->data, bytes, size);
- // Null termination is the convention -- even if we suspect the data
- // to be binary, it's not up to us to decide, it's the caller's
- // call. Heck, that's why they call it the caller!
- strbuf->data[size] = '\0';
- strbuf->len = size;
- return strbuf;
- }
- static stringbuf_t *
- stringbuf_create(
- const char * cstring,
- apr_pool_t * pool)
- {
- return stringbuf_ncreate(cstring, strlen(cstring), pool);
- }
- static void
- stringbuf_ensure(
- stringbuf_t * str,
- apr_size_t minimum_size)
- {
- // Keep doubling capacity until have enough.
- if (str->blocksize < minimum_size)
- {
- if (str->blocksize == 0)
- // APR will increase odd allocation sizes to the next
- // multiple for 8, for instance. Take advantage of that
- // knowledge and allow for the extra size to be used.
- str->blocksize = APR_ALIGN_DEFAULT(minimum_size);
- else
- while (str->blocksize < minimum_size)
- {
- // str->blocksize is aligned;
- // doubling it should keep it aligned
- apr_size_t prev_size = str->blocksize;
- str->blocksize *= 2;
- // check for apr_size_t overflow
- if (prev_size > str->blocksize)
- {
- str->blocksize = minimum_size;
- break;
- }
- }
- str->data = (char *) my_realloc(str->data,
- str->len + 1,
- // We need to maintain (and thus copy)
- // the trailing null
- str->blocksize,
- str->pool);
- }
- }
- static void
- stringbuf_set(
- stringbuf_t * str,
- const char * value)
- {
- apr_size_t amt = strlen(value);
- stringbuf_ensure(str, amt + 1);
- memcpy(str->data, value, amt + 1);
- str->len = amt;
- }
- static void
- stringbuf_setempty(
- stringbuf_t * str)
- {
- if (str->len > 0)
- str->data[0] = '\0';
- str->len = 0;
- }
- static bool
- stringbuf_isempty(
- const stringbuf_t * str)
- {
- return (str->len == 0);
- }
- // Return a new string_t object, allocated in POOL, initialized with
- // DATA and SIZE. Do not copy the contents of DATA, just store the pointer.
- // SIZE is the length in bytes of DATA, excluding the required NUL
- // terminator.
- static string_t *
- create_string(
- const char * data,
- apr_size_t size,
- apr_pool_t * pool)
- {
- string_t * new_string;
- new_string = static_cast<string_t *>(apr_pcalloc(pool, sizeof(*new_string)));
- new_string->data = data;
- new_string->len = size;
- return new_string;
- }
- static string_t *
- string_ncreate(
- const char * bytes,
- apr_size_t size,
- apr_pool_t * pool)
- {
- void * mem = NULL;
- char * data = NULL;
- string_t * new_string;
- // Allocate memory for string_t and data in one chunk.
- mem = apr_pcalloc(pool, sizeof(*new_string) + size + 1);
- data = (char *)mem + sizeof(*new_string);
- new_string = static_cast<string_t *>(mem);
- new_string->data = data;
- new_string->len = size;
- memcpy(data, bytes, size);
- // Null termination is the convention -- even if we suspect the data
- // to be binary, it's not up to us to decide, it's the caller's
- // call. Heck, that's why they call it the caller!
- data[size] = '\0';
- return new_string;
- }
- static string_t *
- string_create(
- const char * cstring,
- apr_pool_t * pool)
- {
- return string_ncreate(cstring, strlen(cstring), pool);
- }
- static string_t *
- string_createv(
- apr_pool_t * pool,
- const char * fmt,
- va_list ap)
- {
- char * data = apr_pvsprintf(pool, fmt, ap);
- // wrap an string_t around the new data
- return create_string(data, strlen(data), pool);
- }
- static string_t *
- string_createf(
- apr_pool_t * pool,
- const char * fmt,
- ...)
- {
- string_t * str = NULL;
- va_list ap;
- va_start(ap, fmt);
- str = string_createv(pool, fmt, ap);
- va_end(ap);
- return str;
- }
- static bool
- string_compare(
- const string_t * str1,
- const string_t * str2)
- {
- return
- string_compare(str1->data, str2->data, str1->len, str2->len);
- }
- static void
- stringbuf_appendbytes(
- stringbuf_t * str,
- const char * bytes,
- apr_size_t count)
- {
- apr_size_t total_len = 0;
- void * start_address = NULL;
- total_len = str->len + count; // total size needed
- // +1 for null terminator.
- stringbuf_ensure(str, (total_len + 1));
- // get address 1 byte beyond end of original bytestring
- start_address = (str->data + str->len);
- memcpy(start_address, bytes, count);
- str->len = total_len;
- str->data[str->len] = '\0'; // We don't know if this is binary
- // data or not, but convention is
- // to null-terminate.
- }
- static void
- stringbuf_appendstr(
- stringbuf_t * targetstr,
- const stringbuf_t * appendstr)
- {
- stringbuf_appendbytes(targetstr, appendstr->data, appendstr->len);
- }
- static void
- stringbuf_appendcstr(
- stringbuf_t * targetstr,
- const char * cstr)
- {
- stringbuf_appendbytes(targetstr, cstr, strlen(cstr));
- }
- static error_t
- cstring_strtoi64(
- apr_int64_t * n,
- const char * str,
- apr_int64_t minval,
- apr_int64_t maxval,
- int base)
- {
- apr_int64_t val = 0;
- char * endptr = NULL;
- // We assume errno is thread-safe.
- errno = 0; // APR-0.9 doesn't always set errno
- val = apr_strtoi64(str, &endptr, base);
- if (errno == EINVAL || endptr == str || str[0] == '\0' || *endptr != '\0')
- return error_createf(WEBDAV_ERR_INCORRECT_PARAMS, NULL,
- "Could not convert '%s' into a number",
- str);
- if ((errno == ERANGE && (val == APR_INT64_MIN || val == APR_INT64_MAX)) ||
- val < minval || val > maxval)
- // Mark this for translation when gettext doesn't choke on macros.
- return error_createf(WEBDAV_ERR_INCORRECT_PARAMS, NULL,
- "Number '%s' is out of range "
- "'[%" APR_INT64_T_FMT ", %" APR_INT64_T_FMT "]'",
- str, minval, maxval);
- *n = val;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- cstring_atoi64(
- apr_int64_t * n,
- const char * str)
- {
- return error_trace(cstring_strtoi64(n, str, APR_INT64_MIN,
- APR_INT64_MAX, 10));
- }
- static int
- cstring_casecmp(
- const char * str1,
- const char * str2)
- {
- for (;;)
- {
- const int a = *str1++;
- const int b = *str2++;
- const int cmp = ctype_casecmp(a, b);
- if (cmp || !a || !b)
- return cmp;
- }
- }
- static stringbuf_t *
- create_stringbuf(
- char * data,
- apr_size_t size,
- apr_size_t blocksize,
- apr_pool_t * pool)
- {
- stringbuf_t * new_string;
- new_string = static_cast<stringbuf_t *>(apr_pcalloc(pool, sizeof(*new_string)));
- new_string->data = data;
- new_string->len = size;
- new_string->blocksize = blocksize;
- new_string->pool = pool;
- return new_string;
- }
- static stringbuf_t *
- stringbuf_createv(
- apr_pool_t * pool,
- const char * fmt,
- va_list ap)
- {
- char * data = apr_pvsprintf(pool, fmt, ap);
- apr_size_t size = strlen(data);
- // wrap an stringbuf_t around the new data
- return create_stringbuf(data, size, size + 1, pool);
- }
- static stringbuf_t *
- stringbuf_createf(
- apr_pool_t * pool,
- const char * fmt,
- ...)
- {
- stringbuf_t * str = NULL;
- va_list ap;
- va_start(ap, fmt);
- str = stringbuf_createv(pool, fmt, ap);
- va_end(ap);
- return str;
- }
- static void
- cstring_split_append(
- apr_array_header_t * array,
- const char * input,
- const char * sep_chars,
- bool chop_whitespace,
- apr_pool_t * pool)
- {
- char * last = NULL;
- char * pats = apr_pstrdup(pool, input); // strtok wants non-const data
- char * p = apr_strtok(pats, sep_chars, &last);
- while (p)
- {
- if (chop_whitespace)
- {
- while (ctype_isspace(*p))
- p++;
- {
- char * e = p + (strlen(p) - 1);
- while ((e >= p) && (ctype_isspace(*e)))
- e--;
- *(++e) = '\0';
- }
- }
- if (p[0] != '\0')
- APR_ARRAY_PUSH(array, const char *) = p;
- p = apr_strtok(NULL, sep_chars, &last);
- }
- return;
- }
- static apr_array_header_t *
- cstring_split(
- const char * input,
- const char * sep_chars,
- bool chop_whitespace,
- apr_pool_t * pool)
- {
- apr_array_header_t * a = apr_array_make(pool, 5, sizeof(input));
- cstring_split_append(a, input, sep_chars, chop_whitespace, pool);
- return a;
- }
- //------------------------------------------------------------------------------
- // from ctype.c
- static const apr_uint32_t ctype_table_internal[256] =
- {
- // **** DO NOT EDIT! ****
- // This table was generated by genctype.py, make changes there.
- /* nul */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* soh */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* stx */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* etx */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* eot */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* enq */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* ack */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* bel */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* bs */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* ht */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL | WEBDAV_CTYPE_SPACE,
- /* nl */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL | WEBDAV_CTYPE_SPACE,
- /* vt */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL | WEBDAV_CTYPE_SPACE,
- /* np */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL | WEBDAV_CTYPE_SPACE,
- /* cr */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL | WEBDAV_CTYPE_SPACE,
- /* so */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* si */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* dle */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* dc1 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* dc2 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* dc3 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* dc4 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* nak */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* syn */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* etb */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* can */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* em */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* sub */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* esc */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* fs */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* gs */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* rs */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* us */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* sp */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_SPACE,
- /* ! */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* " */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* # */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* $ */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* % */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* & */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* ' */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* ( */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* ) */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* * */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* + */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* , */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* - */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* . */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* / */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* 0 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
- /* 1 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
- /* 2 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
- /* 3 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
- /* 4 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
- /* 5 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
- /* 6 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
- /* 7 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
- /* 8 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
- /* 9 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
- /* : */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* ; */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* < */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* = */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* > */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* ? */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* @ */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* A */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER | WEBDAV_CTYPE_XALPHA,
- /* B */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER | WEBDAV_CTYPE_XALPHA,
- /* C */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER | WEBDAV_CTYPE_XALPHA,
- /* D */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER | WEBDAV_CTYPE_XALPHA,
- /* E */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER | WEBDAV_CTYPE_XALPHA,
- /* F */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER | WEBDAV_CTYPE_XALPHA,
- /* G */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* H */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* I */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* J */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* K */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* L */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* M */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* N */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* O */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* P */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* Q */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* R */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* S */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* T */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* U */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* V */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* W */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* X */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* Y */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* Z */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
- /* [ */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* \ */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* ] */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* ^ */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* _ */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* ` */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* a */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER | WEBDAV_CTYPE_XALPHA,
- /* b */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER | WEBDAV_CTYPE_XALPHA,
- /* c */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER | WEBDAV_CTYPE_XALPHA,
- /* d */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER | WEBDAV_CTYPE_XALPHA,
- /* e */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER | WEBDAV_CTYPE_XALPHA,
- /* f */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER | WEBDAV_CTYPE_XALPHA,
- /* g */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* h */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* i */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* j */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* k */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* l */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* m */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* n */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* o */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* p */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* q */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* r */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* s */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* t */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* u */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* v */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* w */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* x */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* y */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* z */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
- /* { */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* | */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* } */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* ~ */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
- /* del */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
- /* x80 */ WEBDAV_CTYPE_UTF8CONT,
- /* x81 */ WEBDAV_CTYPE_UTF8CONT,
- /* x82 */ WEBDAV_CTYPE_UTF8CONT,
- /* x83 */ WEBDAV_CTYPE_UTF8CONT,
- /* x84 */ WEBDAV_CTYPE_UTF8CONT,
- /* x85 */ WEBDAV_CTYPE_UTF8CONT,
- /* x86 */ WEBDAV_CTYPE_UTF8CONT,
- /* x87 */ WEBDAV_CTYPE_UTF8CONT,
- /* x88 */ WEBDAV_CTYPE_UTF8CONT,
- /* x89 */ WEBDAV_CTYPE_UTF8CONT,
- /* x8a */ WEBDAV_CTYPE_UTF8CONT,
- /* x8b */ WEBDAV_CTYPE_UTF8CONT,
- /* x8c */ WEBDAV_CTYPE_UTF8CONT,
- /* x8d */ WEBDAV_CTYPE_UTF8CONT,
- /* x8e */ WEBDAV_CTYPE_UTF8CONT,
- /* x8f */ WEBDAV_CTYPE_UTF8CONT,
- /* x90 */ WEBDAV_CTYPE_UTF8CONT,
- /* x91 */ WEBDAV_CTYPE_UTF8CONT,
- /* x92 */ WEBDAV_CTYPE_UTF8CONT,
- /* x93 */ WEBDAV_CTYPE_UTF8CONT,
- /* x94 */ WEBDAV_CTYPE_UTF8CONT,
- /* x95 */ WEBDAV_CTYPE_UTF8CONT,
- /* x96 */ WEBDAV_CTYPE_UTF8CONT,
- /* x97 */ WEBDAV_CTYPE_UTF8CONT,
- /* x98 */ WEBDAV_CTYPE_UTF8CONT,
- /* x99 */ WEBDAV_CTYPE_UTF8CONT,
- /* x9a */ WEBDAV_CTYPE_UTF8CONT,
- /* x9b */ WEBDAV_CTYPE_UTF8CONT,
- /* x9c */ WEBDAV_CTYPE_UTF8CONT,
- /* x9d */ WEBDAV_CTYPE_UTF8CONT,
- /* x9e */ WEBDAV_CTYPE_UTF8CONT,
- /* x9f */ WEBDAV_CTYPE_UTF8CONT,
- /* xa0 */ WEBDAV_CTYPE_UTF8CONT,
- /* xa1 */ WEBDAV_CTYPE_UTF8CONT,
- /* xa2 */ WEBDAV_CTYPE_UTF8CONT,
- /* xa3 */ WEBDAV_CTYPE_UTF8CONT,
- /* xa4 */ WEBDAV_CTYPE_UTF8CONT,
- /* xa5 */ WEBDAV_CTYPE_UTF8CONT,
- /* xa6 */ WEBDAV_CTYPE_UTF8CONT,
- /* xa7 */ WEBDAV_CTYPE_UTF8CONT,
- /* xa8 */ WEBDAV_CTYPE_UTF8CONT,
- /* xa9 */ WEBDAV_CTYPE_UTF8CONT,
- /* xaa */ WEBDAV_CTYPE_UTF8CONT,
- /* xab */ WEBDAV_CTYPE_UTF8CONT,
- /* xac */ WEBDAV_CTYPE_UTF8CONT,
- /* xad */ WEBDAV_CTYPE_UTF8CONT,
- /* xae */ WEBDAV_CTYPE_UTF8CONT,
- /* xaf */ WEBDAV_CTYPE_UTF8CONT,
- /* xb0 */ WEBDAV_CTYPE_UTF8CONT,
- /* xb1 */ WEBDAV_CTYPE_UTF8CONT,
- /* xb2 */ WEBDAV_CTYPE_UTF8CONT,
- /* xb3 */ WEBDAV_CTYPE_UTF8CONT,
- /* xb4 */ WEBDAV_CTYPE_UTF8CONT,
- /* xb5 */ WEBDAV_CTYPE_UTF8CONT,
- /* xb6 */ WEBDAV_CTYPE_UTF8CONT,
- /* xb7 */ WEBDAV_CTYPE_UTF8CONT,
- /* xb8 */ WEBDAV_CTYPE_UTF8CONT,
- /* xb9 */ WEBDAV_CTYPE_UTF8CONT,
- /* xba */ WEBDAV_CTYPE_UTF8CONT,
- /* xbb */ WEBDAV_CTYPE_UTF8CONT,
- /* xbc */ WEBDAV_CTYPE_UTF8CONT,
- /* xbd */ WEBDAV_CTYPE_UTF8CONT,
- /* xbe */ WEBDAV_CTYPE_UTF8CONT,
- /* xbf */ WEBDAV_CTYPE_UTF8CONT,
- /* xc0 */ 0,
- /* xc1 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xc2 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xc3 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xc4 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xc5 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xc6 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xc7 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xc8 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xc9 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xca */ WEBDAV_CTYPE_UTF8LEAD,
- /* xcb */ WEBDAV_CTYPE_UTF8LEAD,
- /* xcc */ WEBDAV_CTYPE_UTF8LEAD,
- /* xcd */ WEBDAV_CTYPE_UTF8LEAD,
- /* xce */ WEBDAV_CTYPE_UTF8LEAD,
- /* xcf */ WEBDAV_CTYPE_UTF8LEAD,
- /* xd0 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xd1 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xd2 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xd3 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xd4 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xd5 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xd6 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xd7 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xd8 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xd9 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xda */ WEBDAV_CTYPE_UTF8LEAD,
- /* xdb */ WEBDAV_CTYPE_UTF8LEAD,
- /* xdc */ WEBDAV_CTYPE_UTF8LEAD,
- /* xdd */ WEBDAV_CTYPE_UTF8LEAD,
- /* xde */ WEBDAV_CTYPE_UTF8LEAD,
- /* xdf */ WEBDAV_CTYPE_UTF8LEAD,
- /* xe0 */ 0,
- /* xe1 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xe2 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xe3 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xe4 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xe5 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xe6 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xe7 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xe8 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xe9 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xea */ WEBDAV_CTYPE_UTF8LEAD,
- /* xeb */ WEBDAV_CTYPE_UTF8LEAD,
- /* xec */ WEBDAV_CTYPE_UTF8LEAD,
- /* xed */ WEBDAV_CTYPE_UTF8LEAD,
- /* xee */ WEBDAV_CTYPE_UTF8LEAD,
- /* xef */ WEBDAV_CTYPE_UTF8LEAD,
- /* xf0 */ 0,
- /* xf1 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xf2 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xf3 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xf4 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xf5 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xf6 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xf7 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xf8 */ 0,
- /* xf9 */ WEBDAV_CTYPE_UTF8LEAD,
- /* xfa */ WEBDAV_CTYPE_UTF8LEAD,
- /* xfb */ WEBDAV_CTYPE_UTF8LEAD,
- /* xfc */ 0,
- /* xfd */ WEBDAV_CTYPE_UTF8LEAD,
- /* xfe */ 0,
- /* xff */ 0
- };
- const apr_uint32_t * const ctype_table = ctype_table_internal;
- static const unsigned char casefold_table[256] =
- {
- // Identity, except {97:122} => {65:90}
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
- 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
- 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
- 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
- 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,123,124,125,126,127,
- 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
- 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
- 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
- 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
- 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
- 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
- 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
- 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
- };
- static int
- ctype_casecmp(int a, int b)
- {
- const int A = casefold_table[(unsigned char)a];
- const int B = casefold_table[(unsigned char)b];
- return A - B;
- }
- //------------------------------------------------------------------------------
- // from svn_pool.c
- // Pool allocation handler which just aborts, since we aren't generally
- // prepared to deal with out-of-memory errors.
- static int
- abort_on_pool_failure(int retcode)
- {
- // Don't translate this string! It requires memory allocation to do so!
- // And we don't have any of it...
- printf("Out of memory - terminating application.\n");
- abort();
- }
- static apr_pool_t *
- pool_create_ex(
- apr_pool_t * parent_pool,
- apr_allocator_t * allocator)
- {
- apr_pool_t * pool;
- apr_pool_create_ex(&pool, parent_pool, abort_on_pool_failure, allocator);
- return pool;
- }
- //------------------------------------------------------------------------------
- // from time.c
- #define OLD_TIMESTAMP_FORMAT \
- "%3s %d %3s %d %02d:%02d:%02d.%06d (day %03d, dst %d, gmt_off %06d)"
- static apr_size_t
- find_matching_string(
- char * str,
- apr_size_t size,
- const char strings[][4])
- {
- for (apr_size_t i = 0; i < size; i++)
- if (strings[i] && (strcmp(str, strings[i]) == 0))
- return i;
- return (apr_size_t)-1;
- }
- static error_t
- time_from_cstring(
- apr_time_t * when,
- const char * data,
- apr_pool_t * pool)
- {
- apr_time_exp_t exploded_time;
- apr_status_t apr_err = 0;
- char wday[4] = {0}, month[4] = {0};
- char * c = NULL;
- // Open-code parsing of the new timestamp format, as this
- // is a hot path for reading the entries file. This format looks
- // like: "2001-08-31T04:24:14.966996Z"
- exploded_time.tm_year = strtol(data, &c, 10);
- if (*c++ != '-') goto fail;
- exploded_time.tm_mon = strtol(c, &c, 10);
- if (*c++ != '-') goto fail;
- exploded_time.tm_mday = strtol(c, &c, 10);
- if (*c++ != 'T') goto fail;
- exploded_time.tm_hour = strtol(c, &c, 10);
- if (*c++ != ':') goto fail;
- exploded_time.tm_min = strtol(c, &c, 10);
- if (*c++ != ':') goto fail;
- exploded_time.tm_sec = strtol(c, &c, 10);
- if (*c != 'Z')
- {
- if (*c++ != '.') goto fail;
- exploded_time.tm_usec = strtol(c, &c, 10);
- if (*c++ != 'Z') goto fail;
- }
- exploded_time.tm_year -= 1900;
- exploded_time.tm_mon -= 1;
- exploded_time.tm_wday = 0;
- exploded_time.tm_yday = 0;
- exploded_time.tm_isdst = 0;
- exploded_time.tm_gmtoff = 0;
- apr_err = apr_time_exp_gmt_get(when, &exploded_time);
- if (apr_err == APR_SUCCESS)
- return WEBDAV_NO_ERROR;
- return error_createf(WEBDAV_ERR_BAD_DATE, NULL, "error parsing date: %s", data);
- fail:
- // 2012-09-11T14:18:40+07:00
- char gmt_shift = 0;
- int gmt_hour = 0;
- int gmt_min = 0;
- if (sscanf(data,
- "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
- &exploded_time.tm_year,
- &exploded_time.tm_mon,
- &exploded_time.tm_mday,
- &exploded_time.tm_hour,
- &exploded_time.tm_min,
- &exploded_time.tm_sec,
- &gmt_shift,
- &gmt_hour,
- &gmt_min) == 9)
- {
- exploded_time.tm_year -= 1900;
- exploded_time.tm_mon -= 1;
- exploded_time.tm_wday = 0;
- exploded_time.tm_yday = 0;
- exploded_time.tm_isdst = 0;
- exploded_time.tm_gmtoff = (gmt_shift == '-' ? -1 : 1) * gmt_hour * SecsPerHour + gmt_min * SecsPerMin;
- exploded_time.tm_usec = 0;
- apr_err = apr_time_exp_gmt_get(when, &exploded_time);
- if (apr_err != APR_SUCCESS)
- return error_createf(WEBDAV_ERR_BAD_DATE, NULL, "error parsing date: %s", data);
- return WEBDAV_NO_ERROR;
- }
- // 2012-09-11T03:56:20
- if (sscanf(data,
- "%04d-%02d-%02dT%02d:%02d:%02d",
- &exploded_time.tm_year,
- &exploded_time.tm_mon,
- &exploded_time.tm_mday,
- &exploded_time.tm_hour,
- &exploded_time.tm_min,
- &exploded_time.tm_sec) == 6)
- {
- exploded_time.tm_year -= 1900;
- exploded_time.tm_mon -= 1;
- exploded_time.tm_wday = 0;
- exploded_time.tm_yday = 0;
- exploded_time.tm_isdst = 0;
- exploded_time.tm_gmtoff = 0;
- exploded_time.tm_usec = 0;
- apr_err = apr_time_exp_gmt_get(when, &exploded_time);
- if (apr_err != APR_SUCCESS)
- return error_createf(WEBDAV_ERR_BAD_DATE, NULL, "error parsing date: %s", data);
- return WEBDAV_NO_ERROR;
- }
- // Try the compatibility option. This does not need to be fast,
- // as this format is no longer generated and the client will convert
- // an old-format entries file the first time it reads it.
- if (sscanf(data,
- OLD_TIMESTAMP_FORMAT,
- wday,
- &exploded_time.tm_mday,
- month,
- &exploded_time.tm_year,
- &exploded_time.tm_hour,
- &exploded_time.tm_min,
- &exploded_time.tm_sec,
- &exploded_time.tm_usec,
- &exploded_time.tm_yday,
- &exploded_time.tm_isdst,
- &exploded_time.tm_gmtoff) == 11)
- {
- exploded_time.tm_year -= 1900;
- exploded_time.tm_yday -= 1;
- // Using hard coded limits for the arrays - they are going away
- // soon in any case.
- exploded_time.tm_wday = (apr_int32_t)find_matching_string(wday, 7, apr_day_snames);
- exploded_time.tm_mon = (apr_int32_t)find_matching_string(month, 12, apr_month_snames);
- apr_err = apr_time_exp_gmt_get(when, &exploded_time);
- if (apr_err != APR_SUCCESS)
- return error_createf(WEBDAV_ERR_BAD_DATE, NULL, "error parsing date: %s", data);
- return WEBDAV_NO_ERROR;
- }
- // Timestamp is something we do not recognize.
- // return error_createf(WEBDAV_ERR_BAD_DATE, NULL, "error parsing date: %s", data);
- *when = apr_time_now();
- return WEBDAV_NO_ERROR;
- }
- //------------------------------------------------------------------------------
- // from path.c
- // TRUE if s is the canonical empty path, FALSE otherwise
- #define WEBDAV_PATH_IS_EMPTY(s) ((s)[0] == '\0')
- // TRUE if s,n is the platform's empty path ("."), FALSE otherwise. Can
- // this be changed? Well, the path library will work, not so sure about
- // the OS!
- #define WEBDAV_PATH_IS_PLATFORM_EMPTY(s,n) ((n) == 1 && (s)[0] == '.')
- /* Here is the BNF for path components in a URI. "pchar" is a
- character in a path component.
- pchar = unreserved | escaped |
- ":" | "@" | "&" | "=" | "+" | "$" | ","
- unreserved = alphanum | mark
- mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
- Note that "escaped" doesn't really apply to what users can put in
- their paths, so that really means the set of characters is:
- alphanum | mark | ":" | "@" | "&" | "=" | "+" | "$" | ","
- */
- static const char uri_char_validity[256] =
- {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0,
- // 64
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0,
- // 128
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- // 192
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- };
- // URI-encode each character c in PATH for which TABLE[c] is 0.
- // If no encoding was needed, return PATH, else return a new string allocated
- // in POOL.
- static const char *
- uri_escape(
- const char * path,
- const char table[],
- apr_pool_t * pool)
- {
- stringbuf_t * retstr = NULL;
- size_t i = 0, copied = 0;
- int c = 0;
- retstr = stringbuf_create_ensure(strlen(path), pool);
- for (i = 0; path[i]; i++)
- {
- c = (unsigned char)path[i];
- if (table[c])
- continue;
- // If we got here, we're looking at a character that isn't
- // supported by the (or at least, our) URI encoding scheme. We
- // need to escape this character.
- // First things first, copy all the good stuff that we haven't
- // yet copied into our output buffer.
- if (i - copied)
- stringbuf_appendbytes(retstr, path + copied,
- i - copied);
- // Now, write in our escaped character, consisting of the
- // '%' and two digits. We cast the C to unsigned char here because
- // the 'X' format character will be tempted to treat it as an unsigned
- // int...which causes problem when messing with 0x80-0xFF chars.
- // We also need space for a null as apr_snprintf will write one.
- stringbuf_ensure(retstr, retstr->len + 4);
- apr_snprintf(retstr->data + retstr->len, 4, "%%%02X", (unsigned char)c);
- retstr->len += 3;
- // Finally, update our copy counter.
- copied = i + 1;
- }
- // If we didn't encode anything, we don't need to duplicate the string.
- if (retstr->len == 0)
- return path;
- // Anything left to copy?
- if (i - copied)
- stringbuf_appendbytes(retstr, path + copied, i - copied);
- // retstr is null-terminated either by apr_snprintf or the stringbuf
- // functions.
- return retstr->data;
- }
- static const char *
- path_uri_decode(
- const char * path,
- apr_pool_t * pool)
- {
- stringbuf_t * retstr = NULL;
- size_t i = 0;
- bool query_start = FALSE;
- // avoid repeated realloc
- retstr = stringbuf_create_ensure(strlen(path) + 1, pool);
- retstr->len = 0;
- for (i = 0; path[i]; i++)
- {
- char c = path[i];
- if (c == '?')
- {
- // Mark the start of the query string, if it exists.
- query_start = TRUE;
- }
- else if (c == '+' && query_start)
- {
- // Only do this if we are into the query string.
- // RFC 2396, section 3.3
- c = ' ';
- }
- else if (c == '%' && ctype_isxdigit(path[i + 1]) && ctype_isxdigit(path[i+2]))
- {
- char digitz[3];
- digitz[0] = path[++i];
- digitz[1] = path[++i];
- digitz[2] = '\0';
- c = (char)(strtol(digitz, NULL, 16));
- }
- retstr->data[retstr->len++] = c;
- }
- // Null-terminate this bad-boy.
- retstr->data[retstr->len] = 0;
- return retstr->data;
- }
- static const char *
- path_uri_encode(
- const char * path,
- apr_pool_t * pool)
- {
- const char * ret = uri_escape(path, uri_char_validity, pool);
- // Our interface guarantees a copy.
- if (ret == path)
- return apr_pstrdup(pool, path);
- else
- return ret;
- }
- static char *
- path_join(
- const char * base,
- const char * component,
- apr_pool_t * pool)
- {
- apr_size_t blen = strlen(base);
- apr_size_t clen = strlen(component);
- char * path = NULL;
- // assert(path_is_canonical(base, pool));
- // assert(path_is_canonical(component, pool));
- // If the component is absolute, then return it.
- if (*component == '/')
- return (char *)apr_pmemdup(pool, component, clen + 1);
- // If either is empty return the other
- if (WEBDAV_PATH_IS_EMPTY(base))
- return (char *)apr_pmemdup(pool, component, clen + 1);
- if (WEBDAV_PATH_IS_EMPTY(component))
- return (char *)apr_pmemdup(pool, base, blen + 1);
- if ((blen == 1) && (base[0] == '/'))
- blen = 0; // Ignore base, just return separator + component
- // Construct the new, combined path.
- path = (char *)apr_pcalloc(pool, blen + 1 + clen + 1);
- memcpy(path, base, blen);
- path[blen] = '/';
- memcpy(path + blen + 1, component, clen + 1);
- return path;
- }
- static const char *
- path_url_add_component2(
- const char * url,
- const char * component,
- apr_pool_t * pool)
- {
- // = path_uri_encode() but without always copying
- component = uri_escape(component, uri_char_validity, pool);
- return path_join(url, component, pool);
- }
- // Get APR's internal path encoding.
- static error_t
- get_path_encoding(
- bool * path_is_utf8,
- apr_pool_t * pool)
- {
- apr_status_t apr_err = 0;
- int encoding_style = 0;
- apr_err = apr_filepath_encoding(&encoding_style, pool);
- if (apr_err)
- return error_wrap_apr(apr_err,
- "Can't determine the native path encoding");
- // What to do about APR_FILEPATH_ENCODING_UNKNOWN?
- // Well, for now we'll just punt to the utf_ functions;
- // those will at least do the ASCII-subset check.
- *path_is_utf8 = (encoding_style == APR_FILEPATH_ENCODING_UTF8);
- return WEBDAV_NO_ERROR;
- }
- static error_t
- path_cstring_to_utf8(
- const char ** path_utf8,
- const char * path_apr,
- apr_pool_t * pool)
- {
- bool path_is_utf8 = FALSE;
- WEBDAV_ERR(get_path_encoding(&path_is_utf8, pool));
- if (path_is_utf8)
- {
- *path_utf8 = apr_pstrdup(pool, path_apr);
- return WEBDAV_NO_ERROR;
- }
- else
- return utf_cstring_to_utf8(path_utf8, path_apr, pool);
- }
- static apr_size_t
- path_component_count(
- const char * path)
- {
- if (!path) return 0;
- apr_size_t count = 0;
- while (*path)
- {
- const char * start;
- while (*path == '/')
- ++path;
- start = path;
- while (*path && (*path != '/'))
- ++path;
- if (path != start)
- ++count;
- }
- return count;
- }
- // Return the length of substring necessary to encompass the entire
- // previous path segment in PATH, which should be a LEN byte string.
- // A trailing slash will not be included in the returned length except
- // in the case in which PATH is absolute and there are no more
- // previous segments.
- static apr_size_t
- previous_segment(
- const char * path,
- apr_size_t len)
- {
- if (len == 0)
- return 0;
- while ((len > 0) && (path[--len] != '/'))
- ;
- if ((len == 0) && (path[0] == '/'))
- return 1;
- else
- return len;
- }
- static void
- path_remove_component(
- stringbuf_t * path)
- {
- path->len = previous_segment(path->data, path->len);
- path->data[path->len] = '\0';
- }
- static void
- path_remove_components(
- stringbuf_t * path,
- apr_size_t n)
- {
- while (n > 0)
- {
- path_remove_component(path);
- n--;
- }
- }
- static error_t
- path_cstring_from_utf8(
- const char ** path_apr,
- const char * path_utf8,
- apr_pool_t * pool)
- {
- bool path_is_utf8 = FALSE;
- WEBDAV_ERR(get_path_encoding(&path_is_utf8, pool));
- if (path_is_utf8)
- {
- *path_apr = apr_pstrdup(pool, path_utf8);
- return WEBDAV_NO_ERROR;
- }
- else
- return utf_cstring_from_utf8(path_apr, path_utf8, pool);
- }
- static bool
- path_is_backpath_present(
- const char * path)
- {
- size_t len;
- // 0 and 1-length paths do not have a backpath
- if ((path[0] == '\0') || (path[1] == '\0'))
- return FALSE;
- // Handle ".." or a leading "../"
- if ((path[0] == '.') && (path[1] == '.') && ((path[2] == '\0') || (path[2] == '/')))
- return TRUE;
- // Paths of length 2 (at this point) have no backpath present.
- if (path[2] == '\0')
- return FALSE;
- // If any segment is "..", then a backpath is present.
- if (strstr(path, "/../") != NULL)
- return TRUE;
- // Does the path end in "/.." ?
- len = strlen(path);
- return (path[len - 3] == '/') && (path[len - 2] == '.') && (path[len - 1] == '.');
- }
- //------------------------------------------------------------------------------
- // from svn_client.h
- typedef error_t (*client_list_func_t)(
- void * baton,
- const char * path,
- const dirent_t * dirent,
- const char * abs_path,
- apr_pool_t * pool);
- typedef struct client_ctx_t
- {
- auth_baton_t * auth_baton;
- cancel_func_t cancel_func;
- void * cancel_baton;
- progress_notify_func_t progress_func;
- void * progress_baton;
- const char * client_name;
- } client_ctx_t;
- //------------------------------------------------------------------------------
- // from win32_xlate.c
- static apr_status_t
- subr_win32_xlate_to_stringbuf(// win32_xlate_t *handle,
- const char * src_data,
- apr_size_t src_length,
- stringbuf_t ** dest,
- apr_pool_t * pool)
- {
- WCHAR * wide_str = NULL;
- int retval = 0, wide_size = 0;
- if (src_length == 0)
- {
- *dest = stringbuf_create("", pool);
- return APR_SUCCESS;
- }
- int from_page_id = CP_ACP;
- retval = MultiByteToWideChar(from_page_id, // CP_UTF8, // handle->from_page_id,
- 0, src_data, (int)src_length, NULL, 0);
- if (retval == 0)
- return apr_get_os_error();
- wide_size = retval;
- // Allocate temporary buffer for small strings on stack instead of heap.
- if (wide_size <= MAX_PATH)
- {
- wide_str = static_cast<WCHAR *>(alloca(wide_size * sizeof(WCHAR)));
- }
- else
- {
- wide_str = static_cast<WCHAR *>(apr_pcalloc(pool, wide_size * sizeof(WCHAR)));
- }
- retval = MultiByteToWideChar(from_page_id, // handle->from_page_id,
- 0, src_data, (int)src_length, wide_str, wide_size);
- if (retval == 0)
- return apr_get_os_error();
- int to_page_id = CP_UTF8;
- retval = WideCharToMultiByte(to_page_id, // handle->to_page_id,
- 0, wide_str, wide_size, NULL, 0, NULL, NULL);
- if (retval == 0)
- return apr_get_os_error();
- // Ensure that buffer is enough to hold result string and termination
- // character.
- *dest = stringbuf_create_ensure(retval + 1, pool);
- (*dest)->len = retval;
- retval = WideCharToMultiByte(to_page_id, // handle->to_page_id,
- 0, wide_str, wide_size, (*dest)->data, (int)(*dest)->len, NULL, NULL);
- if (retval == 0)
- return apr_get_os_error();
- (*dest)->len = retval;
- return APR_SUCCESS;
- }
- static apr_status_t
- utf8_to_unicode(
- WCHAR ** retstr,
- const char * srcstr,
- apr_pool_t * pool)
- {
- /*apr_size_t retlen = 0;
- apr_size_t srcremains = strlen(srcstr) + 1;
- *retstr = static_cast<WCHAR *>(apr_pcalloc(pool, srcremains * 4));
- apr_status_t rv;
- if (rv = apr_conv_utf8_to_ucs2(srcstr, &srcremains, *retstr, &retlen)) {
- return (rv == APR_INCOMPLETE) ? APR_EINVAL : rv;
- }
- if (srcremains) {
- return APR_ENAMETOOLONG;
- }*/
- WCHAR * wide_str = NULL;
- int retval = 0, wide_size = 0;
- apr_size_t src_length = strlen(srcstr);
- if (src_length == 0)
- {
- *retstr = L"";
- return APR_SUCCESS;
- }
- retval = MultiByteToWideChar(CP_UTF8, // handle->from_page_id,
- 0, srcstr, (int)src_length, NULL, 0);
- if (retval == 0)
- return apr_get_os_error();
- wide_size = retval;
- wide_str = static_cast<WCHAR *>(apr_pcalloc(pool, (wide_size + 1) * sizeof(WCHAR)));
- retval = MultiByteToWideChar(CP_UTF8, // handle->from_page_id,
- 0, srcstr, (int)src_length, wide_str, wide_size);
- if (retval == 0)
- return apr_get_os_error();
- *retstr = wide_str;
- (*retstr)[wide_size] = L'\0';
- return APR_SUCCESS;
- }
- //------------------------------------------------------------------------------
- // from utf.c
- // Verify that the sequence DATA of length LEN is valid UTF-8.
- // If it is not, return an error with code APR_EINVAL.
- static error_t
- check_utf8(
- const char * data,
- apr_size_t len,
- apr_pool_t * pool)
- {
- // TODO: if (!utf_is_valid(data, len)))
- // return invalid_utf8(data, len, pool);
- return WEBDAV_NO_ERROR;
- }
- // Convert SRC_LENGTH bytes of SRC_DATA in NODE->handle, store the result
- // in *DEST, which is allocated in POOL.
- static error_t
- convert_to_stringbuf(// xlate_handle_node_t *node,
- const char * src_data,
- apr_size_t src_length,
- stringbuf_t ** dest,
- apr_pool_t * pool)
- {
- apr_status_t apr_err = 0;
- apr_err = subr_win32_xlate_to_stringbuf(// (win32_xlate_t *) node->handle,
- src_data, src_length,
- dest, pool);
- // If we exited the loop with an error, return the error.
- if (apr_err)
- {
- const char * errstr = NULL;
- error_t err = 0;
- // Can't use error_wrap_apr here because it calls functions in
- // this file, leading to infinite recursion.
- errstr = apr_psprintf(pool, "Can't convert string"); // from native encoding to '%s':"),
- err = error_create(apr_err, NULL, "");
- return error_create(apr_err, &err, errstr);
- }
- // Else, exited due to success. Trim the result buffer down to the
- // right length.
- (*dest)->data[(*dest)->len] = '\0';
- return WEBDAV_NO_ERROR;
- }
- // Common implementation for utf_cstring_to_utf8,
- // utf_cstring_to_utf8_ex, utf_cstring_from_utf8 and
- // utf_cstring_from_utf8_ex. Convert SRC to DEST using NODE->handle as
- // the translator and allocating from POOL.
- static error_t
- convert_cstring(
- const char ** dest,
- const char * src,
- apr_pool_t * pool)
- {
- stringbuf_t * destbuf;
- WEBDAV_ERR(convert_to_stringbuf(// node,
- src, strlen(src), &destbuf, pool));
- *dest = destbuf->data;
- return WEBDAV_NO_ERROR;
- }
- // Verify that the NULL terminated sequence DATA is valid UTF-8.
- // If it is not, return an error with code APR_EINVAL.
- static error_t
- check_cstring_utf8(
- const char * data,
- apr_pool_t * pool)
- {
- // TODO: if (!utf_cstring_is_valid(data))
- // return invalid_utf8(data, strlen(data), pool);
- return WEBDAV_NO_ERROR;
- }
- static error_t
- utf_cstring_to_utf8(
- const char ** dest,
- const char * src,
- apr_pool_t * pool)
- {
- // TODO: implement
- error_t err = convert_cstring(dest, src, // node,
- pool);
- WEBDAV_ERR(err);
- return check_cstring_utf8(*dest, pool);
- }
- static error_t
- utf_cstring_from_utf8(
- const char ** dest,
- const char * src,
- apr_pool_t * pool)
- {
- WEBDAV_ERR(check_utf8(src, strlen(src), pool));
- error_t err = convert_cstring(dest, src, pool);
- return err;
- }
- //------------------------------------------------------------------------------
- // from xml.c
- static const char *
- xml_get_attr_value(
- const char * name,
- const char ** atts)
- {
- while (atts && (*atts))
- {
- if (strcmp(atts[0], name) == 0)
- return atts[1];
- else
- atts += 2; // continue looping
- }
- // Else no such attribute name seen.
- return NULL;
- }
- //------------------------------------------------------------------------------
- // from apr_base64.c
- static const char basis_64[] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- // This is the same as apr_base64_encode() except on EBCDIC machines, where
- // the conversion of the input to ascii is left out.
- static int
- apr_base64_encode_binary(
- char * encoded,
- const unsigned char * string,
- int len)
- {
- int i;
- char * p;
- p = encoded;
- for (i = 0; i < len - 2; i += 3)
- {
- *p++ = basis_64[(string[i] >> 2) & 0x3F];
- *p++ = basis_64[((string[i] & 0x3) << 4) |
- ((int)(string[i + 1] & 0xF0) >> 4)];
- *p++ = basis_64[((string[i + 1] & 0xF) << 2) |
- ((int)(string[i + 2] & 0xC0) >> 6)];
- *p++ = basis_64[string[i + 2] & 0x3F];
- }
- if (i < len)
- {
- *p++ = basis_64[(string[i] >> 2) & 0x3F];
- if (i == (len - 1))
- {
- *p++ = basis_64[((string[i] & 0x3) << 4)];
- *p++ = '=';
- }
- else
- {
- *p++ = basis_64[((string[i] & 0x3) << 4) |
- ((int)(string[i + 1] & 0xF0) >> 4)];
- *p++ = basis_64[((string[i + 1] & 0xF) << 2)];
- }
- *p++ = '=';
- }
- *p++ = '\0';
- return (int)(p - encoded);
- }
- static int
- apr_base64_encode(
- char * encoded,
- const char * string,
- int len)
- {
- return apr_base64_encode_binary(encoded, (const unsigned char *) string, len);
- }
- static int
- apr_base64_encode_len(int len)
- {
- return ((len + 2) / 3 * 4) + 1;
- }
- // aaaack but it's fast and const should make it shared text page.
- static const unsigned char pr2six[256] =
- {
- // ASCII table
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
- 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
- 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
- 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
- };
- static int
- apr_base64_decode_len(
- const char * bufcoded)
- {
- int nbytesdecoded;
- register const unsigned char * bufin;
- register apr_size_t nprbytes;
- bufin = (const unsigned char *) bufcoded;
- while (pr2six[*(bufin++)] <= 63);
- nprbytes = (bufin - (const unsigned char *) bufcoded) - 1;
- nbytesdecoded = (((int)nprbytes + 3) / 4) * 3;
- return nbytesdecoded + 1;
- }
- // This is the same as apr_base64_decode() except on EBCDIC machines, where
- // the conversion of the output to ebcdic is left out.
- static int
- apr_base64_decode_binary(
- unsigned char * bufplain,
- const char * bufcoded)
- {
- int nbytesdecoded;
- register const unsigned char * bufin;
- register unsigned char * bufout;
- register apr_size_t nprbytes;
- bufin = (const unsigned char *) bufcoded;
- while (pr2six[*(bufin++)] <= 63);
- nprbytes = (bufin - (const unsigned char *) bufcoded) - 1;
- nbytesdecoded = (((int)nprbytes + 3) / 4) * 3;
- bufout = (unsigned char *) bufplain;
- bufin = (const unsigned char *) bufcoded;
- while (nprbytes > 4)
- {
- *(bufout++) =
- (unsigned char)((pr2six[*bufin] << 2) | (pr2six[bufin[1]] >> 4));
- *(bufout++) =
- (unsigned char)((pr2six[bufin[1]] << 4) | (pr2six[bufin[2]] >> 2));
- *(bufout++) =
- (unsigned char)((pr2six[bufin[2]] << 6) | pr2six[bufin[3]]);
- bufin += 4;
- nprbytes -= 4;
- }
- // Note: (nprbytes == 1) would be an error, so just ignore that case
- if (nprbytes > 1)
- {
- *(bufout++) =
- (unsigned char)((pr2six[*bufin] << 2) | (pr2six[bufin[1]] >> 4));
- }
- if (nprbytes > 2)
- {
- *(bufout++) =
- (unsigned char)((pr2six[bufin[1]] << 4) | (pr2six[bufin[2]] >> 2));
- }
- if (nprbytes > 3)
- {
- *(bufout++) =
- (unsigned char)((pr2six[bufin[2]] << 6) | pr2six[bufin[3]]);
- }
- nbytesdecoded -= (4 - (int)nprbytes) & 3;
- return nbytesdecoded;
- }
- static int
- apr_base64_decode(
- char * bufplain,
- const char * bufcoded)
- {
- int len = apr_base64_decode_binary((unsigned char *) bufplain, bufcoded);
- bufplain[len] = '\0';
- return len;
- }
- //---------------------------------------------------------------------------
- // from user.c
- // Get the current user's name from the OS
- static const char *
- get_os_username(
- apr_pool_t * pool)
- {
- #if APR_HAS_USER
- char * username;
- apr_uid_t uid;
- apr_gid_t gid;
- if (apr_uid_current(&uid, &gid, pool) == APR_SUCCESS &&
- apr_uid_name_get(&username, uid, pool) == APR_SUCCESS)
- return username;
- #endif
- return NULL;
- }
- // Return a UTF8 version of STR, or NULL on error.
- // Use POOL for any necessary allocation.
- static const char *
- utf8_or_nothing(
- const char * str,
- apr_pool_t * pool)
- {
- if (str)
- {
- const char * utf8_str;
- error_t err = utf_cstring_to_utf8(&utf8_str, str, pool);
- if (!err)
- return utf8_str;
- error_clear(&err);
- }
- return NULL;
- }
- static const char *
- user_get_name(
- apr_pool_t * pool)
- {
- const char * username = get_os_username(pool);
- return utf8_or_nothing(username, pool);
- }
- //---------------------------------------------------------------------------
- // from sorts.c
- typedef struct sort_item_t
- {
- const void * key;
- apr_ssize_t klen;
- void * value;
- } sort_item_t;
- static int
- sort_compare_items_lexically(
- const sort_item_t * a,
- const sort_item_t * b)
- {
- // Compare bytes of a's key and b's key up to the common length.
- apr_size_t len = (a->klen < b->klen) ? a->klen : b->klen;
- int val = memcmp(a->key, b->key, len);
- if (val != 0)
- return val;
- // They match up until one of them ends; whichever is longer is greater.
- return (a->klen < b->klen) ? -1 : (a->klen > b->klen) ? 1 : 0;
- }
- static apr_array_header_t *
- sort_hash(apr_hash_t * ht,
- int (*comparison_func)(const sort_item_t *,
- const sort_item_t *),
- apr_pool_t * pool)
- {
- apr_array_header_t * ary = NULL;
- bool sorted = FALSE;
- sort_item_t * prev_item = NULL;
- // allocate an array with enough elements to hold all the keys.
- ary = apr_array_make(pool, apr_hash_count(ht), sizeof(sort_item_t));
- // loop over hash table and push all keys into the array
- sorted = TRUE;
- prev_item = NULL;
- for (apr_hash_index_t * hi = apr_hash_first(pool, ht); hi;
- hi = apr_hash_next(hi))
- {
- sort_item_t * item = static_cast<sort_item_t *>(apr_array_push(ary));
- apr_hash_this(hi, &item->key, &item->klen, &item->value);
- if (prev_item == NULL)
- {
- prev_item = item;
- continue;
- }
- if (sorted)
- {
- sorted = (comparison_func(prev_item, item) < 0);
- prev_item = item;
- }
- }
- // quicksort the array if it isn't already sorted.
- if (!sorted)
- qsort(ary->elts, ary->nelts, ary->elt_size,
- (int ( *)(const void *, const void *))comparison_func);
- return ary;
- }
- //---------------------------------------------------------------------------
- // from svn_config.h
- #define WEBDAV_CONFIG_TRUE "TRUE"
- #define WEBDAV_CONFIG_FALSE "FALSE"
- #define WEBDAV_CONFIG_ASK "ASK"
- // Default values for some options. Should be passed as default values
- // to config_get and friends, instead of hard-coding the defaults in
- // multiple places.
- #define WEBDAV_CONFIG_DEFAULT_OPTION_STORE_PASSWORDS TRUE
- #define WEBDAV_CONFIG_DEFAULT_OPTION_STORE_PLAINTEXT_PASSWORDS WEBDAV_CONFIG_ASK
- #define WEBDAV_CONFIG_DEFAULT_OPTION_STORE_AUTH_CREDS TRUE
- #define WEBDAV_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP TRUE
- #define WEBDAV_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT \
- WEBDAV_CONFIG_ASK
- //---------------------------------------------------------------------------
- // from svn_auth.h
- // Certificate is not yet valid.
- #define WEBDAV_AUTH_SSL_NOTYETVALID 0x00000001
- // Certificate has expired.
- #define WEBDAV_AUTH_SSL_EXPIRED 0x00000002
- // Certificate's CN (hostname) does not match the remote hostname.
- #define WEBDAV_AUTH_SSL_CNMISMATCH 0x00000004
- // Certificate authority is unknown (i.e. not trusted)
- #define WEBDAV_AUTH_SSL_UNKNOWNCA 0x00000008
- // Other failure. This can happen if neon has introduced a new
- // failure bit that we do not handle yet.
- #define WEBDAV_AUTH_SSL_OTHER 0x40000000
- #define AUTH_CRED_SSL_CLIENT_CERT_PW "ssl.client-passphrase"
- #define AUTH_CRED_SSL_CLIENT_CERT "ssl.client-cert"
- // The auth-hash prefix indicating that the parameter is global.
- #define AUTH_PARAM_PREFIX "webdav:auth:"
- // The following property is for SSL server cert providers. This
- // provides a pointer to an apr_uint32_t containing the failures
- // detected by the certificate validator.
- #define AUTH_PARAM_SSL_SERVER_FAILURES AUTH_PARAM_PREFIX \
- "ssl:failures"
- // The following property is for SSL server cert providers. This
- // provides the cert info (auth_ssl_server_cert_info_t).
- #define AUTH_PARAM_SSL_SERVER_CERT_INFO AUTH_PARAM_PREFIX \
- "ssl:cert-info"
- #define AUTH_CRED_SSL_SERVER_TRUST "webdav.ssl.server"
- #define AUTH_CRED_SIMPLE "webdav.simple"
- #define WEBDAV_AUTH_CRED_USERNAME "webdav.username"
- #define WEBDAV_AUTH_PARAM_DEFAULT_USERNAME AUTH_PARAM_PREFIX "username"
- #define WEBDAV_AUTH_PARAM_DEFAULT_PASSWORD AUTH_PARAM_PREFIX "password"
- #define WEBDAV_AUTH_PARAM_NON_INTERACTIVE AUTH_PARAM_PREFIX "non-interactive"
- #define WEBDAV_AUTH_PARAM_DONT_STORE_PASSWORDS AUTH_PARAM_PREFIX \
- "dont-store-passwords"
- #define WEBDAV_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS AUTH_PARAM_PREFIX \
- "store-plaintext-passwords"
- #define WEBDAV_AUTH_PARAM_DONT_STORE_SSL_CLIENT_CERT_PP \
- AUTH_PARAM_PREFIX "dont-store-ssl-client-cert-pp"
- #define WEBDAV_AUTH_PARAM_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT \
- AUTH_PARAM_PREFIX "store-ssl-client-cert-pp-plaintext"
- #define WEBDAV_AUTH_PARAM_NO_AUTH_CACHE AUTH_PARAM_PREFIX "no-auth-cache"
- #define WEBDAV_AUTH_SIMPLE_PASSWORD_TYPE "simple"
- #define WEBDAV_AUTH_WINCRYPT_PASSWORD_TYPE "wincrypt"
- // This effectively defines a single table. Every provider in this
- // array returns the same kind of credentials.
- typedef struct provider_set_t
- {
- // ordered array of auth_provider_object_t
- apr_array_header_t * providers;
- } provider_set_t;
- // Abstracted iteration baton
- struct auth_iterstate_t
- {
- provider_set_t * table; // the table being searched
- int provider_idx; // the current provider (row)
- bool got_first; // did we get the provider's first creds?
- void * provider_iter_baton; // the provider's own iteration context
- const char * realmstring; // The original realmstring passed in
- const char * cache_key; // key to use in auth_baton's creds_cache
- auth_baton_t * auth_baton; // the original auth_baton.
- };
- // The main auth baton.
- typedef struct auth_baton_t
- {
- // a collection of tables. maps cred_kind -> provider_set
- apr_hash_t * tables;
- // the pool I'm allocated in.
- apr_pool_t * pool;
- // run-time parameters needed by providers.
- apr_hash_t * parameters;
- // run-time credentials cache.
- apr_hash_t * creds_cache;
- } auth_baton_t;
- // The main authentication "provider" vtable.
- typedef struct auth_provider_t
- {
- // The kind of credentials this provider knows how to retrieve.
- const char * cred_kind;
- error_t (*first_credentials)(void ** credentials,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool);
- error_t (*next_credentials)(void ** credentials,
- void * iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool);
- error_t (*save_credentials)(bool * saved,
- void * credentials,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool);
- } auth_provider_t;
- // A provider object, ready to be put into an array and given to
- // create_baton_open().
- typedef struct auth_provider_object_t
- {
- const auth_provider_t * vtable;
- void * provider_baton;
- } auth_provider_object_t;
- typedef error_t (*auth_plaintext_prompt_func_t)(
- bool * may_save_plaintext,
- const char * realmstring,
- void * baton,
- apr_pool_t * pool);
- typedef error_t (*auth_password_get_t)(
- bool * done,
- const char ** password,
- apr_hash_t * creds,
- const char * realmstring,
- const char * username,
- apr_hash_t * parameters,
- bool non_interactive,
- apr_pool_t * pool);
- typedef struct auth_cred_simple_t
- {
- // Username
- const char * username;
- // Password
- const char * password;
- bool may_save;
- } auth_cred_simple_t;
- typedef struct auth_cred_username_t
- {
- // Username
- const char * username;
- bool may_save;
- } auth_cred_username_t;
- typedef error_t (*auth_password_set_t)(
- bool * done,
- apr_hash_t * creds,
- const char * realmstring,
- const char * username,
- const char * password,
- apr_hash_t * parameters,
- bool non_interactive,
- apr_pool_t * pool);
- // AUTH_CRED_SSL_CLIENT_CERT credentials.
- typedef struct auth_cred_ssl_client_cert_t
- {
- // Absolute path to the certificate file
- const char * cert_file;
- bool may_save;
- } auth_cred_ssl_client_cert_t;
- typedef error_t (*auth_ssl_client_cert_prompt_func_t)(
- auth_cred_ssl_client_cert_t ** cred,
- void * baton,
- const char * realm,
- bool may_save,
- apr_pool_t * pool);
- typedef error_t (*auth_plaintext_passphrase_prompt_func_t)(
- bool * may_save_plaintext,
- const char * realmstring,
- void * baton,
- apr_pool_t * pool);
- // AUTH_CRED_SSL_CLIENT_CERT_PW credentials.
- typedef struct auth_cred_ssl_client_cert_pw_t
- {
- // Certificate password
- const char * password;
- bool may_save;
- } auth_cred_ssl_client_cert_pw_t;
- // AUTH_CRED_SSL_SERVER_TRUST credentials.
- typedef struct auth_cred_ssl_server_trust_t
- {
- bool may_save;
- // Bit mask of the accepted failures
- apr_uint32_t accepted_failures;
- } auth_cred_ssl_server_trust_t;
- // SSL server certificate information used by
- // AUTH_CRED_SSL_SERVER_TRUST providers.
- typedef struct auth_ssl_server_cert_info_t
- {
- // Primary CN
- const char * hostname;
- // ASCII fingerprint
- const char * fingerprint;
- // ASCII date from which the certificate is valid
- const char * valid_from;
- // ASCII date until which the certificate is valid
- const char * valid_until;
- // DN of the certificate issuer
- const char * issuer_dname;
- // Base-64 encoded DER certificate representation
- const char * ascii_cert;
- } auth_ssl_server_cert_info_t;
- typedef error_t (*auth_ssl_client_cert_pw_prompt_func_t)(
- auth_cred_ssl_client_cert_pw_t ** cred,
- void * baton,
- const char * realm,
- bool may_save,
- apr_pool_t * pool);
- typedef error_t (*auth_ssl_server_trust_prompt_func_t)(
- auth_cred_ssl_server_trust_t ** cred,
- void * baton,
- const char * realm,
- apr_uint32_t failures,
- const auth_ssl_server_cert_info_t * cert_info,
- bool may_save,
- apr_pool_t * pool);
- typedef error_t (*auth_simple_prompt_func_t)(
- auth_cred_simple_t ** cred,
- void * baton,
- const char * realm,
- const char * username,
- bool may_save,
- apr_pool_t * pool);
- typedef error_t (*auth_username_prompt_func_t)(
- auth_cred_username_t ** cred,
- void * baton,
- const char * realm,
- bool may_save,
- apr_pool_t * pool);
- //---------------------------------------------------------------------------
- // from config_auth.c
- #define CONST_FS_KEY "fs"
- #define CONST_FINGERPRINT_KEY "fingerprint"
- // The keys that will be stored on disk. These serve the same role as
- // similar constants in other providers.
- #define AUTHN_ASCII_CERT_KEY "ascii_cert"
- #define AUTHN_FAILURES_KEY "failures"
- static const char CertificateStorageKey[] = "HttpsCertificates";
- static error_t
- config_read_auth_data(
- apr_hash_t ** hash,
- const char * cred_kind,
- const char * realmstring,
- TWebDAVFileSystem * fs,
- apr_pool_t * pool)
- {
- const char * subkey = CertificateStorageKey;
- THierarchicalStorage * Storage = NULL;
- WEBDAV_ERR(fs->CreateStorage(Storage));
- assert(Storage);
- std::auto_ptr<THierarchicalStorage> StoragePtr;
- StoragePtr.reset(Storage);
- Storage->AccessMode = smRead;
- if (!Storage->OpenSubKey(UnicodeString(subkey), false))
- return WEBDAV_ERR_BAD_PARAM;
- *hash = apr_hash_make(pool);
- TStrings * Keys = new TStringList();
- try
- {
- Storage->GetValueNames(Keys);
- for (int Index = 0; Index < Keys->Count; ++Index)
- {
- UnicodeString Key = Keys->Strings[Index];
- UnicodeString Value = Storage->ReadStringRaw(Key, L"");
- apr_hash_set(*hash, AUTHN_ASCII_CERT_KEY, APR_HASH_KEY_STRING,
- string_create(AnsiString(Key).c_str(), pool));
- apr_hash_set(*hash, AUTHN_FAILURES_KEY, APR_HASH_KEY_STRING,
- string_createf(pool, "%lu", (unsigned long)
- StrToIntDef(Value, 0)));
- }
- }
- __finally
- {
- delete Keys;
- }
- return WEBDAV_NO_ERROR;
- }
- static error_t
- config_write_auth_data(
- apr_hash_t * hash,
- const char * cred_kind,
- const char * realmstring,
- TWebDAVFileSystem * fs,
- apr_pool_t * pool)
- {
- const char * subkey = CertificateStorageKey;
- assert(fs);
- THierarchicalStorage * Storage = NULL;
- WEBDAV_ERR(fs->CreateStorage(Storage));
- assert(Storage);
- std::auto_ptr<THierarchicalStorage> StoragePtr;
- StoragePtr.reset(Storage);
- Storage->AccessMode = smReadWrite;
- if (!Storage->OpenSubKey(UnicodeString(subkey), true))
- return WEBDAV_ERR_BAD_PARAM;
- string_t * trusted_cert = static_cast<string_t *>(apr_hash_get(hash, AUTHN_ASCII_CERT_KEY,
- APR_HASH_KEY_STRING));
- string_t * failstr = static_cast<string_t *>(apr_hash_get(hash, AUTHN_FAILURES_KEY,
- APR_HASH_KEY_STRING));
- if (trusted_cert && failstr)
- Storage->WriteString(UnicodeString(trusted_cert->data), UnicodeString(failstr->data));
- return WEBDAV_NO_ERROR;
- }
- //---------------------------------------------------------------------------
- // from simple_providers.c
- // The keys that will be stored on disk. These serve the same role as
- // similar constants in other providers.
- #define AUTHN_USERNAME_KEY "username"
- #define AUTHN_PASSWORD_KEY "password"
- #define AUTHN_PASSTYPE_KEY "passtype"
- // Baton type for the simple provider.
- typedef struct simple_provider_baton_t
- {
- auth_plaintext_prompt_func_t plaintext_prompt_func;
- void * prompt_baton;
- // We cache the user's answer to the plaintext prompt, keyed
- // by realm, in case we'll be called multiple times for the
- // same realm.
- apr_hash_t * plaintext_answers;
- } simple_provider_baton_t;
- // Implementation of auth_password_get_t that retrieves
- // the plaintext password from CREDS.
- static error_t
- auth_simple_password_get(
- bool * done,
- const char ** password,
- apr_hash_t * creds,
- const char * realmstring,
- const char * username,
- apr_hash_t * parameters,
- bool non_interactive,
- apr_pool_t * pool)
- {
- *done = FALSE;
- string_t * str = static_cast<string_t *>(apr_hash_get(creds, AUTHN_USERNAME_KEY, APR_HASH_KEY_STRING));
- if (str && username && strcmp(str->data, username) == 0)
- {
- str = static_cast<string_t *>(apr_hash_get(creds, AUTHN_PASSWORD_KEY, APR_HASH_KEY_STRING));
- if (str && str->data)
- {
- *password = str->data;
- *done = TRUE;
- }
- }
- return WEBDAV_NO_ERROR;
- }
- // Implementation of auth_password_set_t that stores
- // the plaintext password in CREDS.
- static error_t
- auth_simple_password_set(
- bool * done,
- apr_hash_t * creds,
- const char * realmstring,
- const char * username,
- const char * password,
- apr_hash_t * parameters,
- bool non_interactive,
- apr_pool_t * pool)
- {
- apr_hash_set(creds, AUTHN_PASSWORD_KEY, APR_HASH_KEY_STRING,
- string_create(password, pool));
- *done = TRUE;
- return WEBDAV_NO_ERROR;
- }
- // Set **USERNAME to the username retrieved from CREDS; ignore
- // other parameters. *USERNAME will have the same lifetime as CREDS.
- static bool
- simple_username_get(
- const char ** username,
- apr_hash_t * creds,
- const char * realmstring,
- bool non_interactive)
- {
- string_t * str = static_cast<string_t *>(apr_hash_get(creds, AUTHN_USERNAME_KEY, APR_HASH_KEY_STRING));
- if (str && str->data)
- {
- *username = str->data;
- return TRUE;
- }
- return FALSE;
- }
- // Common implementation for simple_first_creds. Uses PARAMETERS, REALMSTRING
- // and the simple auth provider's username and password cache to fill a set of
- // CREDENTIALS. PASSWORD_GET is used to obtain the password value.
- // PASSTYPE identifies the type of the cached password. CREDENTIALS are
- // allocated from POOL.
- static error_t
- auth_simple_first_creds_helper(
- void ** credentials,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- auth_password_get_t password_get,
- const char * passtype,
- apr_pool_t * pool)
- {
- const char * username = static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_DEFAULT_USERNAME,
- APR_HASH_KEY_STRING));
- const char * password = static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_DEFAULT_PASSWORD,
- APR_HASH_KEY_STRING));
- bool non_interactive = apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_NON_INTERACTIVE,
- APR_HASH_KEY_STRING) != NULL;
- const char * default_username = NULL; // Default username from cache.
- const char * default_password = NULL; // Default password from cache.
- // This checks if we should save the CREDS, if saving the credentials is
- // allowed by the run-time configuration.
- bool need_to_save = FALSE;
- apr_hash_t * creds_hash = NULL;
- error_t err = 0;
- // Try to load credentials from a file on disk, based on the
- // realmstring. Don't throw an error, though: if something went
- // wrong reading the file, no big deal. What really matters is that
- // we failed to get the creds, so allow the auth system to try the
- // next provider.
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- err = config_read_auth_data(&creds_hash, AUTH_CRED_SIMPLE,
- realmstring, fs, pool);
- if (err)
- {
- error_clear(&err);
- err = NULL;
- }
- else if (creds_hash)
- {
- // We have something in the auth cache for this realm.
- bool have_passtype = FALSE;
- // The password type in the auth data must match the
- // mangler's type, otherwise the password must be
- // interpreted by another provider.
- string_t * str = static_cast<string_t *>(apr_hash_get(creds_hash, AUTHN_PASSTYPE_KEY, APR_HASH_KEY_STRING));
- if (str && str->data)
- if (passtype && (0 == strcmp(str->data, passtype)))
- have_passtype = TRUE;
- // See if we need to save this username if it is not present in
- // auth cache.
- if (username)
- {
- if (!simple_username_get(&default_username, creds_hash, realmstring,
- non_interactive))
- {
- need_to_save = TRUE;
- }
- else
- {
- if (0 == strcmp(default_username, username))
- need_to_save = FALSE;
- else
- need_to_save = TRUE;
- }
- }
- // See if we need to save this password if it is not present in
- // auth cache.
- if (password)
- {
- if (have_passtype)
- {
- bool done;
- WEBDAV_ERR(password_get(&done, &default_password, creds_hash, realmstring,
- username, parameters, non_interactive, pool));
- if (!done)
- {
- need_to_save = TRUE;
- }
- else
- {
- if (0 == strcmp(default_password, password))
- need_to_save = FALSE;
- else
- need_to_save = TRUE;
- }
- }
- }
- // If we don't have a username and a password yet, we try the
- // auth cache
- if (!(username && password))
- {
- if (!username)
- if (!simple_username_get(&username, creds_hash, realmstring,
- non_interactive))
- username = NULL;
- if (username && !password)
- {
- if (!have_passtype)
- password = NULL;
- else
- {
- bool done;
- WEBDAV_ERR(password_get(&done, &password, creds_hash, realmstring,
- username, parameters, non_interactive,
- pool));
- if (!done)
- password = NULL;
- // If the auth data didn't contain a password type,
- // force a write to upgrade the format of the auth
- // data file.
- if (password && !have_passtype)
- need_to_save = TRUE;
- }
- }
- }
- }
- else
- {
- // Nothing was present in the auth cache, so indicate that these
- // credentials should be saved.
- need_to_save = TRUE;
- }
- // Ask the OS for the username if we have a password but no username.
- if (password && !username)
- username = user_get_name(pool);
- if (username && password)
- {
- auth_cred_simple_t * creds = static_cast<auth_cred_simple_t *>(apr_pcalloc(pool, sizeof(*creds)));
- creds->username = username;
- creds->password = password;
- creds->may_save = need_to_save;
- *credentials = creds;
- }
- else
- *credentials = NULL;
- *iter_baton = NULL;
- return WEBDAV_NO_ERROR;
- }
- // Common implementation for simple_save_creds. Uses PARAMETERS and
- // REALMSTRING to save a set of CREDENTIALS to the simple auth provider's
- // username and password cache. PASSWORD_SET is used to store the password.
- // PASSTYPE identifies the type of the cached password. Allocates from POOL.
- static error_t
- auth_simple_save_creds_helper(
- bool * saved,
- void * credentials,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- auth_password_set_t password_set,
- const char * passtype,
- apr_pool_t * pool)
- {
- auth_cred_simple_t * creds = static_cast<auth_cred_simple_t *>(credentials);
- apr_hash_t * creds_hash = NULL;
- error_t err = 0;
- bool dont_store_passwords =
- apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_DONT_STORE_PASSWORDS,
- APR_HASH_KEY_STRING) != NULL;
- const char * store_plaintext_passwords = static_cast<const char *>(
- apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS,
- APR_HASH_KEY_STRING));
- bool non_interactive = apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_NON_INTERACTIVE,
- APR_HASH_KEY_STRING) != NULL;
- simple_provider_baton_t * b = (simple_provider_baton_t *)provider_baton;
- bool no_auth_cache = (!creds->may_save) ||
- (apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
- APR_HASH_KEY_STRING) != NULL);
- // Make sure we've been passed a passtype.
- WEBDAV_ERR_ASSERT(passtype != NULL);
- *saved = FALSE;
- if (no_auth_cache)
- return WEBDAV_NO_ERROR;
- // Put the username into the credentials hash.
- creds_hash = apr_hash_make(pool);
- apr_hash_set(creds_hash, AUTHN_USERNAME_KEY, APR_HASH_KEY_STRING,
- string_create(creds->username, pool));
- // Don't store passwords in any form if the user has told
- // us not to do so.
- if (!dont_store_passwords)
- {
- bool may_save_password = FALSE;
- // If the password is going to be stored encrypted, go right
- // ahead and store it to disk. Else determine whether saving
- // in plaintext is OK.
- if (passtype &&
- (strcmp(passtype, WEBDAV_AUTH_WINCRYPT_PASSWORD_TYPE) == 0))
- {
- may_save_password = TRUE;
- }
- else
- {
- if (store_plaintext_passwords && cstring_casecmp(store_plaintext_passwords,
- WEBDAV_CONFIG_ASK) == 0)
- {
- if (non_interactive)
- // In non-interactive mode, the default behaviour is
- // to not store the password, because it is usually
- // passed on the command line.
- may_save_password = FALSE;
- else if (b && b->plaintext_prompt_func)
- {
- // We're interactive, and the client provided a
- // prompt callback. So we can ask the user.
- // Check for a cached answer before prompting.
- bool * cached_answer;
- cached_answer = static_cast<bool *>(apr_hash_get(b->plaintext_answers,
- realmstring,
- APR_HASH_KEY_STRING));
- if (cached_answer != NULL)
- may_save_password = *cached_answer;
- else
- {
- apr_pool_t * cached_answer_pool;
- // Nothing cached for this realm, prompt the user.
- WEBDAV_ERR((*b->plaintext_prompt_func)(&may_save_password,
- realmstring,
- b->prompt_baton,
- pool));
- cached_answer_pool = apr_hash_pool_get(b->plaintext_answers);
- cached_answer = static_cast<bool *>(apr_pcalloc(cached_answer_pool,
- sizeof(bool)));
- *cached_answer = may_save_password;
- apr_hash_set(b->plaintext_answers, realmstring,
- APR_HASH_KEY_STRING, cached_answer);
- }
- }
- else
- {
- may_save_password = TRUE;
- }
- }
- else if (store_plaintext_passwords && cstring_casecmp(store_plaintext_passwords,
- WEBDAV_CONFIG_FALSE) == 0)
- {
- may_save_password = FALSE;
- }
- else if (store_plaintext_passwords && cstring_casecmp(store_plaintext_passwords,
- WEBDAV_CONFIG_TRUE) == 0)
- {
- may_save_password = TRUE;
- }
- else
- {
- /*return error_createf
- (WEBDAV_ERR_BAD_CONFIG_VALUE, NULL,
- "Config error: invalid value '%s' for option '%s'",
- store_plaintext_passwords,
- WEBDAV_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS);*/
- may_save_password = FALSE;
- }
- }
- if (may_save_password)
- {
- WEBDAV_ERR(password_set(saved, creds_hash, realmstring,
- creds->username, creds->password,
- parameters, non_interactive, pool));
- if (*saved && passtype)
- // Store the password type with the auth data, so that we
- // know which provider owns the password.
- apr_hash_set(creds_hash, AUTHN_PASSTYPE_KEY, APR_HASH_KEY_STRING,
- string_create(passtype, pool));
- }
- }
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- // Save credentials to disk.
- err = config_write_auth_data(creds_hash, AUTH_CRED_SIMPLE,
- realmstring, fs, pool);
- error_clear(&err);
- return WEBDAV_NO_ERROR;
- }
- // Get cached (unencrypted) credentials from the simple provider's cache.
- static error_t
- simple_first_creds(
- void ** credentials,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- return auth_simple_first_creds_helper(credentials,
- iter_baton,
- provider_baton,
- parameters,
- realmstring,
- auth_simple_password_get,
- WEBDAV_AUTH_SIMPLE_PASSWORD_TYPE,
- pool);
- }
- // Save (unencrypted) credentials to the simple provider's cache.
- static error_t
- simple_save_creds(
- bool * saved,
- void * credentials,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- return auth_simple_save_creds_helper(saved, credentials,
- provider_baton,
- parameters,
- realmstring,
- auth_simple_password_set,
- WEBDAV_AUTH_SIMPLE_PASSWORD_TYPE,
- pool);
- }
- static const auth_provider_t simple_provider =
- {
- AUTH_CRED_SIMPLE,
- simple_first_creds,
- NULL,
- simple_save_creds
- };
- // Public API
- static void
- auth_get_simple_provider2(
- auth_provider_object_t ** provider,
- auth_plaintext_prompt_func_t plaintext_prompt_func,
- void * prompt_baton,
- apr_pool_t * pool)
- {
- auth_provider_object_t * po = static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
- simple_provider_baton_t * pb = static_cast<simple_provider_baton_t *>(apr_pcalloc(pool, sizeof(*pb)));
- pb->plaintext_prompt_func = plaintext_prompt_func;
- pb->prompt_baton = prompt_baton;
- pb->plaintext_answers = apr_hash_make(pool);
- po->vtable = &simple_provider;
- po->provider_baton = pb;
- *provider = po;
- }
- // Baton type for username/password prompting.
- typedef struct simple_prompt_provider_baton_t
- {
- auth_simple_prompt_func_t prompt_func;
- void * prompt_baton;
- // how many times to re-prompt after the first one fails
- int retry_limit;
- } simple_prompt_provider_baton_t;
- // Iteration baton type for username/password prompting.
- typedef struct simple_prompt_iter_baton_t
- {
- // how many times we've reprompted
- int retries;
- } simple_prompt_iter_baton_t;
- // Helper Functions
- static error_t
- prompt_for_simple_creds(
- auth_cred_simple_t ** cred_p,
- simple_prompt_provider_baton_t * pb,
- apr_hash_t * parameters,
- const char * realmstring,
- bool first_time,
- bool may_save,
- apr_pool_t * pool)
- {
- const char * default_username = NULL;
- const char * default_password = NULL;
- *cred_p = NULL;
- // If we're allowed to check for default usernames and passwords, do so.
- if (first_time)
- {
- default_username = static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_DEFAULT_USERNAME,
- APR_HASH_KEY_STRING));
- // No default username? Try the auth cache.
- if (!default_username)
- {
- apr_hash_t * creds_hash = NULL;
- string_t * str;
- error_t err;
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- err = config_read_auth_data(&creds_hash, AUTH_CRED_SIMPLE,
- realmstring, fs, pool);
- error_clear(&err);
- if (!err && creds_hash)
- {
- str = static_cast<string_t *>(apr_hash_get(creds_hash, AUTHN_USERNAME_KEY,
- APR_HASH_KEY_STRING));
- if (str && str->data)
- default_username = str->data;
- }
- }
- // Still no default username? Try the 'servers' file.
- if (!default_username)
- {
- default_username = NULL;
- }
- // Still no default username? Try the UID.
- if (!default_username)
- default_username = user_get_name(pool);
- default_password = static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_DEFAULT_PASSWORD,
- APR_HASH_KEY_STRING));
- }
- // If we have defaults, just build the cred here and return it.
- // I do wonder why this is here instead of in a separate
- // 'defaults' provider that would run before the prompt
- // provider... Hmmm.
- if (default_username && default_password)
- {
- *cred_p = static_cast<auth_cred_simple_t *>(apr_pcalloc(pool, sizeof(**cred_p)));
- (*cred_p)->username = apr_pstrdup(pool, default_username);
- (*cred_p)->password = apr_pstrdup(pool, default_password);
- (*cred_p)->may_save = TRUE;
- }
- else
- {
- WEBDAV_ERR(pb->prompt_func(cred_p, pb->prompt_baton, realmstring,
- default_username, may_save, pool));
- }
- return WEBDAV_NO_ERROR;
- }
- // Our first attempt will use any default username/password passed
- // in, and prompt for the remaining stuff.
- static error_t
- simple_prompt_first_creds(
- void ** credentials_p,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- simple_prompt_provider_baton_t * pb =
- static_cast<simple_prompt_provider_baton_t *>(provider_baton);
- simple_prompt_iter_baton_t * ibaton =
- static_cast<simple_prompt_iter_baton_t *>(apr_pcalloc(pool, sizeof(*ibaton)));
- const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
- APR_HASH_KEY_STRING));
- WEBDAV_ERR(prompt_for_simple_creds((auth_cred_simple_t **) credentials_p,
- pb, parameters, realmstring, TRUE,
- !no_auth_cache, pool));
- ibaton->retries = 0;
- *iter_baton = ibaton;
- return WEBDAV_NO_ERROR;
- }
- // Subsequent attempts to fetch will ignore the default values, and
- // simply re-prompt for both, up to a maximum of ib->pb->retry_limit.
- static error_t
- simple_prompt_next_creds(
- void ** credentials_p,
- void * iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- simple_prompt_iter_baton_t * ib =
- static_cast<simple_prompt_iter_baton_t *>(iter_baton);
- simple_prompt_provider_baton_t * pb =
- static_cast<simple_prompt_provider_baton_t *>(provider_baton);
- const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
- APR_HASH_KEY_STRING));
- if ((pb->retry_limit >= 0) && (ib->retries >= pb->retry_limit))
- {
- // give up, go on to next provider.
- *credentials_p = NULL;
- return WEBDAV_NO_ERROR;
- }
- ib->retries++;
- return prompt_for_simple_creds((auth_cred_simple_t **) credentials_p,
- pb, parameters, realmstring, FALSE,
- !no_auth_cache, pool);
- }
- static const auth_provider_t simple_prompt_provider =
- {
- AUTH_CRED_SIMPLE,
- simple_prompt_first_creds,
- simple_prompt_next_creds,
- NULL,
- };
- // Public API
- static void
- auth_get_simple_prompt_provider(
- auth_provider_object_t ** provider,
- auth_simple_prompt_func_t prompt_func,
- void * prompt_baton,
- int retry_limit,
- apr_pool_t * pool)
- {
- auth_provider_object_t * po =
- static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
- simple_prompt_provider_baton_t * pb =
- static_cast<simple_prompt_provider_baton_t *>(apr_pcalloc(pool, sizeof(*pb)));
- pb->prompt_func = prompt_func;
- pb->prompt_baton = prompt_baton;
- pb->retry_limit = retry_limit;
- po->vtable = &simple_prompt_provider;
- po->provider_baton = pb;
- *provider = po;
- }
- //---------------------------------------------------------------------------
- // from ssl_client_cert_pw_providers.c
- // The keys that will be stored on disk. These serve the same role as
- // similar constants in other providers.
- // AUTHN_PASSTYPE_KEY just records the passphrase type next to the
- // passphrase, so that anyone who is manually editing their authn
- // files can know which provider owns the password.
- #define AUTHN_PASSPHRASE_KEY "passphrase"
- #define AUTHN_PASSTYPE_KEY "passtype"
- // Baton type for the ssl client cert passphrase provider.
- typedef struct ssl_client_cert_pw_file_provider_baton_t
- {
- auth_plaintext_passphrase_prompt_func_t plaintext_passphrase_prompt_func;
- void * prompt_baton;
- // We cache the user's answer to the plaintext prompt, keyed
- // by realm, in case we'll be called multiple times for the
- // same realm. So: keys are 'const char *' realm strings, and
- // values are 'bool *'.
- apr_hash_t * plaintext_answers;
- } ssl_client_cert_pw_file_provider_baton_t;
- // This implements the auth_password_get_t interface.
- // Set **PASSPHRASE to the plaintext passphrase retrieved from CREDS;
- // ignore other parameters.
- static error_t
- auth_ssl_client_cert_pw_get(
- bool * done,
- const char ** passphrase,
- apr_hash_t * creds,
- const char * realmstring,
- const char * username,
- apr_hash_t * parameters,
- bool non_interactive,
- apr_pool_t * pool)
- {
- string_t * str = static_cast<string_t *>(apr_hash_get(creds, AUTHN_PASSPHRASE_KEY, APR_HASH_KEY_STRING));
- if (str && str->data)
- {
- *passphrase = str->data;
- *done = TRUE;
- return WEBDAV_NO_ERROR;
- }
- *done = FALSE;
- return WEBDAV_NO_ERROR;
- }
- // This implements the auth_password_set_t interface.
- // Store PASSPHRASE in CREDS; ignore other parameters.
- static error_t
- auth_ssl_client_cert_pw_set(
- bool * done,
- apr_hash_t * creds,
- const char * realmstring,
- const char * username,
- const char * passphrase,
- apr_hash_t * parameters,
- bool non_interactive,
- apr_pool_t * pool)
- {
- apr_hash_set(creds, AUTHN_PASSPHRASE_KEY, APR_HASH_KEY_STRING,
- string_create(passphrase, pool));
- *done = TRUE;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- auth_ssl_client_cert_pw_file_first_creds_helper(
- void ** credentials_p,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- auth_password_get_t passphrase_get,
- const char * passtype,
- apr_pool_t * pool)
- {
- bool non_interactive = apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_NON_INTERACTIVE,
- APR_HASH_KEY_STRING) != NULL;
- const char * password = NULL;
- if (!password)
- {
- error_t err;
- apr_hash_t * creds_hash = NULL;
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- // Try to load passphrase from the auth/ cache.
- err = config_read_auth_data(&creds_hash,
- AUTH_CRED_SSL_CLIENT_CERT_PW,
- realmstring, fs, pool);
- error_clear(&err);
- if (!err && creds_hash)
- {
- bool done;
- WEBDAV_ERR(passphrase_get(&done, &password, creds_hash, realmstring,
- NULL, parameters, non_interactive, pool));
- if (!done)
- password = NULL;
- }
- }
- if (password)
- {
- auth_cred_ssl_client_cert_pw_t * cred =
- static_cast<auth_cred_ssl_client_cert_pw_t *>(apr_pcalloc(pool, sizeof(*cred)));
- cred->password = password;
- cred->may_save = FALSE;
- *credentials_p = cred;
- }
- else *credentials_p = NULL;
- *iter_baton = NULL;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- auth_ssl_client_cert_pw_file_save_creds_helper(
- bool * saved,
- void * credentials,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- auth_password_set_t passphrase_set,
- const char * passtype,
- apr_pool_t * pool)
- {
- auth_cred_ssl_client_cert_pw_t * creds =
- static_cast<auth_cred_ssl_client_cert_pw_t *>(credentials);
- apr_hash_t * creds_hash = NULL;
- error_t err = 0;
- bool dont_store_passphrase =
- apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_DONT_STORE_SSL_CLIENT_CERT_PP,
- APR_HASH_KEY_STRING) != NULL;
- const char * store_ssl_client_cert_pp_plaintext =
- static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT,
- APR_HASH_KEY_STRING));
- bool non_interactive = apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_NON_INTERACTIVE,
- APR_HASH_KEY_STRING) != NULL;
- ssl_client_cert_pw_file_provider_baton_t * b =
- (ssl_client_cert_pw_file_provider_baton_t *)provider_baton;
- bool no_auth_cache = (!creds->may_save) ||
- (apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
- APR_HASH_KEY_STRING) != NULL);
- *saved = FALSE;
- if (no_auth_cache)
- return WEBDAV_NO_ERROR;
- creds_hash = apr_hash_make(pool);
- // Don't store passphrase in any form if the user has told
- // us not to do so.
- if (!dont_store_passphrase)
- {
- bool may_save_passphrase = FALSE;
- // If the passphrase is going to be stored encrypted, go right
- // ahead and store it to disk. Else determine whether saving
- // in plaintext is OK.
- if (strcmp(passtype, WEBDAV_AUTH_WINCRYPT_PASSWORD_TYPE) == 0)
- {
- may_save_passphrase = TRUE;
- }
- else
- {
- if (cstring_casecmp(store_ssl_client_cert_pp_plaintext,
- WEBDAV_CONFIG_ASK) == 0)
- {
- if (non_interactive)
- {
- // In non-interactive mode, the default behaviour is
- // to not store the passphrase
- may_save_passphrase = FALSE;
- }
- else if (b->plaintext_passphrase_prompt_func)
- {
- bool * cached_answer =
- static_cast<bool *>(apr_hash_get(b->plaintext_answers, realmstring,
- APR_HASH_KEY_STRING));
- if (cached_answer != NULL)
- {
- may_save_passphrase = *cached_answer;
- }
- else
- {
- apr_pool_t * cached_answer_pool;
- // Nothing cached for this realm, prompt the user.
- WEBDAV_ERR((*b->plaintext_passphrase_prompt_func)(
- &may_save_passphrase,
- realmstring,
- b->prompt_baton,
- pool));
- cached_answer_pool = apr_hash_pool_get(b->plaintext_answers);
- cached_answer = static_cast<bool *>(apr_pcalloc(cached_answer_pool,
- sizeof(*cached_answer)));
- *cached_answer = may_save_passphrase;
- apr_hash_set(b->plaintext_answers, realmstring,
- APR_HASH_KEY_STRING, cached_answer);
- }
- }
- else
- {
- may_save_passphrase = FALSE;
- }
- }
- else if (cstring_casecmp(store_ssl_client_cert_pp_plaintext,
- WEBDAV_CONFIG_FALSE) == 0)
- {
- may_save_passphrase = FALSE;
- }
- else if (cstring_casecmp(store_ssl_client_cert_pp_plaintext,
- WEBDAV_CONFIG_TRUE) == 0)
- {
- may_save_passphrase = TRUE;
- }
- else
- {
- return error_createf(WEBDAV_ERR_DAV_INVALID_CONFIG_VALUE, NULL,
- "Config error: invalid value '%s' for option '%s'",
- store_ssl_client_cert_pp_plaintext,
- WEBDAV_AUTH_PARAM_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT);
- }
- }
- if (may_save_passphrase)
- {
- WEBDAV_ERR(passphrase_set(saved, creds_hash, realmstring,
- NULL, creds->password, parameters,
- non_interactive, pool));
- if (*saved && passtype)
- {
- apr_hash_set(creds_hash, AUTHN_PASSTYPE_KEY,
- APR_HASH_KEY_STRING,
- string_create(passtype, pool));
- }
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- // Save credentials to disk.
- err = config_write_auth_data(creds_hash,
- AUTH_CRED_SSL_CLIENT_CERT_PW,
- realmstring, fs, pool);
- error_clear(&err);
- *saved = !err;
- }
- }
- return WEBDAV_NO_ERROR;
- }
- // This implements the auth_provider_t.first_credentials API.
- // It gets cached (unencrypted) credentials from the ssl client cert
- // password provider's cache.
- static error_t
- ssl_client_cert_pw_file_first_credentials(
- void ** credentials_p,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- return auth_ssl_client_cert_pw_file_first_creds_helper(
- credentials_p,
- iter_baton,
- provider_baton,
- parameters,
- realmstring,
- auth_ssl_client_cert_pw_get,
- WEBDAV_AUTH_SIMPLE_PASSWORD_TYPE,
- pool);
- }
- // This implements the auth_provider_t.save_credentials API.
- // It saves the credentials unencrypted.
- static error_t
- ssl_client_cert_pw_file_save_credentials(
- bool * saved,
- void * credentials,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- return auth_ssl_client_cert_pw_file_save_creds_helper(
- saved, credentials,
- provider_baton,
- parameters,
- realmstring,
- auth_ssl_client_cert_pw_set,
- WEBDAV_AUTH_SIMPLE_PASSWORD_TYPE,
- pool);
- }
- static const auth_provider_t ssl_client_cert_pw_file_provider =
- {
- AUTH_CRED_SSL_CLIENT_CERT_PW,
- ssl_client_cert_pw_file_first_credentials,
- NULL,
- ssl_client_cert_pw_file_save_credentials
- };
- // Public API to SSL file providers.
- static void
- auth_get_ssl_client_cert_pw_file_provider2(
- auth_provider_object_t ** provider,
- auth_plaintext_passphrase_prompt_func_t plaintext_passphrase_prompt_func,
- void * prompt_baton,
- apr_pool_t * pool)
- {
- auth_provider_object_t * po =
- static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
- ssl_client_cert_pw_file_provider_baton_t * pb =
- static_cast<ssl_client_cert_pw_file_provider_baton_t *>(apr_pcalloc(pool,
- sizeof(*pb)));
- pb->plaintext_passphrase_prompt_func = plaintext_passphrase_prompt_func;
- pb->prompt_baton = prompt_baton;
- pb->plaintext_answers = apr_hash_make(pool);
- po->vtable = &ssl_client_cert_pw_file_provider;
- po->provider_baton = pb;
- *provider = po;
- }
- /*-----------------------------------------------------------------------*/
- // Prompt provider
- /*-----------------------------------------------------------------------*/
- // Baton type for client passphrase prompting.
- // There is no iteration baton type.
- typedef struct ssl_client_cert_pw_prompt_provider_baton_t
- {
- auth_ssl_client_cert_pw_prompt_func_t prompt_func;
- void * prompt_baton;
- // how many times to re-prompt after the first one fails
- int retry_limit;
- } ssl_client_cert_pw_prompt_provider_baton_t;
- // Iteration baton.
- typedef struct ssl_client_cert_pw_prompt_iter_baton_t
- {
- // The original provider baton
- ssl_client_cert_pw_prompt_provider_baton_t * pb;
- // The original realmstring
- const char * realmstring;
- // how many times we've reprompted
- int retries;
- } ssl_client_cert_pw_prompt_iter_baton_t;
- static error_t
- ssl_client_cert_pw_prompt_first_cred(
- void ** credentials_p,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- ssl_client_cert_pw_prompt_provider_baton_t * pb =
- static_cast<ssl_client_cert_pw_prompt_provider_baton_t *>(provider_baton);
- ssl_client_cert_pw_prompt_iter_baton_t * ib =
- static_cast<ssl_client_cert_pw_prompt_iter_baton_t *>(apr_pcalloc(pool, sizeof(*ib)));
- const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
- APR_HASH_KEY_STRING));
- WEBDAV_ERR(pb->prompt_func((auth_cred_ssl_client_cert_pw_t **)
- credentials_p, pb->prompt_baton, realmstring,
- !no_auth_cache, pool));
- ib->pb = pb;
- ib->realmstring = apr_pstrdup(pool, realmstring);
- ib->retries = 0;
- *iter_baton = ib;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- ssl_client_cert_pw_prompt_next_cred(
- void ** credentials_p,
- void * iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- ssl_client_cert_pw_prompt_iter_baton_t * ib =
- static_cast<ssl_client_cert_pw_prompt_iter_baton_t *>(iter_baton);
- const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
- APR_HASH_KEY_STRING));
- if ((ib->pb->retry_limit >= 0) && (ib->retries >= ib->pb->retry_limit))
- {
- // give up, go on to next provider.
- *credentials_p = NULL;
- return WEBDAV_NO_ERROR;
- }
- ib->retries++;
- return ib->pb->prompt_func((auth_cred_ssl_client_cert_pw_t **)
- credentials_p, ib->pb->prompt_baton,
- ib->realmstring, !no_auth_cache, pool);
- }
- static const auth_provider_t client_cert_pw_prompt_provider =
- {
- AUTH_CRED_SSL_CLIENT_CERT_PW,
- ssl_client_cert_pw_prompt_first_cred,
- ssl_client_cert_pw_prompt_next_cred,
- NULL
- };
- static void
- auth_get_ssl_client_cert_pw_prompt_provider(
- auth_provider_object_t ** provider,
- auth_ssl_client_cert_pw_prompt_func_t prompt_func,
- void * prompt_baton,
- int retry_limit,
- apr_pool_t * pool)
- {
- auth_provider_object_t * po =
- static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
- ssl_client_cert_pw_prompt_provider_baton_t * pb =
- static_cast<ssl_client_cert_pw_prompt_provider_baton_t *>(apr_pcalloc(pool, sizeof(*pb)));
- pb->prompt_func = prompt_func;
- pb->prompt_baton = prompt_baton;
- pb->retry_limit = retry_limit;
- po->vtable = &client_cert_pw_prompt_provider;
- po->provider_baton = pb;
- *provider = po;
- }
- //------------------------------------------------------------------------------
- // from win32_crypto.c
- // The description string that's combined with unencrypted data by the
- // Windows CryptoAPI. Used during decryption to verify that the
- // encrypted data were valid.
- static const WCHAR description[] = L"auth.simple.wincrypt";
- // Implementation of auth_password_set_t that encrypts
- // the incoming password using the Windows CryptoAPI.
- static error_t
- windows_password_encrypter(
- bool * done,
- apr_hash_t * creds,
- const char * realmstring,
- const char * username,
- const char * in,
- apr_hash_t * parameters,
- bool non_interactive,
- apr_pool_t * pool)
- {
- DATA_BLOB blobin;
- DATA_BLOB blobout;
- BOOL crypted = FALSE;
- blobin.cbData = (DWORD)strlen(in);
- blobin.pbData = (BYTE *) in;
- crypted = CryptProtectData(&blobin, description, NULL, NULL, NULL,
- CRYPTPROTECT_UI_FORBIDDEN, &blobout);
- if (crypted)
- {
- char * coded = static_cast<char *>(apr_pcalloc(pool, apr_base64_encode_len(blobout.cbData)));
- apr_base64_encode(coded, (const char *)blobout.pbData, blobout.cbData);
- WEBDAV_ERR(auth_simple_password_set(done, creds, realmstring, username,
- coded, parameters,
- non_interactive, pool));
- LocalFree(blobout.pbData);
- }
- return WEBDAV_NO_ERROR;
- }
- // Implementation of auth_password_get_t that decrypts
- // the incoming password using the Windows CryptoAPI and verifies its
- // validity.
- static error_t
- windows_password_decrypter(
- bool * done,
- const char ** out,
- apr_hash_t * creds,
- const char * realmstring,
- const char * username,
- apr_hash_t * parameters,
- bool non_interactive,
- apr_pool_t * pool)
- {
- DATA_BLOB blobin;
- DATA_BLOB blobout;
- LPWSTR descr;
- BOOL decrypted = FALSE;
- const char * in = NULL;
- WEBDAV_ERR(auth_simple_password_get(done, &in, creds, realmstring, username,
- parameters, non_interactive, pool));
- if (!*done)
- return WEBDAV_NO_ERROR;
- blobin.cbData = (DWORD)strlen(in);
- blobin.pbData = static_cast<BYTE *>(apr_pcalloc(pool, apr_base64_decode_len(in)));
- apr_base64_decode((char *)blobin.pbData, in);
- decrypted = CryptUnprotectData(&blobin, &descr, NULL, NULL, NULL,
- CRYPTPROTECT_UI_FORBIDDEN, &blobout);
- if (decrypted)
- {
- if (0 == lstrcmpW(descr, description))
- *out = apr_pstrndup(pool, (const char *)blobout.pbData, blobout.cbData);
- else
- decrypted = FALSE;
- LocalFree(blobout.pbData);
- LocalFree(descr);
- }
- *done = decrypted != 0;
- return WEBDAV_NO_ERROR;
- }
- // Get cached encrypted credentials from the simple provider's cache.
- static error_t
- windows_simple_first_creds(
- void ** credentials,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- return auth_simple_first_creds_helper(credentials,
- iter_baton,
- provider_baton,
- parameters,
- realmstring,
- windows_password_decrypter,
- WEBDAV_AUTH_WINCRYPT_PASSWORD_TYPE,
- pool);
- }
- // Save encrypted credentials to the simple provider's cache.
- static error_t
- windows_simple_save_creds(
- bool * saved,
- void * credentials,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- return auth_simple_save_creds_helper(saved, credentials,
- provider_baton,
- parameters,
- realmstring,
- windows_password_encrypter,
- WEBDAV_AUTH_WINCRYPT_PASSWORD_TYPE,
- pool);
- }
- static const auth_provider_t windows_simple_provider =
- {
- AUTH_CRED_SIMPLE,
- windows_simple_first_creds,
- NULL,
- windows_simple_save_creds
- };
- // Public API
- static void
- auth_get_windows_simple_provider(
- auth_provider_object_t ** provider,
- apr_pool_t * pool)
- {
- auth_provider_object_t * po =
- static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
- po->vtable = &windows_simple_provider;
- *provider = po;
- }
- /*-----------------------------------------------------------------------*/
- // Windows SSL server trust provider, validates ssl certificate using
- // CryptoApi.
- /*-----------------------------------------------------------------------*/
- // Implementation of auth_password_set_t that encrypts
- // the incoming password using the Windows CryptoAPI.
- static error_t
- windows_ssl_client_cert_pw_encrypter(
- bool * done,
- apr_hash_t * creds,
- const char * realmstring,
- const char * username,
- const char * in,
- apr_hash_t * parameters,
- bool non_interactive,
- apr_pool_t * pool)
- {
- DATA_BLOB blobin;
- DATA_BLOB blobout;
- BOOL crypted;
- blobin.cbData = (DWORD)strlen(in);
- blobin.pbData = (BYTE *) in;
- crypted = CryptProtectData(&blobin, description, NULL, NULL, NULL,
- CRYPTPROTECT_UI_FORBIDDEN, &blobout);
- if (crypted)
- {
- char * coded = static_cast<char *>(apr_pcalloc(pool, apr_base64_encode_len(blobout.cbData)));
- apr_base64_encode(coded, (const char *)blobout.pbData, blobout.cbData);
- WEBDAV_ERR(auth_ssl_client_cert_pw_set(done, creds, realmstring, username,
- coded, parameters,
- non_interactive, pool));
- LocalFree(blobout.pbData);
- }
- return WEBDAV_NO_ERROR;
- }
- // Implementation of auth_password_get_t that decrypts
- // the incoming password using the Windows CryptoAPI and verifies its
- // validity.
- static error_t
- windows_ssl_client_cert_pw_decrypter(
- bool * done,
- const char ** out,
- apr_hash_t * creds,
- const char * realmstring,
- const char * username,
- apr_hash_t * parameters,
- bool non_interactive,
- apr_pool_t * pool)
- {
- DATA_BLOB blobin;
- DATA_BLOB blobout;
- LPWSTR descr;
- BOOL decrypted;
- const char * in = NULL;
- WEBDAV_ERR(auth_ssl_client_cert_pw_get(done, &in, creds, realmstring, username,
- parameters, non_interactive, pool));
- if (!*done)
- return WEBDAV_NO_ERROR;
- blobin.cbData = (DWORD)strlen(in);
- blobin.pbData = static_cast<BYTE *>(apr_pcalloc(pool, apr_base64_decode_len(in)));
- apr_base64_decode((char *)blobin.pbData, in);
- decrypted = CryptUnprotectData(&blobin, &descr, NULL, NULL, NULL,
- CRYPTPROTECT_UI_FORBIDDEN, &blobout);
- if (decrypted)
- {
- if (0 == lstrcmpW(descr, description))
- *out = apr_pstrndup(pool, (const char *)blobout.pbData, blobout.cbData);
- else
- decrypted = FALSE;
- LocalFree(blobout.pbData);
- LocalFree(descr);
- }
- *done = decrypted != 0;
- return WEBDAV_NO_ERROR;
- }
- // Get cached encrypted credentials from the simple provider's cache.
- static error_t
- windows_ssl_client_cert_pw_first_creds(
- void ** credentials,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- return auth_ssl_client_cert_pw_file_first_creds_helper(
- credentials,
- iter_baton,
- provider_baton,
- parameters,
- realmstring,
- windows_ssl_client_cert_pw_decrypter,
- WEBDAV_AUTH_WINCRYPT_PASSWORD_TYPE,
- pool);
- }
- // Save encrypted credentials to the simple provider's cache.
- static error_t
- windows_ssl_client_cert_pw_save_creds(
- bool * saved,
- void * credentials,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- return auth_ssl_client_cert_pw_file_save_creds_helper(
- saved,
- credentials,
- provider_baton,
- parameters,
- realmstring,
- windows_ssl_client_cert_pw_encrypter,
- WEBDAV_AUTH_WINCRYPT_PASSWORD_TYPE,
- pool);
- }
- static const auth_provider_t windows_ssl_client_cert_pw_provider =
- {
- AUTH_CRED_SSL_CLIENT_CERT_PW,
- windows_ssl_client_cert_pw_first_creds,
- NULL,
- windows_ssl_client_cert_pw_save_creds
- };
- // Public API
- static void
- auth_get_windows_ssl_client_cert_pw_provider(
- auth_provider_object_t ** provider,
- apr_pool_t * pool)
- {
- auth_provider_object_t * po =
- static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
- po->vtable = &windows_ssl_client_cert_pw_provider;
- *provider = po;
- }
- /*-----------------------------------------------------------------------*/
- // Windows SSL server trust provider, validates ssl certificate using
- // CryptoApi.
- /*-----------------------------------------------------------------------*/
- // Helper to create CryptoAPI CERT_CONTEXT from base64 encoded BASE64_CERT.
- // Returns NULL on error.
- static PCCERT_CONTEXT
- certcontext_from_base64(
- const char * base64_cert,
- apr_pool_t * pool)
- {
- PCCERT_CONTEXT cert_context = NULL;
- int cert_len = 0;
- BYTE * binary_cert = NULL;
- // Use apr-util as CryptStringToBinaryA is available only on XP+.
- binary_cert = static_cast<BYTE *>(apr_pcalloc(pool,
- apr_base64_decode_len(base64_cert)));
- cert_len = apr_base64_decode((char *)binary_cert, base64_cert);
- // Parse the certificate into a context.
- cert_context = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
- binary_cert, cert_len);
- return cert_context;
- }
- // Helper for windows_ssl_server_trust_first_credentials for validating
- // certificate using CryptoApi. Sets *OK_P to TRUE if base64 encoded ASCII_CERT
- // certificate considered as valid.
- static error_t
- windows_validate_certificate(
- bool * ok_p,
- const char * ascii_cert,
- apr_pool_t * pool)
- {
- PCCERT_CONTEXT cert_context = NULL;
- CERT_CHAIN_PARA chain_para;
- PCCERT_CHAIN_CONTEXT chain_context = NULL;
- *ok_p = FALSE;
- // Parse the certificate into a context.
- cert_context = certcontext_from_base64(ascii_cert, pool);
- if (cert_context)
- {
- // Retrieve the certificate chain of the certificate
- // (a certificate without a valid root does not have a chain).
- memset(&chain_para, 0, sizeof(chain_para));
- chain_para.cbSize = sizeof(chain_para);
- HCERTCHAINENGINE chain_engine;
- CERT_CHAIN_ENGINE_CONFIG chain_config;
- chain_config.cbSize = sizeof(CERT_CHAIN_ENGINE_CONFIG);
- chain_config.hRestrictedRoot = NULL;
- chain_config.hRestrictedTrust = NULL;
- chain_config.hRestrictedOther = NULL;
- chain_config.cAdditionalStore = 0;
- chain_config.rghAdditionalStore = NULL;
- chain_config.dwFlags = CERT_CHAIN_CACHE_END_CERT;
- chain_config.dwUrlRetrievalTimeout = 0;
- chain_config.MaximumCachedCertificates =0;
- chain_config.CycleDetectionModulus = 0;
- CertCreateCertificateChainEngine(
- &chain_config,
- &chain_engine);
- if (CertGetCertificateChain(chain_engine, cert_context, NULL, NULL, &chain_para,
- CERT_CHAIN_CACHE_END_CERT |
- CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
- NULL, &chain_context))
- {
- CERT_CHAIN_POLICY_PARA policy_para;
- CERT_CHAIN_POLICY_STATUS policy_status;
- policy_para.cbSize = sizeof(policy_para);
- policy_para.dwFlags = 0;
- policy_para.pvExtraPolicyPara = NULL;
- policy_status.cbSize = sizeof(policy_status);
- if (CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL,
- chain_context, &policy_para,
- &policy_status))
- {
- if (policy_status.dwError == S_OK)
- {
- // Windows thinks the certificate is valid.
- *ok_p = TRUE;
- }
- }
- CertFreeCertificateChain(chain_context);
- }
- CertFreeCertificateContext(cert_context);
- CertFreeCertificateChainEngine(chain_engine);
- }
- return WEBDAV_NO_ERROR;
- }
- // Retrieve ssl server CA failure overrides (if any) from CryptoApi.
- static error_t
- windows_ssl_server_trust_first_credentials(
- void ** credentials,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- apr_uint32_t * failures = static_cast<apr_uint32_t *>(apr_hash_get(parameters,
- AUTH_PARAM_SSL_SERVER_FAILURES,
- APR_HASH_KEY_STRING));
- const auth_ssl_server_cert_info_t * cert_info =
- static_cast<const auth_ssl_server_cert_info_t *>(apr_hash_get(parameters,
- AUTH_PARAM_SSL_SERVER_CERT_INFO,
- APR_HASH_KEY_STRING));
- *credentials = NULL;
- *iter_baton = NULL;
- // We can accept only unknown certificate authority.
- if (*failures & WEBDAV_AUTH_SSL_UNKNOWNCA)
- {
- bool ok;
- WEBDAV_ERR(windows_validate_certificate(&ok, cert_info->ascii_cert, pool));
- // Windows thinks that certificate is ok.
- if (ok)
- {
- // Clear failure flag.
- *failures &= ~WEBDAV_AUTH_SSL_UNKNOWNCA;
- }
- }
- // If all failures are cleared now, we return the creds
- if (!*failures)
- {
- auth_cred_ssl_server_trust_t * creds =
- static_cast<auth_cred_ssl_server_trust_t *>(apr_pcalloc(pool, sizeof(*creds)));
- creds->may_save = FALSE; // No need to save it.
- *credentials = creds;
- }
- return WEBDAV_NO_ERROR;
- }
- static const auth_provider_t windows_server_trust_provider =
- {
- AUTH_CRED_SSL_SERVER_TRUST,
- windows_ssl_server_trust_first_credentials,
- NULL,
- NULL,
- };
- // Public API
- static void
- auth_get_windows_ssl_server_trust_provider(
- auth_provider_object_t ** provider,
- apr_pool_t * pool)
- {
- auth_provider_object_t * po =
- static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
- po->vtable = &windows_server_trust_provider;
- *provider = po;
- }
- //------------------------------------------------------------------------------
- // from username_providers.c
- // Username-only Provider
- static error_t
- username_first_creds(
- void ** credentials,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- const char * username = static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_DEFAULT_USERNAME,
- APR_HASH_KEY_STRING));
- bool may_save = !!username;
- error_t err = 0;
- // If we don't have a usename yet, try the auth cache
- if (!username)
- {
- apr_hash_t * creds_hash = NULL;
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- // Try to load credentials from a file on disk, based on the
- // realmstring. Don't throw an error, though: if something went
- // wrong reading the file, no big deal. What really matters is that
- // we failed to get the creds, so allow the auth system to try the
- // next provider.
- err = config_read_auth_data(&creds_hash, WEBDAV_AUTH_CRED_USERNAME,
- realmstring, fs,
- pool);
- error_clear(&err);
- if (!err && creds_hash)
- {
- string_t * str = static_cast<string_t *>(apr_hash_get(creds_hash, AUTHN_USERNAME_KEY,
- APR_HASH_KEY_STRING));
- if (str && str->data)
- username = str->data;
- }
- }
- // If that failed, ask the OS for the username
- if (!username)
- username = user_get_name(pool);
- if (username)
- {
- auth_cred_simple_t * creds =
- static_cast<auth_cred_simple_t *>(apr_pcalloc(pool, sizeof(*creds)));
- creds->username = username;
- creds->may_save = may_save;
- *credentials = creds;
- }
- else
- *credentials = NULL;
- *iter_baton = NULL;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- username_save_creds(
- bool * saved,
- void * credentials,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- auth_cred_simple_t * creds =
- static_cast<auth_cred_simple_t *>(credentials);
- apr_hash_t * creds_hash = NULL;
- error_t err;
- *saved = FALSE;
- if (!creds->may_save)
- return WEBDAV_NO_ERROR;
- // Put the credentials in a hash and save it to disk
- creds_hash = apr_hash_make(pool);
- apr_hash_set(creds_hash, AUTHN_USERNAME_KEY, APR_HASH_KEY_STRING,
- string_create(creds->username, pool));
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- err = config_write_auth_data(creds_hash, WEBDAV_AUTH_CRED_USERNAME,
- realmstring,
- fs,
- pool);
- error_clear(&err);
- *saved = !err;
- return WEBDAV_NO_ERROR;
- }
- static const auth_provider_t username_provider =
- {
- WEBDAV_AUTH_CRED_USERNAME,
- username_first_creds,
- NULL,
- username_save_creds
- };
- // Public API
- static void
- auth_get_username_provider(
- auth_provider_object_t ** provider,
- apr_pool_t * pool)
- {
- auth_provider_object_t * po =
- static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
- po->vtable = &username_provider;
- *provider = po;
- }
- // Baton type for username-only prompting.
- typedef struct username_prompt_provider_baton_t
- {
- auth_username_prompt_func_t prompt_func;
- void * prompt_baton;
- // how many times to re-prompt after the first one fails
- int retry_limit;
- } username_prompt_provider_baton_t;
- // Iteration baton type for username-only prompting.
- typedef struct username_prompt_iter_baton_t
- {
- // how many times we've reprompted
- int retries;
- } username_prompt_iter_baton_t;
- // Helper Functions
- static error_t
- prompt_for_username_creds(
- auth_cred_username_t ** cred_p,
- username_prompt_provider_baton_t * pb,
- apr_hash_t * parameters,
- const char * realmstring,
- bool first_time,
- bool may_save,
- apr_pool_t * pool)
- {
- const char * def_username = NULL;
- *cred_p = NULL;
- // If we're allowed to check for default usernames, do so.
- if (first_time)
- def_username = static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_DEFAULT_USERNAME,
- APR_HASH_KEY_STRING));
- // If we have defaults, just build the cred here and return it.
- // I do wonder why this is here instead of in a separate
- // 'defaults' provider that would run before the prompt
- // provider... Hmmm.
- if (def_username)
- {
- *cred_p = static_cast<auth_cred_username_t *>(apr_pcalloc(pool, sizeof(**cred_p)));
- (*cred_p)->username = apr_pstrdup(pool, def_username);
- (*cred_p)->may_save = TRUE;
- }
- else
- {
- WEBDAV_ERR(pb->prompt_func(cred_p, pb->prompt_baton, realmstring,
- may_save, pool));
- }
- return WEBDAV_NO_ERROR;
- }
- // Our first attempt will use any default username passed
- // in, and prompt for the remaining stuff.
- static error_t
- username_prompt_first_creds(
- void ** credentials_p,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- username_prompt_provider_baton_t * pb =
- static_cast<username_prompt_provider_baton_t *>(provider_baton);
- username_prompt_iter_baton_t * ibaton =
- static_cast<username_prompt_iter_baton_t *>(apr_pcalloc(pool, sizeof(*ibaton)));
- const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
- APR_HASH_KEY_STRING));
- WEBDAV_ERR(prompt_for_username_creds((auth_cred_username_t **) credentials_p, pb,
- parameters, realmstring, TRUE, !no_auth_cache, pool));
- ibaton->retries = 0;
- *iter_baton = ibaton;
- return WEBDAV_NO_ERROR;
- }
- // Subsequent attempts to fetch will ignore the default username
- // value, and simply re-prompt for the username, up to a maximum of
- // ib->pb->retry_limit.
- static error_t
- username_prompt_next_creds(
- void ** credentials_p,
- void * iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- username_prompt_iter_baton_t * ib =
- static_cast<username_prompt_iter_baton_t *>(iter_baton);
- username_prompt_provider_baton_t * pb =
- static_cast<username_prompt_provider_baton_t *>(provider_baton);
- const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
- APR_HASH_KEY_STRING));
- if ((pb->retry_limit >= 0) && (ib->retries >= pb->retry_limit))
- {
- // give up, go on to next provider.
- *credentials_p = NULL;
- return WEBDAV_NO_ERROR;
- }
- ib->retries++;
- return prompt_for_username_creds((auth_cred_username_t **) credentials_p, pb,
- parameters, realmstring, FALSE, !no_auth_cache, pool);
- }
- static const auth_provider_t username_prompt_provider =
- {
- WEBDAV_AUTH_CRED_USERNAME,
- username_prompt_first_creds,
- username_prompt_next_creds,
- NULL,
- };
- // Public API
- static void
- auth_get_username_prompt_provider(
- auth_provider_object_t ** provider,
- auth_username_prompt_func_t prompt_func,
- void * prompt_baton,
- int retry_limit,
- apr_pool_t * pool)
- {
- auth_provider_object_t * po =
- static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
- username_prompt_provider_baton_t * pb =
- static_cast<username_prompt_provider_baton_t *>(apr_pcalloc(pool, sizeof(*pb)));
- pb->prompt_func = prompt_func;
- pb->prompt_baton = prompt_baton;
- pb->retry_limit = retry_limit;
- po->vtable = &username_prompt_provider;
- po->provider_baton = pb;
- *provider = po;
- }
- //------------------------------------------------------------------------------
- // from auth.c
- static void
- auth_baton_set_parameter(
- auth_baton_t * auth_baton,
- const char * name,
- const void * value)
- {
- apr_hash_set(auth_baton->parameters, name, APR_HASH_KEY_STRING, value);
- }
- static const void *
- auth_baton_get_parameter(
- auth_baton_t * auth_baton,
- const char * name)
- {
- return apr_hash_get(auth_baton->parameters, name, APR_HASH_KEY_STRING);
- }
- static error_t
- auth_first_credentials(
- void ** credentials,
- auth_iterstate_t ** state,
- const char * cred_kind,
- const char * realmstring,
- auth_baton_t * auth_baton,
- apr_pool_t * pool)
- {
- int i = 0;
- provider_set_t * table = NULL;
- auth_provider_object_t * provider = NULL;
- void * creds = NULL;
- void * iter_baton = NULL;
- bool got_first = FALSE;
- auth_iterstate_t * iterstate = NULL;
- const char * cache_key = NULL;
- // Get the appropriate table of providers for CRED_KIND.
- table = static_cast<provider_set_t *>(apr_hash_get(auth_baton->tables, cred_kind, APR_HASH_KEY_STRING));
- if (!table)
- return error_createf(WEBDAV_ERR_AUTHN_NO_PROVIDER, NULL,
- "No provider registered for '%s' credentials",
- cred_kind);
- // First, see if we have cached creds in the auth_baton.
- cache_key = apr_pstrcat(pool, cred_kind, ":", realmstring, (char *)NULL);
- creds = static_cast<void *>(apr_hash_get(auth_baton->creds_cache,
- cache_key, APR_HASH_KEY_STRING));
- if (creds)
- {
- got_first = false;
- }
- else
- // If not, find a provider that can give "first" credentials.
- {
- // Find a provider that can give "first" credentials.
- for (i = 0; i < table->providers->nelts; i++)
- {
- provider = APR_ARRAY_IDX(table->providers, i,
- auth_provider_object_t *);
- WEBDAV_ERR(provider->vtable->first_credentials(
- &creds, &iter_baton, provider->provider_baton,
- auth_baton->parameters, realmstring, auth_baton->pool));
- if (creds != NULL)
- {
- got_first = true;
- break;
- }
- }
- }
- if (!creds)
- *state = NULL;
- else
- {
- // Build an abstract iteration state.
- iterstate = static_cast<auth_iterstate_t *>(apr_pcalloc(pool, sizeof(*iterstate)));
- iterstate->table = table;
- iterstate->provider_idx = i;
- iterstate->got_first = got_first;
- iterstate->provider_iter_baton = iter_baton;
- iterstate->realmstring = apr_pstrdup(pool, realmstring);
- iterstate->cache_key = cache_key;
- iterstate->auth_baton = auth_baton;
- *state = iterstate;
- // Put the creds in the cache
- apr_hash_set(auth_baton->creds_cache,
- apr_pstrdup(auth_baton->pool, cache_key),
- APR_HASH_KEY_STRING,
- creds);
- }
- *credentials = creds;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- auth_next_credentials(
- void ** credentials,
- auth_iterstate_t * state,
- apr_pool_t * pool)
- {
- auth_baton_t * auth_baton = state->auth_baton;
- auth_provider_object_t * provider = NULL;
- provider_set_t * table = state->table;
- void * creds = NULL;
- // Continue traversing the table from where we left off.
- for (/* no init */;
- state->provider_idx < table->providers->nelts;
- state->provider_idx++)
- {
- provider = APR_ARRAY_IDX(table->providers,
- state->provider_idx,
- auth_provider_object_t *);
- if (!state->got_first)
- {
- WEBDAV_ERR(provider->vtable->first_credentials(
- &creds, &(state->provider_iter_baton),
- provider->provider_baton, auth_baton->parameters,
- state->realmstring, auth_baton->pool));
- state->got_first = TRUE;
- }
- else
- {
- if (provider->vtable->next_credentials)
- WEBDAV_ERR(provider->vtable->next_credentials(
- &creds, state->provider_iter_baton,
- provider->provider_baton, auth_baton->parameters,
- state->realmstring, auth_baton->pool));
- }
- if (creds != NULL)
- {
- // Put the creds in the cache
- apr_hash_set(auth_baton->creds_cache,
- state->cache_key, APR_HASH_KEY_STRING,
- creds);
- break;
- }
- state->got_first = FALSE;
- }
- *credentials = creds;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- auth_save_credentials(
- auth_iterstate_t * state,
- apr_pool_t * pool)
- {
- int i = 0;
- auth_provider_object_t * provider = NULL;
- bool save_succeeded = FALSE;
- const char * no_auth_cache = NULL;
- auth_baton_t * auth_baton = NULL;
- void * creds = NULL;
- if (!state || state->table->providers->nelts <= state->provider_idx)
- return WEBDAV_NO_ERROR;
- auth_baton = state->auth_baton;
- creds = apr_hash_get(state->auth_baton->creds_cache,
- state->cache_key, APR_HASH_KEY_STRING);
- if (!creds)
- return WEBDAV_NO_ERROR;
- // Do not save the creds if AUTH_PARAM_NO_AUTH_CACHE is set
- no_auth_cache = static_cast<const char *>(apr_hash_get(auth_baton->parameters,
- AUTH_PARAM_NO_AUTH_CACHE,
- APR_HASH_KEY_STRING));
- if (no_auth_cache)
- return WEBDAV_NO_ERROR;
- // First, try to save the creds using the provider that produced them.
- provider = APR_ARRAY_IDX(state->table->providers,
- state->provider_idx,
- auth_provider_object_t *);
- if (provider->vtable->save_credentials)
- WEBDAV_ERR(provider->vtable->save_credentials(&save_succeeded,
- creds,
- provider->provider_baton,
- auth_baton->parameters,
- state->realmstring,
- pool));
- if (save_succeeded)
- return WEBDAV_NO_ERROR;
- // Otherwise, loop from the top of the list, asking every provider
- // to attempt a save. todo: someday optimize so we don't
- // necessarily start from the top of the list.
- for (i = 0; i < state->table->providers->nelts; i++)
- {
- provider = APR_ARRAY_IDX(state->table->providers, i,
- auth_provider_object_t *);
- if (provider->vtable->save_credentials)
- WEBDAV_ERR(provider->vtable->save_credentials(
- &save_succeeded, creds,
- provider->provider_baton,
- auth_baton->parameters,
- state->realmstring,
- pool));
- if (save_succeeded)
- break;
- }
- // notice that at the moment, if no provider can save, there's
- // no way the caller will know.
- return WEBDAV_NO_ERROR;
- }
- static error_t
- auth_get_platform_specific_provider(
- auth_provider_object_t ** provider,
- const char * provider_name,
- const char * provider_type,
- apr_pool_t * pool)
- {
- *provider = NULL;
- {
- if (strcmp(provider_name, "windows") == 0 &&
- strcmp(provider_type, "simple") == 0)
- {
- auth_get_windows_simple_provider(provider, pool);
- }
- else if (strcmp(provider_name, "windows") == 0 &&
- strcmp(provider_type, "ssl_client_cert_pw") == 0)
- {
- auth_get_windows_ssl_client_cert_pw_provider(provider, pool);
- }
- else if (strcmp(provider_name, "windows") == 0 &&
- strcmp(provider_type, "ssl_server_trust") == 0)
- {
- auth_get_windows_ssl_server_trust_provider(provider, pool);
- }
- }
- return WEBDAV_NO_ERROR;
- }
- #define WEBDAV_MAYBE_ADD_PROVIDER(list, p) \
- { if (p) APR_ARRAY_PUSH(list, auth_provider_object_t *) = p; }
- static error_t
- auth_get_platform_specific_client_providers(
- apr_array_header_t ** providers,
- apr_pool_t * pool)
- {
- auth_provider_object_t * provider;
- const char * password_stores_config_option;
- apr_array_header_t * password_stores;
- int i;
- password_stores_config_option = "windows-cryptoapi";
- *providers = apr_array_make(pool, 12, sizeof(auth_provider_object_t *));
- password_stores = cstring_split(password_stores_config_option, " ,", TRUE, pool);
- for (i = 0; i < password_stores->nelts; i++)
- {
- const char * password_store = APR_ARRAY_IDX(password_stores, i,
- const char *);
- // Windows
- if (apr_strnatcmp(password_store, "windows-cryptoapi") == 0)
- {
- WEBDAV_ERR(auth_get_platform_specific_provider(&provider,
- "windows",
- "simple",
- pool));
- WEBDAV_MAYBE_ADD_PROVIDER(*providers, provider);
- WEBDAV_ERR(auth_get_platform_specific_provider(&provider,
- "windows",
- "ssl_client_cert_pw",
- pool));
- WEBDAV_MAYBE_ADD_PROVIDER(*providers, provider);
- continue;
- }
- return error_createf(WEBDAV_ERR_BAD_CONFIG_VALUE, NULL,
- "Invalid config: unknown password store "
- "'%s'",
- password_store);
- }
- return WEBDAV_NO_ERROR;
- }
- //------------------------------------------------------------------------------
- // from dirent_uri.c
- // TRUE if s is the canonical empty path, FALSE otherwise
- #define PATH_IS_EMPTY(s) ((s)[0] == '\0')
- // Path separator for local filesystem
- #define WEBDAV_PATH_LOCAL_SEPARATOR '\\'
- // Path type definition. Used only by internal functions.
- typedef enum path_type_t
- {
- type_uri,
- type_dirent,
- type_relpath
- } path_type_t;
- // Locale insensitive tolower() for converting parts of dirents and urls
- // while canonicalizing
- static char
- canonicalize_to_lower(char c)
- {
- if (c < 'A' || c > 'Z')
- return c;
- else
- return c - 'A' + 'a';
- }
- // Locale insensitive toupper() for converting parts of dirents and urls
- // while canonicalizing
- static char
- canonicalize_to_upper(char c)
- {
- if (c < 'a' || c > 'z')
- return c;
- else
- return c - 'a' + 'A';
- }
- // Return the canonicalized version of PATH, of type TYPE, allocated in POOL.
- static const char *
- canonicalize(
- path_type_t type,
- const char * path,
- apr_pool_t * pool)
- {
- char * canon = NULL, *dst = NULL;
- const char * src = NULL;
- size_t seglen = 0;
- size_t schemelen = 0;
- size_t canon_segments = 0;
- bool url = FALSE;
- char * schema_data = NULL;
- // "" is already canonical, so just return it; note that later code
- // depends on path not being zero-length.
- if (PATH_IS_EMPTY(path))
- {
- assert(type != type_uri);
- return "";
- }
- dst = canon = static_cast<char *>(apr_pcalloc(pool, strlen(path) + 1));
- // If this is supposed to be an URI, it should start with
- // "scheme://". We'll copy the scheme, host name, etc. to DST and
- // set URL = TRUE.
- src = path;
- if (type == type_uri)
- {
- assert(*src != '/');
- while (*src && (*src != '/') && (*src != ':'))
- src++;
- if ((*src == ':') && (*(src+1) == '/') && (*(src+2) == '/'))
- {
- const char * seg;
- url = TRUE;
- // Found a scheme, convert to lowercase and copy to dst.
- src = path;
- while (*src != ':')
- {
- *(dst++) = canonicalize_to_lower((*src++));
- schemelen++;
- }
- *(dst++) = ':';
- *(dst++) = '/';
- *(dst++) = '/';
- src += 3;
- schemelen += 3;
- // This might be the hostname
- seg = src;
- while (*src && (*src != '/') && (*src != '@'))
- src++;
- if (*src == '@')
- {
- // Copy the username & password.
- seglen = src - seg + 1;
- memcpy(dst, seg, seglen);
- dst += seglen;
- src++;
- }
- else
- src = seg;
- // Found a hostname, convert to lowercase and copy to dst.
- while (*src && (*src != '/') && (*src != ':'))
- *(dst++) = canonicalize_to_lower((*src++));
- if (*src == ':')
- {
- // We probably have a port number: Is it a default portnumber
- // which doesn't belong in a canonical url?
- if ((src[1] == '8') && (src[2] == '0') &&
- ((src[3] == '/') || !src[3]) &&
- !strncmp(canon, "http:", 5))
- {
- src += 3;
- }
- else if ((src[1] == '4') && (src[2] == '4') && (src[3] == '3') &&
- ((src[4] == '/') || !src[4]) &&
- !strncmp(canon, "https:", 6))
- {
- src += 4;
- }
- else if ((src[1] == '/') || !src[1])
- {
- src += 1;
- }
- while (*src && (*src != '/'))
- *(dst++) = canonicalize_to_lower((*src++));
- }
- // Copy trailing slash, or null-terminator.
- *(dst) = *(src);
- // Move src and dst forward only if we are not
- // at null-terminator yet.
- if (*src)
- {
- src++;
- dst++;
- schema_data = dst;
- }
- canon_segments = 1;
- }
- }
- // Copy to DST any separator or drive letter that must come before the
- // first regular path segment.
- if (!url && type != type_relpath)
- {
- src = path;
- // If this is an absolute path, then just copy over the initial
- // separator character.
- if (*src == '/')
- {
- *(dst++) = *(src++);
- // On Windows permit two leading separator characters which means an
- // UNC path.
- if ((type == type_dirent) && (*src == '/'))
- *(dst++) = *(src++);
- }
- // On Windows the first segment can be a drive letter, which we normalize
- // to upper case.
- else if ((type == type_dirent) &&
- ((*src >= 'a' && *src <= 'z') ||
- (*src >= 'A' && *src <= 'Z')) &&
- (src[1] == ':'))
- {
- *(dst++) = canonicalize_to_upper(*(src++));
- // Leave the ':' to be processed as (or as part of) a path segment
- // by the following code block, so we need not care whether it has
- // a slash after it.
- }
- }
- while (*src)
- {
- // Parse each segment, finding the closing '/' (which might look
- // like '%2F' for URIs).
- const char * next = src;
- size_t slash_len = 0;
- while (*next &&
- (next[0] != '/') &&
- (!((type == type_uri) && (next[0] == '%') && (next[1] == '2') &&
- (canonicalize_to_upper(next[2]) == 'F'))))
- {
- ++next;
- }
- // Record how long our "slash" is.
- if (next[0] == '/')
- slash_len = 1;
- else if ((type == type_uri) && (next[0] == '%'))
- slash_len = 3;
- seglen = next - src;
- if ((seglen == 0) ||
- ((seglen == 1) && (src[0] == '.')) ||
- ((type == type_uri) && (seglen == 3) && (src[0] == '%') && (src[1] == '2') &&
- (canonicalize_to_upper(src[2]) == 'E')))
- {
- // Empty or noop segment, so do nothing. (For URIs, '%2E'
- // is equivalent to '.').
- }
- // If this is the first path segment of a file:// URI and it contains a
- // windows drive letter, convert the drive letter to upper case.
- else if (url && (canon_segments == 1) && (seglen == 2) &&
- (strncmp(canon, "file:", 5) == 0) &&
- (src[0] >= 'a') && (src[0] <= 'z') && (src[1] == ':'))
- {
- *(dst++) = canonicalize_to_upper(src[0]);
- *(dst++) = ':';
- if (*next)
- *(dst++) = *next;
- canon_segments++;
- }
- else
- {
- // An actual segment, append it to the destination path
- memcpy(dst, src, seglen);
- dst += seglen;
- if (slash_len)
- {
- *(dst++) = '/';
- }
- canon_segments++;
- }
- // Skip over trailing slash to the next segment.
- src = next + slash_len;
- }
- *dst = '\0';
- // Skip leading double slashes when there are less than 2
- // canon segments. UNC paths *MUST* have two segments.
- if ((type == type_dirent) && (canon[0] == '/') && (canon[1] == '/'))
- {
- if (canon_segments < 2)
- return canon + 1;
- else
- {
- // Now we're sure this is a valid UNC path, convert the server name
- // (the first path segment) to lowercase as Windows treats it as case
- // insensitive.
- // Note: normally the share name is treated as case insensitive too,
- // but it seems to be possible to configure Samba to treat those as
- // case sensitive, so better leave that alone.
- for (dst = canon + 2; *dst && (*dst != '/'); dst++)
- *dst = canonicalize_to_lower(*dst);
- }
- }
- // Check the normalization of characters in a uri
- if (schema_data)
- {
- int need_extra = 0;
- src = schema_data;
- while (*src)
- {
- switch (*src)
- {
- case '/':
- break;
- case '%':
- if (!ctype_isxdigit(*(src+1)) ||
- !ctype_isxdigit(*(src+2)))
- need_extra += 2;
- else
- src += 2;
- break;
- default:
- if (!uri_char_validity[(unsigned char)*src])
- need_extra += 2;
- break;
- }
- src++;
- }
- if (need_extra > 0)
- {
- size_t pre_schema_size = (size_t)(schema_data - canon);
- dst = static_cast<char *>(apr_pcalloc(pool, (size_t)(src - canon) + need_extra + 1));
- memcpy(dst, canon, pre_schema_size);
- canon = dst;
- dst += pre_schema_size;
- }
- else
- dst = schema_data;
- src = schema_data;
- while (*src)
- {
- switch (*src)
- {
- case '/':
- *(dst++) = '/';
- break;
- case '%':
- if (!ctype_isxdigit(*(src+1)) ||
- !ctype_isxdigit(*(src+2)))
- {
- *(dst++) = '%';
- *(dst++) = '2';
- *(dst++) = '5';
- }
- else
- {
- char digitz[3];
- int val;
- digitz[0] = *(++src);
- digitz[1] = *(++src);
- digitz[2] = 0;
- val = (int)strtol(digitz, NULL, 16);
- if (uri_char_validity[(unsigned char)val])
- *(dst++) = (char)val;
- else
- {
- *(dst++) = '%';
- *(dst++) = canonicalize_to_upper(digitz[0]);
- *(dst++) = canonicalize_to_upper(digitz[1]);
- }
- }
- break;
- default:
- if (!uri_char_validity[(unsigned char)*src])
- {
- apr_snprintf(dst, 4, "%%%02X", (unsigned char)*src);
- dst += 3;
- }
- else
- *(dst++) = *src;
- break;
- }
- src++;
- }
- *dst = '\0';
- }
- return canon;
- }
- static const char *
- uri_canonicalize(
- const char * uri,
- apr_pool_t * pool)
- {
- return canonicalize(type_uri, uri, pool);
- }
- static const char *
- relpath_canonicalize(
- const char * relpath,
- apr_pool_t * pool)
- {
- return canonicalize(type_relpath, relpath, pool);
- }
- static const char *
- fspath_canonicalize(
- const char * fspath,
- apr_pool_t * pool)
- {
- if ((fspath[0] == '/') && (fspath[1] == '\0'))
- return "/";
- return apr_pstrcat(pool, "/", relpath_canonicalize(fspath, pool),
- (char *)NULL);
- }
- // Examine PATH as a potential URI, and return a substring of PATH
- // that immediately follows the (scheme):// portion of the URI, or
- // NULL if PATH doesn't appear to be a valid URI. The returned value
- // is not allocated -- it shares memory with PATH.
- static const char *
- skip_uri_scheme(
- const char * path)
- {
- size_t j = 0;
- // A scheme is terminated by a : and cannot contain any /'s.
- for (j = 0; path[j] && (path[j] != ':'); ++j)
- if (path[j] == '/')
- return NULL;
- if ((j > 0) && (path[j] == ':') && (path[j+1] == '/') && (path[j+2] == '/'))
- return path + j + 3;
- return NULL;
- }
- static bool
- path_is_url(
- const char * path)
- {
- // This function is reaaaaaaaaaaaaaally stupid right now.
- // We're just going to look for:
- // (scheme)://(optional_stuff)
- // Where (scheme) has no ':' or '/' characters.
- // Someday it might be nice to have an actual URI parser here.
- return skip_uri_scheme(path) != NULL;
- }
- static const char *
- urlpath_canonicalize(
- const char * uri,
- apr_pool_t * pool)
- {
- if (path_is_url(uri))
- {
- uri = uri_canonicalize(uri, pool);
- }
- else
- {
- uri = fspath_canonicalize(uri, pool);
- // Do a little dance to normalize hex encoding.
- uri = path_uri_decode(uri, pool);
- uri = path_uri_encode(uri, pool);
- }
- return uri;
- }
- // We decided against using apr_filepath_root here because of the negative
- // performance impact (creating a pool and converting strings ).
- static bool
- dirent_is_root(
- const char * dirent,
- apr_size_t len)
- {
- // On Windows and Cygwin, 'H:' or 'H:/' (where 'H' is any letter)
- // are also root directories
- if ((len == 2 || ((len == 3) && (dirent[2] == '/'))) &&
- (dirent[1] == ':') &&
- ((dirent[0] >= 'A' && dirent[0] <= 'Z') ||
- (dirent[0] >= 'a' && dirent[0] <= 'z')))
- return TRUE;
- // On Windows and Cygwin //server/share is a root directory,
- // and on Cygwin //drive is a drive alias
- if ((len >= 2) && (dirent[0] == '/') && (dirent[1] == '/') &&
- (dirent[len - 1] != '/'))
- {
- int segments = 0;
- for (size_t i = len; i >= 2; i--)
- {
- if (dirent[i] == '/')
- {
- segments++;
- if (segments > 1)
- return FALSE;
- }
- }
- return (segments == 1); // //drive is invalid on plain Windows
- }
- // directory is root if it's equal to '/'
- if ((len == 1) && (dirent[0] == '/'))
- return TRUE;
- return FALSE;
- }
- static bool
- relpath_is_canonical(
- const char * relpath)
- {
- const char * ptr = relpath, *seg = relpath;
- // RELPATH is canonical if it has:
- // - no '.' segments
- // - no start and closing '/'
- // - no '//'
- if (*relpath == '\0')
- return TRUE;
- if (*ptr == '/')
- return FALSE;
- // Now validate the rest of the path.
- while (1)
- {
- apr_size_t seglen = ptr - seg;
- if ((seglen == 1) && (*seg == '.'))
- return FALSE; // /./
- if ((*ptr == '/') && (*(ptr+1) == '/'))
- return FALSE; // //
- if (!*ptr && (*(ptr - 1) == '/'))
- return FALSE; // foo/
- if (!*ptr)
- break;
- if (*ptr == '/')
- ptr++;
- seg = ptr;
- while (*ptr && (*ptr != '/'))
- ptr++;
- }
- return TRUE;
- }
- static const char *
- relpath_basename(
- const char * relpath,
- apr_pool_t * pool)
- {
- apr_size_t len = strlen(relpath);
- apr_size_t start = 0;
- assert(relpath_is_canonical(relpath));
- start = len;
- while ((start > 0) && (relpath[start - 1] != '/'))
- --start;
- if (pool)
- return apr_pstrmemdup(pool, relpath + start, len - start);
- else
- return relpath + start;
- }
- static char *
- relpath_join(
- const char * base,
- const char * component,
- apr_pool_t * pool)
- {
- apr_size_t blen = strlen(base);
- apr_size_t clen = strlen(component);
- char * path = NULL;
- assert(relpath_is_canonical(base));
- assert(relpath_is_canonical(component));
- // If either is empty return the other
- if (blen == 0)
- return static_cast<char *>(apr_pmemdup(pool, component, clen + 1));
- if (clen == 0)
- return static_cast<char *>(apr_pmemdup(pool, base, blen + 1));
- path = static_cast<char *>(apr_pcalloc(pool, blen + 1 + clen + 1));
- memcpy(path, base, blen);
- path[blen] = '/';
- memcpy(path + blen + 1, component, clen + 1);
- return path;
- }
- static const char *
- dirent_canonicalize(
- const char * dirent,
- apr_pool_t * pool)
- {
- const char * dst = canonicalize(type_dirent, dirent, pool);
- // Handle a specific case on Windows where path == "X:/". Here we have to
- // append the final '/', as path_canonicalize will chop this of.
- if (((dirent[0] >= 'A' && dirent[0] <= 'Z') ||
- (dirent[0] >= 'a' && dirent[0] <= 'z')) &&
- (dirent[1] == ':') && (dirent[2] == '/') &&
- (dst[3] == '\0'))
- {
- char * dst_slash = static_cast<char *>(apr_pcalloc(pool, 4));
- dst_slash[0] = canonicalize_to_upper(dirent[0]);
- dst_slash[1] = ':';
- dst_slash[2] = '/';
- dst_slash[3] = '\0';
- return dst_slash;
- }
- return dst;
- }
- static bool
- dirent_is_canonical(
- const char * dirent,
- apr_pool_t * pool)
- {
- const char * ptr = dirent;
- if (*ptr == '/')
- {
- ptr++;
- // Check for UNC paths
- if (*ptr == '/')
- {
- // TODO: Scan hostname and sharename and fall back to part code
- // Fall back to old implementation
- return (strcmp(dirent, dirent_canonicalize(dirent, pool)) == 0);
- }
- }
- else if (((*ptr >= 'a' && *ptr <= 'z') || (*ptr >= 'A' && *ptr <= 'Z')) &&
- (ptr[1] == ':'))
- {
- // The only canonical drive names are "A:"..."Z:", no lower case
- if (*ptr < 'A' || *ptr > 'Z')
- return FALSE;
- ptr += 2;
- if (*ptr == '/')
- ptr++;
- }
- return relpath_is_canonical(ptr);
- }
- static const char *
- dirent_basename(
- const char * dirent,
- apr_pool_t * pool)
- {
- apr_size_t len = strlen(dirent);
- apr_size_t start = 0;
- assert(!pool || dirent_is_canonical(dirent, pool));
- if (dirent_is_root(dirent, len))
- {
- return "";
- }
- else
- {
- start = len;
- while ((start > 0) && (dirent[start - 1] != '/') &&
- (dirent[start - 1] != ':'))
- {
- --start;
- }
- }
- if (pool)
- return apr_pstrmemdup(pool, dirent + start, len - start);
- else
- return dirent + start;
- }
- static const char *
- uri_skip_ancestor(
- const char * parent_uri,
- const char * child_uri)
- {
- apr_size_t len = strlen(parent_uri);
- if (0 != strncmp(parent_uri, child_uri, len))
- return NULL; // parent_uri is no ancestor of child_uri
- if (child_uri[len] == 0)
- return ""; // parent_uri == child_uri
- if (child_uri[len] == '/')
- return child_uri + len + 1;
- return NULL;
- }
- static const char *
- uri_skip_ancestor(
- const char * parent_uri,
- const char * child_uri,
- apr_pool_t * result_pool)
- {
- const char * result = uri_skip_ancestor(parent_uri, child_uri);
- return result ? path_uri_decode(result, result_pool) : NULL;
- }
- static bool
- dirent_is_rooted(
- const char * dirent)
- {
- if (!dirent)
- return FALSE;
- // Root on all systems
- if (dirent[0] == '/')
- return TRUE;
- // On Windows, dirent is also absolute when it starts with 'H:' or 'H:/'
- // where 'H' is any letter.
- if (((dirent[0] >= 'A' && dirent[0] <= 'Z') ||
- (dirent[0] >= 'a' && dirent[0] <= 'z')) &&
- (dirent[1] == ':'))
- {
- return TRUE;
- }
- return FALSE;
- }
- static const char *
- is_child(
- path_type_t type,
- const char * path1,
- const char * path2,
- apr_pool_t * pool)
- {
- apr_size_t i = 0;
- // Allow "" and "foo" or "H:foo" to be parent/child
- if (WEBDAV_PATH_IS_EMPTY(path1)) // "" is the parent
- {
- if (WEBDAV_PATH_IS_EMPTY(path2)) // "" not a child
- {
- return NULL;
- }
- // check if this is an absolute path
- if ((type == type_uri) ||
- (type == type_dirent && dirent_is_rooted(path2)))
- {
- return NULL;
- }
- else
- {
- // everything else is child
- return pool ? apr_pstrdup(pool, path2) : path2;
- }
- }
- for (i = 0; path1[i] && path2[i]; i++)
- if (path1[i] != path2[i])
- {
- return NULL;
- }
- /* FIXME: This comment does not really match
- the checks made in the code it refers to:
- There are two cases that are parent/child
- ... path1[i] == '\0'
- .../foo path2[i] == '/'
- or
- / path1[i] == '\0'
- /foo path2[i] != '/'
- Other root paths (like X:/) fall under the former case:
- X:/ path1[i] == '\0'
- X:/foo path2[i] != '/'
- Check for '//' to avoid matching '/' and '//srv'.
- */
- if ((path1[i] == '\0') && path2[i])
- {
- if ((path1[i - 1] == '/') ||
- ((type == type_dirent) && path1[i - 1] == ':'))
- {
- if (path2[i] == '/')
- /* .../
- * ..../
- * i */
- return NULL;
- else
- /* .../
- * .../foo
- * i */
- return pool ? apr_pstrdup(pool, path2 + i) : path2 + i;
- }
- else if (path2[i] == '/')
- {
- if (path2[i + 1])
- /* ...
- * .../foo
- * i */
- return pool ? apr_pstrdup(pool, path2 + i + 1) : path2 + i + 1;
- else
- /* ...
- * .../
- * i */
- return NULL;
- }
- }
- // Otherwise, path2 isn't a child.
- return NULL;
- }
- static const char *
- uri_is_child(
- const char * parent_uri,
- const char * child_uri,
- apr_pool_t * pool)
- {
- const char * relpath = NULL;
- assert(pool); // hysterical raisins.
- relpath = is_child(type_uri, parent_uri, child_uri, pool);
- if (relpath)
- relpath = path_uri_decode(relpath, pool);
- return relpath;
- }
- static bool
- dirent_is_absolute(
- const char * dirent)
- {
- if (!dirent)
- return FALSE;
- // dirent is absolute if it starts with '/' on non-Windows platforms
- // or with '//' on Windows platforms
- if ((dirent[0] == '/') &&
- (dirent[1] == '/')) // Single '/' depends on current drive
- {
- return TRUE;
- }
- // On Windows, dirent is also absolute when it starts with 'H:/'
- // where 'H' is any letter.
- if (((dirent[0] >= 'A' && dirent[0] <= 'Z')) &&
- (dirent[1] == ':') && (dirent[2] == '/'))
- {
- return TRUE;
- }
- return FALSE;
- }
- static error_t
- dirent_get_absolute(
- const char ** pabsolute,
- const char * relative,
- apr_pool_t * pool)
- {
- char * buffer = NULL;
- apr_status_t apr_err = 0;
- const char * path_apr = NULL;
- WEBDAV_ERR_ASSERT(!path_is_url(relative));
- // Merge the current working directory with the relative dirent.
- WEBDAV_ERR(path_cstring_from_utf8(&path_apr, relative, pool));
- apr_err = apr_filepath_merge(&buffer, NULL,
- path_apr,
- APR_FILEPATH_NOTRELATIVE,
- pool);
- if (apr_err)
- {
- // In some cases when the passed path or its ancestor(s) do not exist
- // or no longer exist apr returns an error.
- // In many of these cases we would like to return a path anyway, when the
- // passed path was already a safe absolute path. So check for that now to
- // avoid an error.
- // dirent_is_absolute() doesn't perform the necessary checks to see
- // if the path doesn't need post processing to be in the canonical absolute
- // format.
- if (dirent_is_absolute(relative) &&
- dirent_is_canonical(relative, pool) &&
- !path_is_backpath_present(relative))
- {
- *pabsolute = apr_pstrdup(pool, relative);
- return WEBDAV_NO_ERROR;
- }
- return error_createf(WEBDAV_ERR_BAD_FILENAME,
- NULL,
- "Couldn't determine absolute path of '%s'", relative);
- }
- WEBDAV_ERR(path_cstring_to_utf8(pabsolute, buffer, pool));
- *pabsolute = dirent_canonicalize(*pabsolute, pool);
- return WEBDAV_NO_ERROR;
- }
- //------------------------------------------------------------------------------
- // from atomic.c
- #define atomic_t apr_uint32_t
- // Magic values for atomic initialization
- #define WEBDAV_ATOMIC_UNINITIALIZED 0
- #define WEBDAV_ATOMIC_START_INIT 1
- #define WEBDAV_ATOMIC_INIT_FAILED 2
- #define WEBDAV_ATOMIC_INITIALIZED 3
- static error_t
- atomic_init_once(
- volatile atomic_t * global_status,
- error_t (*init_func)(void *,apr_pool_t *),
- void * baton,
- apr_pool_t * pool)
- {
- // We have to call init_func exactly once. Because APR
- // doesn't have statically-initialized mutexes, we implement a poor
- // man's spinlock using atomic_cas.
- atomic_t status = apr_atomic_cas32(global_status,
- WEBDAV_ATOMIC_START_INIT,
- WEBDAV_ATOMIC_UNINITIALIZED);
- if (status == WEBDAV_ATOMIC_UNINITIALIZED)
- {
- error_t err = init_func(baton, pool);
- if (err)
- {
- #if APR_HAS_THREADS
- // Tell other threads that the initialization failed.
- apr_atomic_cas32(global_status,
- WEBDAV_ATOMIC_INIT_FAILED,
- WEBDAV_ATOMIC_START_INIT);
- #endif
- return error_create(WEBDAV_ERR_ATOMIC_INIT_FAILURE, &err,
- "Couldn't perform atomic initialization");
- }
- apr_atomic_cas32(global_status,
- WEBDAV_ATOMIC_INITIALIZED,
- WEBDAV_ATOMIC_START_INIT);
- }
- #if APR_HAS_THREADS
- // Wait for whichever thread is performing initialization to finish.
- // XXX FIXME: Should we have a maximum wait here, like we have in
- // the Windows file IO spinner?
- else while (status != WEBDAV_ATOMIC_INITIALIZED)
- {
- if (status == WEBDAV_ATOMIC_INIT_FAILED)
- return error_create(WEBDAV_ERR_ATOMIC_INIT_FAILURE, NULL,
- "Couldn't perform atomic initialization");
- apr_sleep(APR_USEC_PER_SEC / 1000);
- status = apr_atomic_cas32(global_status,
- WEBDAV_ATOMIC_UNINITIALIZED,
- WEBDAV_ATOMIC_UNINITIALIZED);
- }
- #endif // APR_HAS_THREADS
- return WEBDAV_NO_ERROR;
- }
- //------------------------------------------------------------------------------
- // from io.c
- #define RETRY_MAX_ATTEMPTS 2
- #define RETRY_INITIAL_SLEEP 1000
- #define RETRY_MAX_SLEEP 128000
- // Suppress warning: Condition is always true
- #pragma warn -8008
- #define RETRY_LOOP(err, expr, retry_test, sleep_test) \
- do \
- { \
- apr_status_t os_err = APR_TO_OS_ERROR(err); \
- int sleep_count = RETRY_INITIAL_SLEEP; \
- int retries; \
- for (retries = 0; \
- retries < RETRY_MAX_ATTEMPTS && (retry_test); \
- os_err = APR_TO_OS_ERROR(err)) \
- { \
- if (sleep_test) \
- { \
- ++retries; \
- apr_sleep(sleep_count); \
- if (sleep_count < RETRY_MAX_SLEEP) \
- sleep_count *= 2; \
- } \
- (err) = (expr); \
- } \
- } \
- while (0)
- #if defined(EDEADLK) && APR_HAS_THREADS
- #define FILE_LOCK_RETRY_LOOP(err, expr) \
- RETRY_LOOP(err, \
- expr, \
- (APR_STATUS_IS_EINTR(err) || os_err == EDEADLK), \
- (!APR_STATUS_IS_EINTR(err)))
- #else
- #define FILE_LOCK_RETRY_LOOP(err, expr) \
- RETRY_LOOP(err, \
- expr, \
- (APR_STATUS_IS_EINTR(err)), \
- 0)
- #endif
- #ifndef WIN32_RETRY_LOOP
- #if !defined(WEBDAV_NO_WIN32_RETRY_LOOP)
- #define WIN32_RETRY_LOOP(err, expr) \
- RETRY_LOOP(err, expr, (os_err == ERROR_ACCESS_DENIED || \
- os_err == ERROR_SHARING_VIOLATION || \
- os_err == ERROR_DIR_NOT_EMPTY), \
- 1)
- #else
- #define WIN32_RETRY_LOOP(err, expr) ((void)0)
- #endif
- #endif
- // Not specifying any of these means no removal at all.
- typedef enum io_file_del_t
- {
- // No deletion ever
- io_file_del_none = 0,
- // Remove when the file is closed
- io_file_del_on_close,
- // Remove when the associated pool is cleared
- io_file_del_on_pool_cleanup
- } io_file_del_t;
- // Wrapper for apr_file_open(), taking an APR-encoded filename.
- static apr_status_t
- file_open(
- apr_file_t ** file,
- const char * fname_apr,
- apr_int32_t flags,
- apr_fileperms_t perm,
- bool retry_on_failure,
- apr_pool_t * pool)
- {
- apr_status_t status = apr_file_open(file, fname_apr, flags, perm, pool);
- if (retry_on_failure)
- {
- WIN32_RETRY_LOOP(status, apr_file_open(file, fname_apr, flags, perm, pool));
- }
- return status;
- }
- #pragma warn +8008
- static error_t
- io_file_open(
- apr_file_t ** new_file,
- const char * fname,
- apr_int32_t flags,
- apr_fileperms_t perms,
- apr_pool_t * pool)
- {
- const char * fname_apr = NULL;
- apr_status_t status = 0;
- WEBDAV_ERR(cstring_from_utf8(&fname_apr, fname, pool));
- status = file_open(new_file, fname_apr, flags | APR_BINARY, perms,
- /* retry_on_failure */ FALSE,
- pool);
- if (status)
- return error_wrap_apr(status, "Can't open file '%s'", fname);
- else
- return WEBDAV_NO_ERROR;
- }
- static error_t
- io_file_open_writable(
- apr_file_t ** new_file,
- apr_os_file_t * thefile,
- apr_int32_t flags,
- apr_pool_t * pool)
- {
- apr_status_t status = 0;
- status = apr_os_file_put(new_file, thefile,
- flags | APR_BINARY,
- pool);
- if (status)
- return error_wrap_apr(status, "Can't open file");
- else
- return WEBDAV_NO_ERROR;
- }
- // Wrapper for apr_file_name_get(), passing out a UTF8-encoded filename.
- static error_t
- io_file_name_get(
- const char ** filename,
- apr_file_t * file,
- apr_pool_t * pool)
- {
- const char * fname_apr = NULL;
- apr_status_t status = 0;
- status = apr_file_name_get(&fname_apr, file);
- if (status)
- return error_wrap_apr(status, "Can't get file name");
- if (fname_apr)
- WEBDAV_ERR(path_cstring_to_utf8(filename, fname_apr, pool));
- else
- *filename = NULL;
- return WEBDAV_NO_ERROR;
- }
- static APR_INLINE error_t
- do_io_file_wrapper_cleanup(
- apr_file_t * file,
- apr_status_t status,
- const char * msg,
- const char * msg_no_name,
- apr_pool_t * pool)
- {
- const char * name = NULL;
- error_t err = 0;
- if (!status)
- return WEBDAV_NO_ERROR;
- err = io_file_name_get(&name, file, pool);
- if (err)
- name = NULL;
- error_clear(&err);
- // Issue #3014: Return a specific error for broken pipes,
- // with a single element in the error chain.
- if (APR_STATUS_IS_EPIPE(status))
- return error_create(WEBDAV_ERR_IO_PIPE_WRITE_ERROR, NULL, NULL);
- if (name)
- return error_wrap_apr(status, msg, name);
- else
- return error_wrap_apr(status, "%s", msg_no_name);
- }
- static error_t
- io_file_close(
- apr_file_t * file,
- apr_pool_t * pool)
- {
- return do_io_file_wrapper_cleanup(file, apr_file_close(file),
- "Can't close file '%s'",
- "Can't close stream",
- pool);
- }
- static error_t
- io_file_getc(
- char * ch,
- apr_file_t * file,
- apr_pool_t * pool)
- {
- return do_io_file_wrapper_cleanup(file, apr_file_getc(ch, file),
- "Can't read file '%s'",
- "Can't read stream",
- pool);
- }
- static error_t
- io_file_write_full(
- apr_file_t * file,
- const void * buf,
- apr_size_t nbytes,
- apr_size_t * bytes_written,
- apr_pool_t * pool)
- {
- // We cannot simply call apr_file_write_full on Win32 as it may fail
- // for larger values of NBYTES. In that case, we have to emulate the
- // "_full" part here. Thus, always call apr_file_write directly on
- // Win32 as this minimizes overhead for small data buffers.
- #define MAXBUFSIZE 64*1024
- apr_size_t bw = nbytes;
- apr_size_t to_write = nbytes;
- // try a simple "write everything at once" first
- apr_status_t rv = apr_file_write(file, buf, &bw);
- buf = (char *)buf + bw;
- to_write -= bw;
- // if the OS cannot handle that, use smaller chunks
- if ((rv == APR_FROM_OS_ERROR(ERROR_NOT_ENOUGH_MEMORY)) &&
- (nbytes > MAXBUFSIZE))
- {
- do
- {
- bw = to_write > MAXBUFSIZE ? MAXBUFSIZE : to_write;
- rv = apr_file_write(file, buf, &bw);
- buf = (char *)buf + bw;
- to_write -= bw;
- }
- while (rv == APR_SUCCESS && to_write > 0);
- }
- // bytes_written may actually be NULL
- if (bytes_written)
- *bytes_written = nbytes - to_write;
- #undef MAXBUFSIZE
- return error_trace(do_io_file_wrapper_cleanup(file, rv,
- "Can't write to file '%s'",
- "Can't write to stream",
- pool));
- }
- static error_t
- io_file_seek(
- apr_file_t * file,
- apr_seek_where_t where,
- apr_off_t * offset,
- apr_pool_t * pool)
- {
- return do_io_file_wrapper_cleanup(file, apr_file_seek(file, where, offset),
- "Can't set position pointer in file '%s'",
- "Can't set position pointer in stream",
- pool);
- }
- static error_t
- io_file_putc(
- char ch,
- apr_file_t * file,
- apr_pool_t * pool)
- {
- return do_io_file_wrapper_cleanup(file, apr_file_putc(ch, file),
- "Can't write file '%s'",
- "Can't write stream",
- pool);
- }
- static error_t
- io_file_read(
- apr_file_t * file,
- void * buf,
- apr_size_t * nbytes,
- apr_pool_t * pool)
- {
- return do_io_file_wrapper_cleanup(file, apr_file_read(file, buf, nbytes),
- "Can't read file '%s'",
- "Can't read stream",
- pool);
- }
- // Local wrapper of path_cstring_from_utf8() that does no copying on
- // operating systems where APR always uses utf-8 as native path format
- static error_t
- cstring_from_utf8(
- const char ** path_apr,
- const char * path_utf8,
- apr_pool_t * pool)
- {
- *path_apr = path_utf8;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- io_file_read_full2(
- apr_file_t * file,
- void * buf,
- apr_size_t nbytes,
- apr_size_t * bytes_read,
- bool * hit_eof,
- apr_pool_t * pool)
- {
- apr_status_t status = apr_file_read_full(file, buf, nbytes, bytes_read);
- if (hit_eof)
- {
- if (APR_STATUS_IS_EOF(status))
- {
- *hit_eof = TRUE;
- return WEBDAV_NO_ERROR;
- }
- else
- *hit_eof = FALSE;
- }
- return do_io_file_wrapper_cleanup(file, status,
- "Can't read file '%s'",
- "Can't read stream",
- pool);
- }
- //------------------------------------------------------------------------------
- // from svn_io.h
- // Read handler function for a generic stream. see stream_t.
- typedef error_t (*read_fn_t)(
- void * baton,
- char * buffer,
- apr_size_t * len);
- // Skip data handler function for a generic stream. see stream_t
- // and stream_skip().
- typedef error_t (*stream_skip_fn_t)(
- void * baton,
- apr_size_t len);
- // Write handler function for a generic stream. see stream_t.
- typedef error_t (*write_fn_t)(
- void * baton,
- const char * data,
- apr_size_t * len);
- // Close handler function for a generic stream. see stream_t.
- typedef error_t (*close_fn_t)(void * baton);
- typedef struct stream_mark_t stream_mark_t;
- typedef error_t (*stream_mark_fn_t)(
- void * baton,
- stream_mark_t ** mark,
- apr_pool_t * pool);
- typedef error_t (*stream_seek_fn_t)(
- void * baton,
- const stream_mark_t * mark);
- typedef bool (*stream_is_buffered_fn_t)(void * baton);
- //------------------------------------------------------------------------------
- // from stream.c
- typedef struct stream_t
- {
- void * baton;
- read_fn_t read_fn;
- stream_skip_fn_t skip_fn;
- write_fn_t write_fn;
- close_fn_t close_fn;
- stream_mark_fn_t mark_fn;
- stream_seek_fn_t seek_fn;
- stream_is_buffered_fn_t is_buffered_fn;
- } stream_t;
- // Generic stream for APR files
- struct baton_apr_t
- {
- apr_file_t * file;
- apr_pool_t * pool;
- };
- // stream_mark_t for streams backed by APR files.
- struct mark_apr_t
- {
- apr_off_t off;
- };
- static error_t
- read_handler_apr(
- void * baton,
- char * buffer,
- apr_size_t * len)
- {
- struct baton_apr_t * btn = static_cast<baton_apr_t *>(baton);
- error_t err = 0;
- bool eof = FALSE;
- if (*len == 1)
- {
- err = io_file_getc(buffer, btn->file, btn->pool);
- if (err)
- {
- *len = 0;
- if (APR_STATUS_IS_EOF(err))
- {
- error_clear(&err);
- err = WEBDAV_NO_ERROR;
- }
- }
- }
- else
- err = io_file_read_full2(btn->file, buffer, *len, len,
- &eof, btn->pool);
- return err;
- }
- static error_t
- skip_handler_apr(
- void * baton,
- apr_size_t len)
- {
- struct baton_apr_t * btn = static_cast<baton_apr_t *>(baton);
- apr_off_t offset = len;
- return io_file_seek(btn->file, APR_CUR, &offset, btn->pool);
- }
- static error_t
- write_handler_apr(
- void * baton,
- const char * data,
- apr_size_t * len)
- {
- struct baton_apr_t * btn = static_cast<baton_apr_t *>(baton);
- error_t err = 0;
- if (*len == 1)
- {
- err = io_file_putc(*data, btn->file, btn->pool);
- if (err)
- *len = 0;
- }
- else
- err = io_file_write_full(btn->file, data, *len, len, btn->pool);
- return err;
- }
- static error_t
- close_handler_apr(
- void * baton)
- {
- struct baton_apr_t * btn = static_cast<baton_apr_t *>(baton);
- return io_file_close(btn->file, btn->pool);
- }
- static error_t
- mark_handler_apr(
- void * baton,
- stream_mark_t ** mark,
- apr_pool_t * pool)
- {
- struct baton_apr_t * btn = static_cast<baton_apr_t *>(baton);
- struct mark_apr_t * mark_apr = 0;
- mark_apr = static_cast<mark_apr_t *>(apr_pcalloc(pool, sizeof(*mark_apr)));
- mark_apr->off = 0;
- WEBDAV_ERR(io_file_seek(btn->file, APR_CUR, &mark_apr->off, btn->pool));
- *mark = (stream_mark_t *)mark_apr;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- seek_handler_apr(
- void * baton,
- const stream_mark_t * mark)
- {
- struct baton_apr_t * btn = static_cast<baton_apr_t *>(baton);
- apr_off_t offset = (mark != NULL) ? ((const struct mark_apr_t *)mark)->off : 0;
- WEBDAV_ERR(io_file_seek(btn->file, APR_SET, &offset, btn->pool));
- return WEBDAV_NO_ERROR;
- }
- static bool
- is_buffered_handler_apr(
- void * baton)
- {
- struct baton_apr_t * btn = static_cast<baton_apr_t *>(baton);
- return (apr_file_flags_get(btn->file) & APR_BUFFERED) != 0;
- }
- static stream_t *
- stream_create(
- void * baton,
- apr_pool_t * pool)
- {
- stream_t * stream = static_cast<stream_t *>(apr_pcalloc(pool, sizeof(*stream)));
- stream->baton = baton;
- stream->read_fn = NULL;
- stream->skip_fn = NULL;
- stream->write_fn = NULL;
- stream->close_fn = NULL;
- stream->mark_fn = NULL;
- stream->seek_fn = NULL;
- stream->is_buffered_fn = NULL;
- return stream;
- }
- static void
- stream_set_read(
- stream_t * stream,
- read_fn_t read_fn)
- {
- stream->read_fn = read_fn;
- }
- static void
- stream_set_skip(
- stream_t * stream,
- stream_skip_fn_t skip_fn)
- {
- stream->skip_fn = skip_fn;
- }
- static void
- stream_set_write(
- stream_t * stream,
- write_fn_t write_fn)
- {
- stream->write_fn = write_fn;
- }
- static void
- stream_set_close(
- stream_t * stream,
- close_fn_t close_fn)
- {
- stream->close_fn = close_fn;
- }
- static void
- stream_set_mark(
- stream_t * stream,
- stream_mark_fn_t mark_fn)
- {
- stream->mark_fn = mark_fn;
- }
- static void
- stream_set_seek(
- stream_t * stream,
- stream_seek_fn_t seek_fn)
- {
- stream->seek_fn = seek_fn;
- }
- static void
- stream_set_is_buffered(
- stream_t * stream,
- stream_is_buffered_fn_t is_buffered_fn)
- {
- stream->is_buffered_fn = is_buffered_fn;
- }
- static error_t
- read_handler_empty(
- void * baton,
- char * buffer,
- apr_size_t * len)
- {
- *len = 0;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- write_handler_empty(
- void * baton,
- const char * data,
- apr_size_t * len)
- {
- return WEBDAV_NO_ERROR;
- }
- static error_t
- mark_handler_empty(
- void * baton,
- stream_mark_t ** mark,
- apr_pool_t * pool)
- {
- *mark = NULL; // Seek to start of stream marker
- return WEBDAV_NO_ERROR;
- }
- static error_t
- seek_handler_empty(
- void * baton,
- const stream_mark_t * mark)
- {
- return WEBDAV_NO_ERROR;
- }
- static bool
- is_buffered_handler_empty(void * baton)
- {
- return FALSE;
- }
- static stream_t *
- stream_empty(
- apr_pool_t * pool)
- {
- stream_t * stream = stream_create(NULL, pool);
- stream_set_read(stream, read_handler_empty);
- stream_set_write(stream, write_handler_empty);
- stream_set_mark(stream, mark_handler_empty);
- stream_set_seek(stream, seek_handler_empty);
- stream_set_is_buffered(stream, is_buffered_handler_empty);
- return stream;
- }
- static stream_t *
- stream_from_aprfile2(
- apr_file_t * file,
- bool disown,
- apr_pool_t * pool)
- {
- stream_t * stream = NULL;
- if (file == NULL)
- return stream_empty(pool);
- baton_apr_t * baton = static_cast<baton_apr_t *>(apr_pcalloc(pool, sizeof(*baton)));
- baton->file = file;
- baton->pool = pool;
- stream = stream_create(baton, pool);
- stream_set_read(stream, read_handler_apr);
- stream_set_write(stream, write_handler_apr);
- stream_set_skip(stream, skip_handler_apr);
- stream_set_mark(stream, mark_handler_apr);
- stream_set_seek(stream, seek_handler_apr);
- stream_set_is_buffered(stream, is_buffered_handler_apr);
- if (!disown)
- stream_set_close(stream, close_handler_apr);
- return stream;
- }
- static error_t
- stream_open_writable(
- stream_t ** stream,
- apr_os_file_t * thefile,
- apr_pool_t * result_pool,
- apr_pool_t * scratch_pool)
- {
- apr_file_t * file = NULL;
- WEBDAV_ERR(io_file_open_writable(&file,
- thefile,
- APR_WRITE
- | APR_BUFFERED
- | APR_BINARY
- | APR_CREATE,
- // | APR_EXCL,
- result_pool));
- *stream = stream_from_aprfile2(file, FALSE, result_pool);
- return WEBDAV_NO_ERROR;
- }
- static error_t
- stream_write(
- stream_t * stream,
- const char * data,
- apr_size_t * len)
- {
- WEBDAV_ERR_ASSERT(stream->write_fn != NULL);
- return stream->write_fn(stream->baton, data, len);
- }
- static error_t
- stream_close(
- stream_t * stream)
- {
- if (stream->close_fn == NULL)
- return WEBDAV_NO_ERROR;
- return stream->close_fn(stream->baton);
- }
- //------------------------------------------------------------------------------
- // from util.c
- static apr_status_t
- dav_request_cleanup(
- void * baton);
- static apr_status_t
- dav_request_sess_cleanup(
- void * baton)
- {
- neon_request_t * req = static_cast<neon_request_t *>(baton);
- // Make sure we don't run the 'child' cleanup anymore:
- // the pool it refers to probably doesn't exist anymore when it
- // finally does get run if it hasn't by now.
- apr_pool_cleanup_kill(req->pool, req, dav_request_cleanup);
- if (req->ne_req)
- ne_request_destroy(req->ne_req);
- return APR_SUCCESS;
- }
- static apr_status_t
- dav_request_cleanup(
- void * baton)
- {
- neon_request_t * req = static_cast<neon_request_t *>(baton);
- apr_pool_cleanup_run(req->sess->pool, req, dav_request_sess_cleanup);
- return APR_SUCCESS;
- }
- // Return a path-absolute relative URL, given a URL reference (which may
- // be absolute or relative).
- static const char *
- path_from_url(
- const char * url)
- {
- const char * p = NULL;
- // Look for the scheme/authority separator. Stop if we see a path
- // separator - that indicates that this definitely isn't an absolute URL.
- for (p = url; *p; p++)
- {
- if ((*p == ':') || (*p == '/'))
- break;
- }
- // Check whether we found the scheme/authority separator.
- if ((*p++ != ':') || (*p++ != '/') || (*p++ != '/'))
- {
- // No separator, so it must already be relative.
- return url;
- }
- // Find the end of the authority section, indicated by the start of
- // a path, query, or fragment section.
- for (; *p; p++)
- {
- if ((*p == '/') || (*p == '?') || (*p == '#'))
- break;
- }
- // Return a pointer to the rest of the URL, or to "/" if there
- // was no next section.
- return *p == '\0' ? "/" : p;
- }
- // Simple multi-status parser
- // For the purpose of 'simple' requests which - if it weren't
- // for our custom error parser - could use the ne_basic.h interfaces.
- // List of XML elements expected in 207 Multi-Status responses.
- static const neon_xml_elm_t multistatus_elements[] =
- {
- { "DAV:", "multistatus", ELEM_multistatus, 0 },
- { "DAV:", "response", ELEM_response, 0 },
- {
- "DAV:", "responsedescription", ELEM_responsedescription,
- NEON_XML_CDATA
- },
- { "DAV:", "status", ELEM_status, NEON_XML_CDATA },
- { "DAV:", "href", ELEM_href, NEON_XML_CDATA },
- { "DAV:", "propstat", ELEM_propstat, NEON_XML_CDATA },
- { "DAV:", "prop", ELEM_prop, NEON_XML_CDATA },
- // We start out basic and are not interested in other elements
- { "", "", ELEM_unknown, 0 },
- { NULL }
- };
- static const int multistatus_nesting_table[][5] =
- {
- { ELEM_root, ELEM_multistatus, NEON_XML_INVALID },
- {
- ELEM_multistatus, ELEM_response, ELEM_responsedescription,
- NEON_XML_DECLINE
- },
- { ELEM_responsedescription, NEON_XML_INVALID },
- {
- ELEM_response, ELEM_href, ELEM_status, ELEM_propstat,
- NEON_XML_DECLINE
- },
- { ELEM_status, NEON_XML_INVALID },
- { ELEM_href, NEON_XML_INVALID },
- {
- ELEM_propstat, ELEM_prop, ELEM_status, ELEM_responsedescription,
- NEON_XML_INVALID
- },
- { ELEM_prop, NEON_XML_DECLINE },
- { NEON_XML_DECLINE },
- };
- static int
- multistatus_validate_element(
- int parent,
- int child)
- {
- int i = 0;
- int j = 0;
- while ((parent != multistatus_nesting_table[i][0]) &&
- (multistatus_nesting_table[i][0] > 0 || i == 0))
- i++;
- if (parent == multistatus_nesting_table[i][0])
- while ((multistatus_nesting_table[i][++j] != child) &&
- (multistatus_nesting_table[i][j] > 0))
- ;
- return multistatus_nesting_table[i][j];
- }
- typedef struct multistatus_baton_t
- {
- stringbuf_t * want_cdata;
- stringbuf_t * cdata;
- bool in_propstat;
- bool propstat_has_error;
- stringbuf_t * propname;
- stringbuf_t * propstat_description;
- neon_request_t * req;
- stringbuf_t * description;
- bool contains_error;
- bool contains_precondition_error;
- } multistatus_baton_t;
- // Implements neon_startelm_cb_t.
- static error_t
- start_207_element(
- int * elem,
- void * baton,
- int parent,
- const char * nspace,
- const char * name,
- const char ** atts)
- {
- multistatus_baton_t * b = static_cast<multistatus_baton_t *>(baton);
- const neon_xml_elm_t * elm =
- neon_lookup_xml_elem(multistatus_elements, nspace, name);
- *elem = elm ? multistatus_validate_element(parent, elm->id) : NEON_XML_DECLINE;
- if (parent == ELEM_prop)
- {
- stringbuf_setempty(b->propname);
- if (strcmp(nspace, "DAV:") == 0)
- stringbuf_set(b->propname, "DAV:");
- stringbuf_appendcstr(b->propname, name);
- }
- if (*elem < 1) // ! > 0
- return WEBDAV_NO_ERROR;
- switch (*elem)
- {
- case ELEM_propstat:
- b->in_propstat = TRUE;
- b->propstat_has_error = FALSE;
- break;
- default:
- break;
- }
- // We're guaranteed to have ELM now: NEON_XML_DECLINE < 1
- if (elm->flags & NEON_XML_CDATA)
- {
- stringbuf_setempty(b->cdata);
- b->want_cdata = b->cdata;
- }
- return WEBDAV_NO_ERROR;
- }
- // Implements neon_endelm_cb_t
- static error_t
- end_207_element(
- void * baton,
- int state,
- const char * nspace,
- const char * name)
- {
- multistatus_baton_t * b = static_cast<multistatus_baton_t *>(baton);
- switch (state)
- {
- case ELEM_multistatus:
- if (b->contains_error)
- {
- if (stringbuf_isempty(b->description))
- return error_create(WEBDAV_ERR_DAV_REQUEST_FAILED, NULL,
- "The request response contained at least one error");
- else if (b->contains_precondition_error)
- return error_create(WEBDAV_ERR_FS_PROP_BASEVALUE_MISMATCH, NULL,
- b->description->data);
- else
- return error_create(WEBDAV_ERR_DAV_REQUEST_FAILED, NULL,
- b->description->data);
- }
- break;
- case ELEM_responsedescription:
- if (b->in_propstat)
- stringbuf_set(b->propstat_description, b->cdata->data);
- else
- {
- if (!stringbuf_isempty(b->description))
- stringbuf_appendcstr(b->description, "\n");
- stringbuf_appendstr(b->description, b->cdata);
- }
- break;
- case ELEM_status:
- {
- ne_status status;
- if (ne_parse_statusline(b->cdata->data, &status) == 0)
- {
- // I wanted ||=, but I guess the end result is the same
- if (!b->in_propstat)
- b->contains_error |= (status.klass != 2);
- else
- b->propstat_has_error = (status.klass != 2);
- // Handle "412 Precondition Failed" specially
- if (status.code == 412)
- b->contains_precondition_error = TRUE;
- ne_free(status.reason_phrase);
- }
- else
- return error_create(WEBDAV_ERR_DAV_REQUEST_FAILED, NULL,
- "The response contains a non-conforming HTTP status line");
- }
- break;
- case ELEM_propstat:
- b->in_propstat = FALSE;
- b->contains_error |= b->propstat_has_error;
- stringbuf_appendcstr(b->description,
- apr_psprintf(b->req->pool,
- "Error setting property '%s': ",
- b->propname->data));
- stringbuf_appendstr(b->description,
- b->propstat_description);
- default:
- // do nothing
- break;
- }
- // When we have an element which wants cdata,
- // we'll set it all up in start_207_element() again
- b->want_cdata = NULL;
- return WEBDAV_NO_ERROR;
- }
- // Create a status parser attached to the request REQ. Detected errors
- // will be returned there.
- static void
- multistatus_parser_create(
- neon_request_t * req)
- {
- multistatus_baton_t * b = static_cast<multistatus_baton_t *>(apr_pcalloc(req->pool, sizeof(*b)));
- // Create a parser, attached to REQ. (Ignore the return value.)
- neon_xml_parser_create(req, ne_accept_207,
- start_207_element,
- neon_xml_collect_cdata,
- end_207_element, b);
- b->cdata = stringbuf_create("", req->pool);
- b->description = stringbuf_create("", req->pool);
- b->req = req;
- b->propname = stringbuf_create("", req->pool);
- b->propstat_description = stringbuf_create("", req->pool);
- }
- static apr_status_t
- compressed_body_reader_cleanup(
- void * baton)
- {
- if (baton)
- ne_decompress_destroy(static_cast<ne_decompress *>(baton));
- return APR_SUCCESS;
- }
- // Attach READER as a response reader for the request REQ, with the
- // acceptance function ACCPT. The response body data will be decompressed,
- // if compressed, before being passed to READER. USERDATA will be passed as
- // the first argument to the acceptance and reader callbacks.
- static void
- attach_ne_body_reader(
- neon_request_t * req,
- ne_accept_response accpt,
- ne_block_reader reader,
- void * userdata)
- {
- if (req->sess->compression)
- {
- ne_decompress * decompress =
- ne_decompress_reader(req->ne_req, accpt, reader, userdata);
- apr_pool_cleanup_register(req->pool,
- decompress,
- compressed_body_reader_cleanup,
- apr_pool_cleanup_null);
- }
- else
- ne_add_response_body_reader(req->ne_req, accpt, reader, userdata);
- }
- typedef struct cancellation_baton_t
- {
- ne_block_reader real_cb;
- void * real_userdata;
- neon_request_t * req;
- } cancellation_baton_t;
- static int
- cancellation_callback(
- void * userdata,
- const char * block,
- size_t len)
- {
- cancellation_baton_t * b = static_cast<cancellation_baton_t *>(userdata);
- neon_session_t * ras = b->req->sess;
- if (ras->callbacks->cancel_func)
- {
- NEON_REQ_ERR(b->req, (ras->callbacks->cancel_func)(ras->callback_baton));
- }
- if (b->req->err)
- return 1;
- else
- return (b->real_cb)(b->real_userdata, block, len);
- }
- static cancellation_baton_t *
- get_cancellation_baton(
- neon_request_t * req,
- ne_block_reader real_cb,
- void * real_userdata,
- apr_pool_t * pool)
- {
- cancellation_baton_t * b = static_cast<cancellation_baton_t *>(apr_pcalloc(pool, sizeof(*b)));
- b->real_cb = real_cb;
- b->real_userdata = real_userdata;
- b->req = req;
- return b;
- }
- typedef struct body_provider_baton_t
- {
- neon_request_t * req;
- apr_file_t * body_file;
- } body_provider_baton_t;
- static ssize_t
- ra_neon_body_provider(
- void * userdata,
- char * buffer,
- size_t buflen)
- {
- body_provider_baton_t * b = static_cast<body_provider_baton_t *>(userdata);
- neon_request_t * req = b->req;
- apr_file_t * body_file = b->body_file;
- if (req->sess->callbacks &&
- req->sess->callbacks->cancel_func)
- {
- NEON_REQ_ERR(req, (req->sess->callbacks->cancel_func)(
- req->sess->callback_baton));
- }
- if (req->err)
- return -1;
- webdav_pool_clear(req->iterpool);
- if (buflen == 0)
- {
- // This is the beginning of a new body pull. Rewind the file.
- apr_off_t offset = 0;
- NEON_REQ_ERR(b->req, io_file_seek(body_file, APR_SET, &offset, req->iterpool));
- return (req->err ? -1 : 0);
- }
- else
- {
- callback_baton_t * cb = static_cast<callback_baton_t *>(req->sess->callback_baton);
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(cb->ctx->auth_baton->parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- fs->AdjustToCPSLimit(buflen);
- apr_size_t nbytes = buflen;
- error_t err = io_file_read(body_file, buffer, &nbytes,
- req->iterpool);
- if (err)
- {
- if (APR_STATUS_IS_EOF(err))
- {
- error_clear(&err);
- return 0;
- }
- NEON_REQ_ERR(req, err);
- return -1;
- }
- else
- return (ssize_t)nbytes;
- }
- }
- static error_t
- neon_set_neon_body_provider(
- neon_request_t * req,
- apr_file_t * body_file)
- {
- apr_status_t status = 0;
- apr_finfo_t finfo = {0};
- body_provider_baton_t * b = static_cast<body_provider_baton_t *>(apr_pcalloc(req->pool, sizeof(*b)));
- status = apr_file_info_get(&finfo, APR_FINFO_SIZE, body_file);
- if (status)
- return error_wrap_apr(status,
- "Can't calculate the request body size");
- b->body_file = body_file;
- b->req = req;
- ne_set_request_body_provider(req->ne_req, (ne_off_t)finfo.size,
- ra_neon_body_provider, b);
- return WEBDAV_NO_ERROR;
- }
- // See doc string for neon_parsed_request.
- static error_t
- parsed_request(
- neon_request_t * req,
- neon_session_t * ras,
- const char * method,
- const char * url,
- const char * body,
- apr_file_t * body_file,
- void set_parser(ne_xml_parser * parser, void * baton),
- neon_startelm_cb_t startelm_cb,
- neon_cdata_cb_t cdata_cb,
- neon_endelm_cb_t endelm_cb,
- void * baton,
- apr_hash_t * extra_headers,
- int * status_code,
- bool check_errors,
- apr_pool_t * pool)
- {
- ne_xml_parser * success_parser = NULL;
- if (body == NULL)
- WEBDAV_ERR(neon_set_neon_body_provider(req, body_file));
- // use a symbolic name somewhere for this MIME type?
- ne_add_request_header(req->ne_req, "Content-Type", "text/xml");
- // create a parser to read the normal response body
- success_parser = neon_xml_parser_create(req, NULL,
- startelm_cb, cdata_cb,
- endelm_cb, baton);
- // if our caller is interested in having access to this parser, call
- // the SET_PARSER callback with BATON.
- if (set_parser != NULL)
- set_parser(success_parser, baton);
- // Register the "main" accepter and body-reader with the request --
- // the one to use when the HTTP status is 2XX.
- attach_ne_body_reader(req, ne_accept_2xx, cancellation_callback,
- get_cancellation_baton(req, ne_xml_parse_v,
- success_parser, pool));
- // run the request and get the resulting status code.
- WEBDAV_ERR(neon_request_dispatch(
- status_code, req, extra_headers, body,
- (strcmp(method, "PROPFIND") == 0) ? 207 : 200,
- 0,
- check_errors,
- pool));
- WEBDAV_ERR(neon_check_parse_error(method, success_parser, url));
- return WEBDAV_NO_ERROR;
- }
- static error_t
- neon_parsed_request(
- neon_session_t * sess,
- const char * method,
- const char * url,
- const char * body,
- apr_file_t * body_file,
- void set_parser(ne_xml_parser * parser, void * baton),
- neon_startelm_cb_t startelm_cb,
- neon_cdata_cb_t cdata_cb,
- neon_endelm_cb_t endelm_cb,
- void * baton,
- apr_hash_t * extra_headers,
- int * status_code,
- bool check_errors,
- apr_pool_t * pool)
- {
- // create/prep the request
- neon_request_t * req = NULL;
- error_t err = 0;
- WEBDAV_ERR(neon_request_create(&req, sess, method, url, pool));
- err = parsed_request(req, sess, method, url, body, body_file,
- set_parser, startelm_cb, cdata_cb, endelm_cb,
- baton, extra_headers, status_code,
- check_errors,
- pool);
- neon_request_destroy(req);
- return err;
- }
- static error_t
- neon_simple_request(
- int * code,
- neon_session_t * ras,
- const char * method,
- const char * url,
- apr_hash_t * extra_headers,
- const char * body,
- int okay_1, int okay_2, apr_pool_t * pool)
- {
- neon_request_t * req = NULL;
- error_t err = 0;
- WEBDAV_ERR(neon_request_create(&req, ras, method, url, pool));
- multistatus_parser_create(req);
- // neon_request_dispatch() adds the custom error response
- // reader. Neon will take care of the Content-Length calculation
- err = neon_request_dispatch(code, req, extra_headers,
- body ? body : "",
- okay_1, okay_2, false, pool);
- neon_request_destroy(req);
- return err;
- }
- static void
- neon_add_depth_header(
- apr_hash_t * extra_headers,
- int depth)
- {
- assert(extra_headers != NULL);
- assert(depth == NEON_DEPTH_ZERO ||
- depth == NEON_DEPTH_ONE ||
- depth == NEON_DEPTH_INFINITE);
- apr_hash_set(extra_headers, "Depth", APR_HASH_KEY_STRING,
- (depth == NEON_DEPTH_INFINITE) ?
- "infinity" : (depth == NEON_DEPTH_ZERO) ? "0" : "1");
- return;
- }
- static const neon_xml_elm_t *
- neon_lookup_xml_elem(
- const neon_xml_elm_t * table,
- const char * nspace,
- const char * name)
- {
- // placeholder for `unknown' element if it's present
- const neon_xml_elm_t * elem_unknown = NULL;
- const neon_xml_elm_t * elem = NULL;
- for (elem = table; elem->nspace; ++elem)
- {
- if ((strcmp(elem->nspace, nspace) == 0) &&
- (strcmp(elem->name, name) == 0))
- return elem;
- // Use a single loop to save CPU cycles.
- // Maybe this element is defined as `unknown'?
- if (elem->id == ELEM_unknown)
- elem_unknown = elem;
- }
- // ELEM_unknown position in the table or NULL
- return elem_unknown;
- }
- static error_t
- neon_xml_collect_cdata(
- void * baton,
- int state,
- const char * cdata,
- size_t len)
- {
- stringbuf_t ** b = static_cast<stringbuf_t **>(baton);
- if (*b)
- stringbuf_appendbytes(*b, cdata, len);
- return WEBDAV_NO_ERROR;
- }
- // Custom function of type ne_accept_response.
- static int
- ra_neon_error_accepter(
- void * userdata,
- ne_request * req,
- const ne_status * st)
- {
- // Before, this function was being run for *all* responses including
- // the 401 auth challenge. In neon 0.24.x that was harmless. But
- // in neon 0.25.0, trying to parse a 401 response as XML using
- // ne_xml_parse_v aborts the response; so the auth hooks never got a
- // chance.
- ne_content_type ctype = {0};
- // Only accept non-2xx responses with text/xml content-type
- if (st->klass != 2 && ne_get_content_type(req, &ctype) == 0)
- {
- int is_xml = (strcmp(ctype.type, "text") == 0) &&
- (strcmp(ctype.subtype, "xml") == 0);
- ne_free(ctype.value);
- return is_xml;
- }
- else
- return 0;
- }
- static const neon_xml_elm_t error_elements[] =
- {
- { "DAV:", "error", ELEM_error, 0 },
- {
- "http://apache.org/dav/xmlns", "human-readable",
- ELEM_human_readable, NEON_XML_CDATA
- },
- // our validator doesn't yet recognize the rich, specific
- // <D:some-condition-failed/> objects as defined by DeltaV.
- { NULL }
- };
- static error_t
- xml_parser_cleanup(void * baton)
- {
- ne_xml_destroy(static_cast<ne_xml_parser *>(baton));
- return WEBDAV_NO_ERROR;
- }
- static ne_xml_parser *
- xml_parser_create(
- neon_request_t * req)
- {
- ne_xml_parser * p = ne_xml_create();
- // HACK: Set the parser's error to the empty string. Someday we
- // hope neon will let us have an easy way to tell the difference
- // between XML parsing errors, and errors that occur while handling
- // the XML tags that we get. Until then, trust that whenever neon
- // has an error somewhere below the API, it sets its own error to
- // something non-empty (the API promises non-NULL, at least).
- ne_xml_set_error(p, "");
- apr_pool_cleanup_register(req->pool, p,
- xml_parser_cleanup,
- apr_pool_cleanup_null);
- return p;
- }
- static int
- validate_error_elements(
- neon_xml_elmid parent,
- neon_xml_elmid child)
- {
- switch (parent)
- {
- case ELEM_root:
- if (child == ELEM_error)
- return child;
- else
- return NEON_XML_INVALID;
- case ELEM_error:
- if ((child == ELEM_error) ||
- (child == ELEM_human_readable))
- return child;
- else
- return NEON_XML_DECLINE; // ignore if something else
- // was in there
- default:
- return NEON_XML_DECLINE;
- }
- // NOTREACHED
- }
- static error_t
- generate_error(
- neon_request_t * req,
- apr_pool_t * pool)
- {
- int errcode = WEBDAV_ERR_DAV_REQUEST_FAILED;
- const char * context =
- apr_psprintf(req->pool, "%s of '%s'", req->method, req->url);
- const char * msg = NULL;
- const char * hostport = NULL;
- // Convert the return codes.
- switch (req->rv)
- {
- case NE_OK:
- switch (req->code)
- {
- case 404:
- return error_create(WEBDAV_ERR_FS_NOT_FOUND, NULL,
- apr_psprintf(pool, "'%s' path not found", req->url));
- case 403:
- return error_create(WEBDAV_ERR_DAV_FORBIDDEN, NULL,
- apr_psprintf(pool, "Access to '%s' forbidden",
- req->url));
- case 301:
- case 302:
- case 307:
- return error_create(WEBDAV_ERR_DAV_RELOCATED, NULL,
- apr_psprintf(pool, (req->code == 301) ?
- "WebDAV resource moved permanently to '%s';"
- " please relocate"
- : "WebDAV resource moved temporarily to '%s';"
- " please relocate",
- neon_request_get_location(req, pool)));
- default:
- return error_create(errcode, NULL,
- apr_psprintf(pool,
- "Server sent unexpected return value (%d %s) "
- "in response to %s request for '%s'", req->code,
- req->code_desc, req->method, req->url));
- }
- case NE_AUTH:
- case NE_PROXYAUTH:
- errcode = WEBDAV_ERR_NOT_AUTHORIZED;
- // neon >= 0.27 gives a descriptive error message after auth
- // failure; expose this since it's a useful diagnostic e.g. for
- // an unsupported challenge scheme, or a local GSSAPI error due
- // to an expired ticket.
- WEBDAV_ERR(utf_cstring_to_utf8(&msg, ne_get_error(req->ne_sess), pool));
- msg = apr_psprintf(pool, "authorization failed: %s", msg);
- break;
- case NE_CONNECT:
- msg = "could not connect to server";
- break;
- case NE_TIMEOUT:
- msg = "timed out waiting for server";
- break;
- default:
- // Get the error string from neon and convert to UTF-8.
- WEBDAV_ERR(utf_cstring_to_utf8(&msg, ne_get_error(req->ne_sess), pool));
- break;
- }
- // The hostname may contain non-ASCII characters, so convert it to UTF-8.
- WEBDAV_ERR(utf_cstring_to_utf8(&hostport,
- ne_get_server_hostport(req->ne_sess), pool));
- // This is a translation nightmare. Make sure to compose full strings
- // and mark those for translation.
- return error_createf(errcode, NULL, "%s: %s (%s://%s)",
- context, msg, ne_get_scheme(req->ne_sess),
- hostport);
- }
- typedef struct error_parser_baton
- {
- stringbuf_t * want_cdata;
- stringbuf_t * cdata;
- error_t * dst_err;
- error_t tmp_err;
- bool * marshalled_error;
- } error_parser_baton_t;
- static int
- start_err_element(
- void * baton,
- int parent,
- const char * nspace,
- const char * name,
- const char ** atts)
- {
- const neon_xml_elm_t * elm = neon_lookup_xml_elem(error_elements, nspace, name);
- int acc = elm ? validate_error_elements(parent, elm->id) : NEON_XML_DECLINE;
- error_parser_baton_t * b = static_cast<error_parser_baton_t *>(baton);
- error_t * err = &(b->tmp_err);
- if (acc < 1) // ! > 0
- return acc;
- switch (elm->id)
- {
- case ELEM_error:
- {
- // allocate the error_t. Hopefully the value will be
- // overwritten by the <human-readable> tag, or even someday by
- // a <D:failed-precondition/> tag.
- *err = error_create(APR_EGENERAL, NULL,
- "General svn error from server");
- break;
- }
- case ELEM_human_readable:
- {
- // get the errorcode attribute if present
- const char * errcode_str =
- xml_get_attr_value("errcode", // make constant in
- // some mod_dav header?
- atts);
- if (errcode_str && *err)
- {
- apr_int64_t val;
- error_t err2;
- err2 = cstring_atoi64(&val, errcode_str);
- if (err2)
- {
- error_clear(&err2);
- break;
- }
- }
- break;
- }
- default:
- break;
- }
- switch (elm->id)
- {
- case ELEM_human_readable:
- b->want_cdata = b->cdata;
- stringbuf_setempty(b->want_cdata);
- break;
- default:
- b->want_cdata = NULL;
- break;
- }
- return elm->id;
- }
- static int
- end_err_element(
- void * baton,
- int state,
- const char * nspace,
- const char * name)
- {
- error_parser_baton_t * b = static_cast<error_parser_baton_t *>(baton);
- error_t * err = &(b->tmp_err);
- switch (state)
- {
- case ELEM_human_readable:
- {
- if (b->cdata->data && err)
- {
- // On the server dav_error_response_tag() will add a leading
- // and trailing newline if DEBUG_CR is defined in mod_dav.h,
- // so remove any such characters here.
- apr_size_t len;
- const char * cd = b->cdata->data;
- if (*cd == '\n')
- ++cd;
- len = strlen(cd);
- if (len > 0 && cd[len - 1] == '\n')
- --len;
- }
- break;
- }
- case ELEM_error:
- {
- if (b->dst_err)
- error_clear(&b->tmp_err);
- else if (b->tmp_err)
- {
- b->dst_err = &b->tmp_err;
- if (b->marshalled_error)
- *(b->marshalled_error) = TRUE;
- }
- b->tmp_err = NULL;
- break;
- }
- default:
- break;
- }
- return 0;
- }
- static int
- collect_error_cdata(
- void * baton,
- int state,
- const char * cdata,
- size_t len)
- {
- stringbuf_t ** b = static_cast<stringbuf_t **>(baton);
- if (*b)
- stringbuf_appendbytes(*b, cdata, len);
- return 0;
- }
- static apr_status_t
- error_parser_baton_cleanup(
- void * baton)
- {
- error_parser_baton_t * b = static_cast<error_parser_baton_t *>(baton);
- if (b->tmp_err)
- error_clear(&b->tmp_err);
- return APR_SUCCESS;
- }
- static ne_xml_parser *
- error_parser_create(
- neon_request_t * req)
- {
- error_parser_baton_t * b = static_cast<error_parser_baton_t *>(apr_pcalloc(req->pool, sizeof(*b)));
- ne_xml_parser * error_parser = NULL;
- b->dst_err = &(req->err);
- b->marshalled_error = &(req->marshalled_error);
- b->tmp_err = NULL;
- b->want_cdata = NULL;
- b->cdata = stringbuf_create("", req->pool);
- // attach a standard <D:error> body parser to the request
- error_parser = xml_parser_create(req);
- ne_xml_push_handler(error_parser,
- start_err_element,
- collect_error_cdata,
- end_err_element, b);
- apr_pool_cleanup_register(req->pool, b,
- error_parser_baton_cleanup,
- apr_pool_cleanup_null);
- // Register the "error" accepter and body-reader with the request --
- // the one to use when HTTP status is *not* 2XX
- attach_ne_body_reader(req, ra_neon_error_accepter,
- ne_xml_parse_v, error_parser);
- return error_parser;
- }
- static error_t
- neon_maybe_store_auth_info(
- neon_session_t * ras,
- apr_pool_t * pool)
- {
- // No auth_baton? Never mind.
- if (!ras->callbacks->auth_baton)
- return WEBDAV_NO_ERROR;
- // If we ever got credentials, ask the iter_baton to save them.
- return auth_save_credentials(ras->auth_iterstate, pool);
- }
- // A baton that is used along with a set of Neon ne_startelm_cb,
- // ne_cdata_cb, and ne_endelm_cb callbacks to handle conversion
- // from our style errors to Neon style errors.
- // The underlying callbacks are called, and if errors
- // are returned they are stored in this baton and a Neon level
- // error code is returned to the parser.
- typedef struct parser_wrapper_baton_t
- {
- neon_request_t * req;
- ne_xml_parser * parser;
- void * baton;
- neon_startelm_cb_t startelm_cb;
- neon_cdata_cb_t cdata_cb;
- neon_endelm_cb_t endelm_cb;
- } parser_wrapper_baton_t;
- static int
- wrapper_startelm_cb(
- void * baton,
- int parent,
- const char * nspace,
- const char * name,
- const char ** atts)
- {
- parser_wrapper_baton_t * pwb = static_cast<parser_wrapper_baton_t *>(baton);
- int elem = NEON_XML_DECLINE;
- if (pwb->startelm_cb)
- {
- NEON_REQ_ERR(pwb->req, pwb->startelm_cb(&elem, pwb->baton, parent, nspace,
- name, atts));
- }
- if (elem == NEON_XML_INVALID)
- {
- NEON_REQ_ERR(pwb->req, error_create(WEBDAV_ERR_XML_MALFORMED, NULL, NULL));
- }
- if (pwb->req->err)
- return NE_XML_ABORT;
- return elem;
- }
- static int
- wrapper_cdata_cb(
- void * baton,
- int state,
- const char * cdata,
- size_t len)
- {
- parser_wrapper_baton_t * pwb = static_cast<parser_wrapper_baton_t *>(baton);
- if (pwb->cdata_cb)
- {
- NEON_REQ_ERR(pwb->req, pwb->cdata_cb(pwb->baton, state, cdata, len));
- }
- if (pwb->req->err)
- return NE_XML_ABORT;
- return 0;
- }
- static int
- wrapper_endelm_cb(
- void * baton,
- int state,
- const char * nspace,
- const char * name)
- {
- parser_wrapper_baton_t * pwb = static_cast<parser_wrapper_baton_t *>(baton);
- if (pwb->endelm_cb)
- {
- NEON_REQ_ERR(pwb->req, pwb->endelm_cb(pwb->baton, state, nspace, name));
- }
- if (pwb->req->err)
- return NE_XML_ABORT;
- return 0;
- }
- static error_t
- neon_check_parse_error(
- const char * method,
- ne_xml_parser * xml_parser,
- const char * url)
- {
- const char * msg = ne_xml_get_error(xml_parser);
- if (msg != NULL && *msg != '\0')
- return error_createf(WEBDAV_ERR_DAV_REQUEST_FAILED, NULL,
- "The %s request returned invalid XML "
- "in the response: %s (%s)",
- method, msg, url);
- return WEBDAV_NO_ERROR;
- }
- static int
- wrapper_reader_cb(
- void * baton,
- const char * data,
- size_t len)
- {
- parser_wrapper_baton_t * pwb = static_cast<parser_wrapper_baton_t *>(baton);
- neon_session_t * sess = pwb->req->sess;
- int parser_status = 0;
- if (pwb->req->err)
- return 1;
- if (sess->callbacks->cancel_func)
- {
- NEON_REQ_ERR(pwb->req, (sess->callbacks->cancel_func)(sess->callback_baton));
- }
- if (pwb->req->err)
- return 1;
- if (len)
- parser_status = ne_xml_parse(pwb->parser, data, len);
- if (parser_status)
- {
- // Pass XML parser error.
- NEON_REQ_ERR(pwb->req, neon_check_parse_error(pwb->req->method,
- pwb->parser,
- pwb->req->url));
- }
- return parser_status;
- }
- // Create a Neon xml parser with callbacks STARTELM_CB, ENDELM_CB and
- // CDATA_CB. The created parser wraps the Neon callbacks and marshals any
- // errors returned by the callbacks through the Neon layer. Any errors
- // raised will be returned by neon_request_dispatch() unless
- // an earlier error occurred.
- // Register a pool cleanup on the pool of REQ to clean up any allocated
- // Neon resources.
- // Return the new parser. Also attach it to REQ if ACCPT is non-null.
- // ACCPT indicates whether the parser wants to read the response body
- // or not. Pass NULL for ACCPT when you don't want the returned parser
- // to be attached to REQ.
- static ne_xml_parser *
- neon_xml_parser_create(
- neon_request_t * req,
- ne_accept_response accpt,
- neon_startelm_cb_t startelm_cb,
- neon_cdata_cb_t cdata_cb,
- neon_endelm_cb_t endelm_cb,
- void * baton)
- {
- ne_xml_parser * p = xml_parser_create(req);
- parser_wrapper_baton_t * pwb = static_cast<parser_wrapper_baton_t *>(apr_pcalloc(req->pool, sizeof(*pwb)));
- pwb->req = req;
- pwb->parser = p;
- pwb->baton = baton;
- pwb->startelm_cb = startelm_cb;
- pwb->cdata_cb = cdata_cb;
- pwb->endelm_cb = endelm_cb;
- ne_xml_push_handler(p,
- wrapper_startelm_cb,
- wrapper_cdata_cb,
- wrapper_endelm_cb, pwb);
- if (accpt)
- attach_ne_body_reader(req, accpt, wrapper_reader_cb, pwb);
- return p;
- }
- static error_t
- neon_request_dispatch(
- int * code_p,
- neon_request_t * req,
- apr_hash_t * extra_headers,
- const char * body,
- int okay_1,
- int okay_2,
- bool check_errors,
- apr_pool_t * pool)
- {
- // add any extra headers passed in by caller.
- if (extra_headers != NULL)
- {
- for (apr_hash_index_t * hi = apr_hash_first(pool, extra_headers); hi;
- hi = apr_hash_next(hi))
- {
- const void * key;
- void * val;
- apr_hash_this(hi, &key, NULL, &val);
- ne_add_request_header(req->ne_req,
- static_cast<const char *>(key), static_cast<const char *>(val));
- }
- }
- if (body)
- ne_set_request_body_buffer(req->ne_req, body, strlen(body));
- // attach a standard <D:error> body parser to the request
- ne_xml_parser * error_parser = error_parser_create(req);
- if (check_errors)
- multistatus_parser_create(req);
- // run the request, see what comes back.
- req->rv = ne_request_dispatch(req->ne_req);
- // Save values from the request
- const ne_status * statstruct = ne_get_status(req->ne_req);
- req->code_desc = apr_pstrdup(pool, statstruct->reason_phrase);
- req->code = statstruct->code;
- // If we see a successful request that used authentication, we should store
- // the credentials for future use.
- if ((req->sess->auth_used) && (statstruct->code < 400))
- {
- req->sess->auth_used = FALSE;
- WEBDAV_ERR(neon_maybe_store_auth_info(req->sess, pool));
- }
- if (code_p)
- *code_p = req->code;
- if (!req->marshalled_error && req->err)
- WEBDAV_ERR(req->err);
- // If the status code was one of the two that we expected, then go
- // ahead and return now. IGNORE any marshalled error.
- if ((req->rv == NE_OK) && (req->code == okay_1 || req->code == okay_2))
- return WEBDAV_NO_ERROR;
- // Any other errors? Report them
- if (req->err)
- WEBDAV_ERR(req->err);
- WEBDAV_ERR(neon_check_parse_error(req->method, error_parser, req->url));
- // We either have a neon error, or some other error
- // that we didn't expect.
- return generate_error(req, pool);
- }
- static const char *
- neon_request_get_location(
- neon_request_t * request,
- apr_pool_t * pool)
- {
- const char * val = ne_get_response_header(request->ne_req, "Location");
- return val ? urlpath_canonicalize(val, pool) : NULL;
- }
- static error_t
- neon_request_create(
- neon_request_t ** request,
- neon_session_t * sess,
- const char * method, const char * url,
- apr_pool_t * pool)
- {
- apr_pool_t * reqpool = webdav_pool_create(pool);
- neon_request_t * req = NULL;
- const char * path = NULL;
- // We never want to send Neon an absolute URL, since that can cause
- // problems with some servers (for example, those that may be accessed
- // using different server names from different locations, or those that
- // want to rewrite the incoming URL). If the URL passed in is absolute,
- // convert it to a path-absolute relative URL.
- path = path_from_url(url);
- req = static_cast<neon_request_t *>(apr_pcalloc(reqpool, sizeof(*req)));
- req->ne_sess = sess->ne_sess;
- req->ne_req = ne_request_create(req->ne_sess, method, path);
- req->sess = sess;
- req->pool = reqpool;
- req->iterpool = webdav_pool_create(req->pool);
- req->method = apr_pstrdup(req->pool, method);
- req->url = apr_pstrdup(req->pool, url);
- req->rv = -1;
- // Neon resources may be NULL on out-of-memory
- assert(req->ne_req != NULL);
- apr_pool_cleanup_register(sess->pool, req,
- dav_request_sess_cleanup,
- apr_pool_cleanup_null);
- apr_pool_cleanup_register(reqpool, req,
- dav_request_cleanup,
- apr_pool_cleanup_null);
- *request = req;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- get_path_relative_to_session(
- session_t * session,
- const char ** rel_path,
- const char * url,
- apr_pool_t * pool)
- {
- const char * sess_url = NULL;
- WEBDAV_ERR(session->vtable->get_session_url(session, &sess_url, pool));
- if (strcmp(sess_url, url) == 0)
- {
- *rel_path = "";
- }
- else
- {
- *rel_path = uri_is_child(sess_url, url, pool);
- if (!*rel_path)
- {
- return error_createf(WEBDAV_ERR_ILLEGAL_URL, NULL,
- "'%s' isn't a child of session URL '%s'", url, sess_url);
- }
- }
- return WEBDAV_NO_ERROR;
- }
- static error_t
- client_path_relative_to_root(
- const char ** rel_path,
- const char * abspath_or_url,
- const char * webdav_root,
- bool include_leading_slash,
- session_t * ra_session,
- apr_pool_t * result_pool,
- apr_pool_t * scratch_pool)
- {
- const char * webdav_relpath = NULL;
- if (!path_is_url(abspath_or_url))
- {
- error_createf(WEBDAV_ERR_DAV_NOT_IMPLEMENTED, NULL,
- "not implemented: 'client_path_relative_to_root'");
- }
- // Merge handling passes a root that is not WebDAV resource root
- else if (webdav_root != NULL)
- {
- /*if (!uri_is_ancestor(webdav_root, abspath_or_url))
- return error_createf(WEBDAV_ERR_CLIENT_UNRELATED_RESOURCES, NULL,
- "URL '%s' is not a child of "
- "root URL '%s'",
- abspath_or_url, webdav_root);*/
- webdav_relpath = uri_skip_ancestor(webdav_root, abspath_or_url,
- result_pool);
- }
- else
- {
- error_t err = 0;
- WEBDAV_ERR_ASSERT(ra_session != NULL);
- // Ask the RA layer to create a relative path for us
- err = get_path_relative_to_root(ra_session, &webdav_relpath,
- abspath_or_url, scratch_pool);
- if (err)
- {
- if (err == WEBDAV_ERR_ILLEGAL_URL)
- {
- return error_createf(WEBDAV_ERR_CLIENT_UNRELATED_RESOURCES, &err,
- "URL '%s' is not inside WebDAV resource root", abspath_or_url);
- }
- return error_trace(err);
- }
- }
- if (include_leading_slash)
- *rel_path = apr_pstrcat(result_pool, "/", webdav_relpath, NULL);
- else
- *rel_path = webdav_relpath;
- return WEBDAV_NO_ERROR;
- }
- static const char *
- neon_uri_unparse(
- const ne_uri * uri,
- apr_pool_t * pool)
- {
- char * unparsed_uri = NULL;
- const char * result = NULL;
- // Unparse uri.
- unparsed_uri = ne_uri_unparse(uri);
- result = uri_canonicalize(unparsed_uri, pool);
- // Free neon's allocated copy.
- ne_free(unparsed_uri);
- // Return string allocated in result pool.
- return result;
- }
- typedef struct body_reader_wrapper_baton_t
- {
- neon_request_t * req;
- neon_block_reader real_reader;
- void * real_baton;
- } body_reader_wrapper_baton_t;
- static int
- body_reader_wrapper(
- void * userdata,
- const char * data,
- size_t len)
- {
- body_reader_wrapper_baton_t * b = static_cast<body_reader_wrapper_baton_t *>(userdata);
- if (b->req->err)
- // We already had an error? Bail out.
- return 1;
- NEON_REQ_ERR(b->req, b->real_reader(b->real_baton, data, len));
- if (b->req->err)
- return 1;
- return 0;
- }
- static void
- neon_add_response_body_reader(
- neon_request_t * req,
- ne_accept_response accpt,
- neon_block_reader reader,
- void * userdata)
- {
- body_reader_wrapper_baton_t * b = static_cast<body_reader_wrapper_baton_t *>(apr_pcalloc(req->pool, sizeof(*b)));
- b->req = req;
- b->real_baton = userdata;
- b->real_reader = reader;
- attach_ne_body_reader(req, accpt, body_reader_wrapper, b);
- }
- //------------------------------------------------------------------------------
- // from fetch.c
- typedef struct file_read_ctx_t
- {
- apr_pool_t * pool;
- // these two are the handler that the editor gave us
- void * handler_baton;
- // if we're receiving an svndiff, this is a parser which places the
- // resulting windows into the above handler/baton.
- stream_t * stream;
- } file_read_ctx_t;
- typedef struct file_write_ctx_t
- {
- stream_t * stream; // stream to write file contents to
- } file_write_ctx_t;
- typedef struct custom_get_ctx_t
- {
- neon_request_t * req; // Used to propagate errors out of the reader
- int checked_type; // have we processed ctype yet?
- void * subctx;
- void * callback_baton;
- } custom_get_ctx_t;
- // Helper for neon_get_file. This implements
- // the neon_block_reader() callback interface.
- static error_t
- get_file_reader(
- void * userdata,
- const char * buf,
- size_t len)
- {
- custom_get_ctx_t * cgc = static_cast<custom_get_ctx_t *>(userdata);
- if (cgc->req->sess->callbacks &&
- cgc->req->sess->callbacks->cancel_func)
- {
- NEON_REQ_ERR(cgc->req, (cgc->req->sess->callbacks->cancel_func)(
- cgc->req->sess->callback_baton));
- }
- assert(cgc->callback_baton);
- callback_baton_t * cb = static_cast<callback_baton_t *>(cgc->callback_baton);
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(cb->ctx->auth_baton->parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- fs->AdjustToCPSLimit(len);
- // The stream we want to push data at.
- file_write_ctx_t * fwc = static_cast<file_write_ctx_t *>(cgc->subctx);
- stream_t * stream = fwc->stream;
- // Write however many bytes were passed in by neon.
- WEBDAV_ERR(stream_write(stream, buf, &len));
- return WEBDAV_NO_ERROR;
- }
- static error_t
- custom_get_request(
- neon_session_t * ras,
- const char * url,
- const char * editor_relpath,
- neon_block_reader reader,
- void * subctx,
- void * cb_baton,
- apr_pool_t * pool)
- {
- custom_get_ctx_t cgc = { 0 };
- neon_request_t * request = NULL;
- error_t err = 0;
- WEBDAV_ERR(neon_request_create(&request, ras, "GET", url, pool));
- neon_add_response_body_reader(request, ne_accept_2xx, reader, &cgc);
- // complete initialization of the body reading context
- cgc.req = request;
- cgc.subctx = subctx;
- cgc.callback_baton = cb_baton;
- // run the request
- err = neon_request_dispatch(NULL, request, NULL, NULL,
- 200 /* OK */,
- 226 /* IM Used */,
- false,
- pool);
- neon_request_destroy(request);
- // The request runner raises internal errors before Neon errors,
- // pass a returned error to our callers
- return err;
- }
- //------------------------------------------------------------------------------
- static error_t
- get_file(
- session_t * session,
- const char * path,
- stream_t * stream,
- apr_hash_t ** props,
- apr_pool_t * pool)
- {
- WEBDAV_ERR_ASSERT(*path != '/');
- return session->vtable->get_file(session, path,
- stream,
- props, pool);
- }
- static error_t
- get_dir2(
- session_t * session,
- apr_hash_t ** dirents,
- const char * path,
- apr_uint32_t dirent_fields,
- apr_pool_t * pool)
- {
- WEBDAV_ERR_ASSERT(*path != '/');
- return session->vtable->get_dir(session, dirents,
- path,
- dirent_fields, pool);
- }
- static error_t
- get_webdav_resource_root2(
- session_t * session,
- const char ** url,
- apr_pool_t * pool)
- {
- WEBDAV_ERR(session->vtable->get_webdav_resource_root(session, url, pool));
- *url = *url ? apr_pstrdup(pool, *url) : NULL;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- stat(
- session_t * session,
- const char * path,
- dirent_t ** dirent,
- apr_pool_t * pool)
- {
- WEBDAV_ERR_ASSERT(*path != '/');
- return session->vtable->stat(session, path,
- dirent, pool);
- }
- static error_t
- get_path_relative_to_root(
- session_t * session,
- const char ** rel_path,
- const char * url,
- apr_pool_t * pool)
- {
- const char * root_url = NULL;
- WEBDAV_ERR(session->vtable->get_webdav_resource_root(session, &root_url, pool));
- if (strcmp(root_url, url) == 0)
- {
- *rel_path = "";
- }
- else
- {
- *rel_path = uri_is_child(root_url, url, pool);
- if (!*rel_path)
- {
- return error_createf(WEBDAV_ERR_ILLEGAL_URL, NULL,
- "'%s' isn't a child of root URL '%s'", url, root_url);
- }
- }
- return WEBDAV_NO_ERROR;
- }
- static error_t
- check_path(
- session_t * session,
- const char * path,
- node_kind_t * kind,
- apr_pool_t * pool)
- {
- WEBDAV_ERR_ASSERT(*path != '/');
- return session->vtable->check_path(session, path,
- kind, pool);
- }
- static error_t
- reparent(
- session_t * session,
- const char * url,
- apr_pool_t * pool)
- {
- return session->vtable->reparent(session, url, pool);
- }
- static error_t
- session_open(
- session_t ** session_p,
- const char ** corrected_url_p,
- const char * session_URL,
- const callbacks2_t * callbacks,
- void * callback_baton,
- apr_pool_t * pool)
- {
- assert(callback_baton);
- // check options, url, prepare parameters, callbacks, auth etc
- apr_pool_t * sesspool = webdav_pool_create(pool);
- // Initialize the return variable.
- *session_p = NULL;
- ne_uri * webdav_URI = NULL;
- error_t err = parse_ne_uri(&webdav_URI, session_URL, sesspool);
- if ((err != WEBDAV_NO_ERROR) || (webdav_URI->host == NULL))
- {
- return error_createf(WEBDAV_ERR_ILLEGAL_URL, NULL,
- "Illegal URL '%s'", session_URL);
- }
- // Auth caching parameters.
- bool store_passwords = WEBDAV_CONFIG_DEFAULT_OPTION_STORE_PASSWORDS;
- bool store_auth_creds = WEBDAV_CONFIG_DEFAULT_OPTION_STORE_AUTH_CREDS;
- const char * store_plaintext_passwords = WEBDAV_CONFIG_DEFAULT_OPTION_STORE_PLAINTEXT_PASSWORDS;
- bool store_pp = WEBDAV_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP;
- const char * store_pp_plaintext = WEBDAV_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT;
- if (callbacks->auth_baton)
- {
- if (auth_baton_get_parameter(callbacks->auth_baton,
- WEBDAV_AUTH_PARAM_DONT_STORE_PASSWORDS) != NULL)
- {
- store_passwords = FALSE;
- }
- if (auth_baton_get_parameter(callbacks->auth_baton,
- WEBDAV_AUTH_PARAM_NO_AUTH_CACHE) != NULL)
- {
- store_auth_creds = FALSE;
- }
- }
- if (callbacks->auth_baton)
- {
- // Save auth caching parameters in the auth parameter hash.
- if (!store_passwords)
- auth_baton_set_parameter(callbacks->auth_baton,
- WEBDAV_AUTH_PARAM_DONT_STORE_PASSWORDS, "");
- auth_baton_set_parameter(callbacks->auth_baton,
- WEBDAV_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS,
- store_plaintext_passwords);
- if (!store_pp)
- auth_baton_set_parameter(callbacks->auth_baton,
- WEBDAV_AUTH_PARAM_DONT_STORE_SSL_CLIENT_CERT_PP,
- "");
- auth_baton_set_parameter(callbacks->auth_baton,
- WEBDAV_AUTH_PARAM_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT,
- store_pp_plaintext);
- if (!store_auth_creds)
- auth_baton_set_parameter(callbacks->auth_baton,
- WEBDAV_AUTH_PARAM_NO_AUTH_CACHE, "");
- }
- const vtable_t * vtable = NULL;
- WEBDAV_ERR(neon_init(&vtable, sesspool));
- // Create the session object.
- session_t * session = static_cast<session_t *>(apr_pcalloc(sesspool, sizeof(*session)));
- session->vtable = vtable;
- session->pool = sesspool;
- const char * corrected_url = NULL;
- // Ask the library to open the session.
- WEBDAV_ERR_W(vtable->open_session(
- session,
- &corrected_url,
- session_URL,
- callbacks, callback_baton, sesspool),
- apr_psprintf(pool, "Unable to connect to a WebDAV resource at URL '%s'",
- session_URL));
- if (corrected_url_p && corrected_url)
- {
- if (!path_is_url(corrected_url))
- {
- ne_uri * corrected_URI = NULL;
- WEBDAV_ERR(parse_ne_uri(&corrected_URI, session_URL, sesspool));
- if (corrected_URI->path) ne_free(corrected_URI->path);
- corrected_URI->path = ne_strdup(corrected_url);
- corrected_url = neon_uri_unparse(corrected_URI, pool);
- }
- *corrected_url_p = uri_canonicalize(corrected_url, pool);
- webdav_pool_destroy(sesspool);
- return WEBDAV_NO_ERROR;
- }
- *session_p = session;
- return WEBDAV_NO_ERROR;
- }
- //---------------------------------------------------------------------------
- // This implements the client_list_func_t API
- static error_t
- list_func(
- void * baton,
- const char * path,
- const dirent_t * dirent,
- const char * abs_path,
- apr_pool_t * pool)
- {
- list_func_baton_t * pb = static_cast<list_func_baton_t *>(baton);
- assert(pb);
- assert(pb->entries);
- const char * entryname = NULL;
- neon_session_t * ras = static_cast<neon_session_t *>(pb->session->priv);
- assert(ras);
- if (ras->callbacks->cancel_func)
- WEBDAV_ERR(ras->callbacks->cancel_func(ras->callback_baton));
- if (strcmp(path, "") == 0)
- {
- if (dirent->kind == node_file)
- entryname = dirent_basename(abs_path, pool);
- else if (pb->verbose)
- entryname = ".";
- else
- // Don't bother to list if no useful information will be shown.
- return WEBDAV_NO_ERROR;
- }
- else
- entryname = path;
- if (pb->verbose)
- {
- apr_time_t now = apr_time_now();
- apr_time_exp_t exp_time;
- apr_status_t apr_err;
- apr_size_t size;
- char timestr[20];
- const char * utf8_timestr;
- // time_to_human_cstring gives us something *way* too long
- // to use for this, so we have to roll our own. We include
- // the year if the entry's time is not within half a year.
- apr_time_exp_lt(&exp_time, dirent->time);
- if (apr_time_sec(now - dirent->time) < (365 * 86400 / 2) &&
- apr_time_sec(dirent->time - now) < (365 * 86400 / 2))
- {
- apr_err = apr_strftime(timestr, &size, sizeof(timestr),
- "%b %d %H:%M", &exp_time);
- }
- else
- {
- apr_err = apr_strftime(timestr, &size, sizeof(timestr),
- "%b %d %Y", &exp_time);
- }
- // if that failed, just zero out the string and print nothing
- if (apr_err)
- timestr[0] = '\0';
- // we need it in UTF-8.
- WEBDAV_ERR(utf_cstring_to_utf8(&utf8_timestr, timestr, pool));
- TListDataEntry entry = {NULL, NULL, NULL, 0, false, false, {0}, NULL};
- if (APR_SUCCESS != utf8_to_unicode(const_cast<wchar_t **>(&entry.Name), entryname, pb->pool))
- {
- return error_create(WEBDAV_ERR_DAV_MALFORMED_DATA, NULL, NULL);
- }
- entry.Permissions = L"";
- entry.OwnerGroup = L"";
- int dir = dirent->kind == node_dir;
- entry.Size = dir == 0 ? dirent->size : 0;
- entry.Dir = dir != 0;
- entry.Link = false;
- entry.Time.Year = exp_time.tm_year + 1900;
- entry.Time.Month = exp_time.tm_mon + 1;
- entry.Time.Day = exp_time.tm_mday;
- entry.Time.Hour = exp_time.tm_hour;
- entry.Time.Minute = exp_time.tm_min;
- entry.Time.Second = exp_time.tm_sec;
- entry.Time.HasTime = true;
- entry.Time.HasSeconds = true;
- entry.Time.HasDate = true;
- entry.LinkTarget = L"";
- pb->entries->push_back(entry);
- }
- return WEBDAV_NO_ERROR;
- }
- //---------------------------------------------------------------------------
- // from url.c
- static error_t
- client_url_from_path2(
- const char ** url,
- const char * path_or_url,
- stringbuf_t * session_url,
- apr_pool_t * result_pool,
- apr_pool_t * scratch_pool)
- {
- if (!path_is_url(path_or_url))
- {
- ne_uri * uri = NULL;
- WEBDAV_ERR(parse_ne_uri(&uri, session_url->data, result_pool));
- if (uri->path) ne_free(uri->path);
- uri->path = ne_strdup(path_or_url);
- const char * corrected_url = neon_uri_unparse(uri, result_pool);
- *url = uri_canonicalize(corrected_url, result_pool);
- }
- else
- *url = uri_canonicalize(path_or_url, result_pool);
- return WEBDAV_NO_ERROR;
- }
- //---------------------------------------------------------------------------
- // from ctx.c
- static error_t
- client_create_context(
- client_ctx_t ** ctx,
- apr_pool_t * pool)
- {
- *ctx = static_cast<client_ctx_t *>(apr_pcalloc(pool, sizeof(client_ctx_t)));
- return WEBDAV_NO_ERROR;
- }
- //------------------------------------------------------------------------------
- // from auth.c
- static void
- auth_baton_create(
- auth_baton_t ** auth_baton,
- apr_pool_t * pool)
- {
- auth_baton_t * ab = NULL;
- // Build the auth_baton.
- ab = static_cast<auth_baton_t *>(apr_pcalloc(pool, sizeof(*ab)));
- ab->tables = apr_hash_make(pool);
- ab->parameters = apr_hash_make(pool);
- ab->creds_cache = apr_hash_make(pool);
- ab->pool = pool;
- *auth_baton = ab;
- }
- static void
- create_baton_open(
- auth_baton_t * auth_baton,
- const apr_array_header_t * providers,
- apr_pool_t * pool)
- {
- auth_provider_object_t * provider = NULL;
- // Register each provider in order. Providers of different
- // credentials will be automatically sorted into different tables by
- // register_provider().
- if (providers)
- {
- for (int i = 0; i < providers->nelts; i++)
- {
- provider_set_t * table = NULL;
- provider = APR_ARRAY_IDX(providers, i, auth_provider_object_t *);
- // Add it to the appropriate table in the auth_baton
- table = static_cast<provider_set_t *>(apr_hash_get(auth_baton->tables,
- provider->vtable->cred_kind, APR_HASH_KEY_STRING));
- if (!table)
- {
- table = static_cast<provider_set_t *>(apr_pcalloc(pool, sizeof(*table)));
- table->providers = apr_array_make(pool, 1, sizeof(auth_provider_object_t *));
- apr_hash_set(auth_baton->tables,
- provider->vtable->cred_kind, APR_HASH_KEY_STRING,
- table);
- }
- APR_ARRAY_PUSH(table->providers, auth_provider_object_t *) = provider;
- }
- }
- }
- //---------------------------------------------------------------------------
- // from ssl_client_cert_providers.c
- // A function returning an SSL client certificate passphrase provider.
- typedef void (*auth_ssl_client_cert_pw_provider_func_t)(
- auth_provider_object_t ** provider,
- apr_pool_t * pool);
- // retrieve and load the ssl client certificate file from servers config
- static error_t
- ssl_client_cert_file_first_credentials(
- void ** credentials_p,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- const char * cert_file;
- cert_file = NULL;
- if (cert_file != NULL)
- {
- auth_cred_ssl_client_cert_t * cred =
- static_cast<auth_cred_ssl_client_cert_t *>(apr_pcalloc(pool, sizeof(*cred)));
- cred->cert_file = cert_file;
- cred->may_save = FALSE;
- *credentials_p = cred;
- }
- else
- {
- *credentials_p = NULL;
- }
- *iter_baton = NULL;
- return WEBDAV_NO_ERROR;
- }
- static const auth_provider_t ssl_client_cert_file_provider =
- {
- AUTH_CRED_SSL_CLIENT_CERT,
- ssl_client_cert_file_first_credentials,
- NULL,
- NULL
- };
- // Public API to SSL file providers.
- static void
- auth_get_ssl_client_cert_file_provider(
- auth_provider_object_t ** provider,
- apr_pool_t * pool)
- {
- auth_provider_object_t * po =
- static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
- po->vtable = &ssl_client_cert_file_provider;
- *provider = po;
- }
- /*-----------------------------------------------------------------------*/
- // Prompt provider
- /*-----------------------------------------------------------------------*/
- // Baton type for prompting to send client ssl creds.
- // There is no iteration baton type.
- typedef struct ssl_client_cert_prompt_provider_baton_t
- {
- auth_ssl_client_cert_prompt_func_t prompt_func;
- void * prompt_baton;
- // how many times to re-prompt after the first one fails
- int retry_limit;
- } ssl_client_cert_prompt_provider_baton_t;
- // Iteration baton.
- typedef struct ssl_client_cert_prompt_iter_baton_t
- {
- // The original provider baton
- ssl_client_cert_prompt_provider_baton_t * pb;
- // The original realmstring
- const char * realmstring;
- // how many times we've reprompted
- int retries;
- } ssl_client_cert_prompt_iter_baton_t;
- static error_t
- ssl_client_cert_prompt_first_cred(
- void ** credentials_p,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- ssl_client_cert_prompt_provider_baton_t * pb =
- static_cast<ssl_client_cert_prompt_provider_baton_t *>(provider_baton);
- ssl_client_cert_prompt_iter_baton_t * ib =
- static_cast<ssl_client_cert_prompt_iter_baton_t *>(apr_pcalloc(pool, sizeof(*ib)));
- const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
- APR_HASH_KEY_STRING));
- WEBDAV_ERR(pb->prompt_func((auth_cred_ssl_client_cert_t **) credentials_p,
- pb->prompt_baton, realmstring, !no_auth_cache,
- pool));
- ib->pb = pb;
- ib->realmstring = apr_pstrdup(pool, realmstring);
- ib->retries = 0;
- *iter_baton = ib;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- ssl_client_cert_prompt_next_cred(
- void ** credentials_p,
- void * iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- ssl_client_cert_prompt_iter_baton_t * ib =
- static_cast<ssl_client_cert_prompt_iter_baton_t *>(iter_baton);
- const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
- APR_HASH_KEY_STRING));
- if ((ib->pb->retry_limit >= 0) && (ib->retries >= ib->pb->retry_limit))
- {
- // give up, go on to next provider.
- *credentials_p = NULL;
- return WEBDAV_NO_ERROR;
- }
- ib->retries++;
- return ib->pb->prompt_func((auth_cred_ssl_client_cert_t **)
- credentials_p, ib->pb->prompt_baton,
- ib->realmstring, !no_auth_cache, pool);
- }
- static const auth_provider_t ssl_client_cert_prompt_provider =
- {
- AUTH_CRED_SSL_CLIENT_CERT,
- ssl_client_cert_prompt_first_cred,
- ssl_client_cert_prompt_next_cred,
- NULL
- };
- // Public API to SSL prompting providers.
- static void
- auth_get_ssl_client_cert_prompt_provider(
- auth_provider_object_t ** provider,
- auth_ssl_client_cert_prompt_func_t prompt_func,
- void * prompt_baton,
- int retry_limit,
- apr_pool_t * pool)
- {
- auth_provider_object_t * po =
- static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
- ssl_client_cert_prompt_provider_baton_t * pb =
- static_cast<ssl_client_cert_prompt_provider_baton_t *>(apr_pcalloc(pool, sizeof(*pb)));
- pb->prompt_func = prompt_func;
- pb->prompt_baton = prompt_baton;
- pb->retry_limit = retry_limit;
- po->vtable = &ssl_client_cert_prompt_provider;
- po->provider_baton = pb;
- *provider = po;
- }
- //---------------------------------------------------------------------------
- // from ssl_server_trust_providers.c
- // retrieve ssl server CA failure overrides (if any) from servers config
- static error_t
- ssl_server_trust_file_first_credentials(
- void ** credentials,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- apr_uint32_t * failures = static_cast<apr_uint32_t *>(apr_hash_get(parameters,
- AUTH_PARAM_SSL_SERVER_FAILURES,
- APR_HASH_KEY_STRING));
- const auth_ssl_server_cert_info_t * cert_info =
- static_cast<const auth_ssl_server_cert_info_t *>(apr_hash_get(parameters,
- AUTH_PARAM_SSL_SERVER_CERT_INFO,
- APR_HASH_KEY_STRING));
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- apr_hash_t * creds_hash = NULL;
- error_t error = WEBDAV_NO_ERROR;
- *credentials = NULL;
- *iter_baton = NULL;
- // Check if this is a permanently accepted certificate
- error = config_read_auth_data(&creds_hash, AUTH_CRED_SSL_SERVER_TRUST,
- realmstring, fs, pool);
- error_clear(&error);
- if (!error && creds_hash)
- {
- string_t * trusted_cert, *this_cert, *failstr;
- apr_uint32_t last_failures = 0;
- trusted_cert = static_cast<string_t *>(apr_hash_get(creds_hash, AUTHN_ASCII_CERT_KEY,
- APR_HASH_KEY_STRING));
- this_cert = string_create(cert_info->fingerprint, pool);
- failstr = static_cast<string_t *>(apr_hash_get(creds_hash, AUTHN_FAILURES_KEY,
- APR_HASH_KEY_STRING));
- if (failstr)
- {
- char * endptr;
- unsigned long tmp_ulong = strtoul(failstr->data, &endptr, 10);
- if (*endptr == '\0')
- last_failures = (apr_uint32_t) tmp_ulong;
- }
- // If the cert is trusted and there are no new failures, we
- // accept it by clearing all failures.
- if (trusted_cert &&
- string_compare(this_cert, trusted_cert) &&
- (*failures & ~last_failures) == 0)
- {
- *failures = 0;
- }
- }
- // If all failures are cleared now, we return the creds
- if (!*failures)
- {
- auth_cred_ssl_server_trust_t * creds =
- static_cast<auth_cred_ssl_server_trust_t *>(apr_pcalloc(pool, sizeof(*creds)));
- creds->may_save = FALSE; // No need to save it again...
- *credentials = creds;
- }
- return WEBDAV_NO_ERROR;
- }
- static error_t
- ssl_server_trust_file_save_credentials(
- bool * saved,
- void * credentials,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- auth_cred_ssl_server_trust_t * creds =
- static_cast<auth_cred_ssl_server_trust_t *>(credentials);
- const auth_ssl_server_cert_info_t * cert_info;
- apr_hash_t * creds_hash = NULL;
- if (!creds->may_save)
- return WEBDAV_NO_ERROR;
- cert_info = static_cast<const auth_ssl_server_cert_info_t *>(apr_hash_get(parameters,
- AUTH_PARAM_SSL_SERVER_CERT_INFO,
- APR_HASH_KEY_STRING));
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- creds_hash = apr_hash_make(pool);
- apr_hash_set(creds_hash, AUTHN_ASCII_CERT_KEY, APR_HASH_KEY_STRING,
- string_create(cert_info->fingerprint, pool));
- apr_hash_set(creds_hash, AUTHN_FAILURES_KEY, APR_HASH_KEY_STRING,
- string_createf(pool, "%lu", (unsigned long)
- creds->accepted_failures));
- WEBDAV_ERR(config_write_auth_data(creds_hash,
- AUTH_CRED_SSL_SERVER_TRUST,
- realmstring,
- fs,
- pool));
- *saved = TRUE;
- return WEBDAV_NO_ERROR;
- }
- static const auth_provider_t ssl_server_trust_file_provider =
- {
- AUTH_CRED_SSL_SERVER_TRUST,
- &ssl_server_trust_file_first_credentials,
- NULL,
- &ssl_server_trust_file_save_credentials,
- };
- // Public API to SSL file providers.
- static void
- auth_get_ssl_server_trust_file_provider(
- auth_provider_object_t ** provider,
- apr_pool_t * pool)
- {
- auth_provider_object_t * po =
- static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
- po->vtable = &ssl_server_trust_file_provider;
- *provider = po;
- }
- /*-----------------------------------------------------------------------*/
- // Prompt provider
- /*-----------------------------------------------------------------------*/
- // Baton type for prompting to verify server ssl creds.
- // There is no iteration baton type.
- typedef struct ssl_server_trust_prompt_provider_baton_t
- {
- auth_ssl_server_trust_prompt_func_t prompt_func;
- void * prompt_baton;
- } ssl_server_trust_prompt_provider_baton_t;
- static error_t
- ssl_server_trust_prompt_first_cred(
- void ** credentials_p,
- void ** iter_baton,
- void * provider_baton,
- apr_hash_t * parameters,
- const char * realmstring,
- apr_pool_t * pool)
- {
- ssl_server_trust_prompt_provider_baton_t * pb =
- static_cast<ssl_server_trust_prompt_provider_baton_t *>(provider_baton);
- apr_uint32_t * failures = static_cast<apr_uint32_t *>(apr_hash_get(parameters,
- AUTH_PARAM_SSL_SERVER_FAILURES,
- APR_HASH_KEY_STRING));
- const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
- WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
- APR_HASH_KEY_STRING));
- const auth_ssl_server_cert_info_t * cert_info =
- static_cast<const auth_ssl_server_cert_info_t *>(apr_hash_get(parameters,
- AUTH_PARAM_SSL_SERVER_CERT_INFO,
- APR_HASH_KEY_STRING));
- WEBDAV_ERR(pb->prompt_func((auth_cred_ssl_server_trust_t **)
- credentials_p, pb->prompt_baton, realmstring,
- *failures, cert_info, !no_auth_cache &&
- !(*failures & WEBDAV_AUTH_SSL_OTHER), pool));
- *iter_baton = NULL;
- return WEBDAV_NO_ERROR;
- }
- static const auth_provider_t ssl_server_trust_prompt_provider =
- {
- AUTH_CRED_SSL_SERVER_TRUST,
- ssl_server_trust_prompt_first_cred,
- NULL,
- NULL
- };
- // Public API to SSL prompting providers.
- static void
- auth_get_ssl_server_trust_prompt_provider(
- auth_provider_object_t ** provider,
- auth_ssl_server_trust_prompt_func_t prompt_func,
- void * prompt_baton,
- apr_pool_t * pool)
- {
- auth_provider_object_t * po =
- static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
- ssl_server_trust_prompt_provider_baton_t * pb =
- static_cast<ssl_server_trust_prompt_provider_baton_t *>(apr_pcalloc(pool, sizeof(*pb)));
- pb->prompt_func = prompt_func;
- pb->prompt_baton = prompt_baton;
- po->vtable = &ssl_server_trust_prompt_provider;
- po->provider_baton = pb;
- *provider = po;
- }
- //---------------------------------------------------------------------------
- // from cmdline.h
- typedef struct cmdline_prompt_baton2_t
- {
- cancel_func_t cancel_func;
- void * cancel_baton;
- } cmdline_prompt_baton2_t;
- //---------------------------------------------------------------------------
- // from prompt.c
- // This is a helper for plaintext prompt functions.
- static error_t
- plaintext_prompt_helper(
- bool * may_save_plaintext,
- const char * realmstring,
- const char * prompt_string,
- const char * prompt_text,
- void * baton,
- apr_pool_t * pool)
- {
- cmdline_prompt_baton2_t * pb = static_cast<cmdline_prompt_baton2_t *>(baton);
- auth_baton_t * ab = static_cast<auth_baton_t *>(pb->cancel_baton);
- assert(ab);
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(ab->parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- unsigned int RequestResult = 0;
- error_t err = fs->SimplePrompt(prompt_text, prompt_string, RequestResult);
- if (err)
- {
- if (err == WEBDAV_ERR_CANCELLED)
- {
- error_clear(&err);
- *may_save_plaintext = FALSE;
- return WEBDAV_NO_ERROR;
- }
- else
- return err;
- }
- if (RequestResult == qaYes)
- {
- *may_save_plaintext = TRUE;
- }
- else if (RequestResult == qaNo)
- {
- *may_save_plaintext = FALSE;
- }
- return WEBDAV_NO_ERROR;
- }
- // This implements 'auth_plaintext_prompt_func_t'.
- static error_t
- cmdline_auth_plaintext_prompt(
- bool * may_save_plaintext,
- const char * realmstring,
- void * baton,
- apr_pool_t * pool)
- {
- const char * prompt_string = "Store password unencrypted (yes/no)? ";
- const char * prompt_text =
- "\n-----------------------------------------------------------------------"
- "\nATTENTION! Your password for authentication realm:\n"
- "\n"
- " %s\n"
- "\n"
- "can only be stored to disk unencrypted! You are advised to configure\n"
- "your system so that system can store passwords encrypted, if\n"
- "possible. See the documentation for details.\n"
- "\n"
- "You can avoid future appearances of this warning by setting the value\n"
- "of the 'store-plaintext-passwords' option to either 'yes' or 'no' in\n"
- "'%s'.\n"
- "-----------------------------------------------------------------------\n"
- ;
- return plaintext_prompt_helper(may_save_plaintext, realmstring,
- prompt_string, prompt_text, baton,
- pool);
- }
- // This implements 'auth_plaintext_passphrase_prompt_func_t'.
- static error_t
- cmdline_auth_plaintext_passphrase_prompt(
- bool * may_save_plaintext,
- const char * realmstring,
- void * baton,
- apr_pool_t * pool)
- {
- const char * prompt_string = "Store passphrase unencrypted (yes/no)? ";
- const char * prompt_text =
- "\n-----------------------------------------------------------------------\n"
- "ATTENTION! Your passphrase for client certificate:\n"
- "\n"
- " %s\n"
- "\n"
- "can only be stored to disk unencrypted! You are advised to configure\n"
- "your system so that system can store passphrase encrypted, if\n"
- "possible. See the documentation for details.\n"
- "\n"
- "You can avoid future appearances of this warning by setting the value\n"
- "of the 'store-ssl-client-cert-pp-plaintext' option to either 'yes' or\n"
- "'no' in '%s'.\n"
- "-----------------------------------------------------------------------\n"
- ;
- return plaintext_prompt_helper(may_save_plaintext, realmstring,
- prompt_string, prompt_text, baton,
- pool);
- }
- // This implements 'auth_ssl_server_trust_prompt_func_t'.
- static error_t
- cmdline_auth_ssl_server_trust_prompt(
- auth_cred_ssl_server_trust_t ** cred_p,
- void * baton,
- const char * realm,
- apr_uint32_t failures,
- const auth_ssl_server_cert_info_t * cert_info,
- bool may_save,
- apr_pool_t * pool)
- {
- cmdline_prompt_baton2_t * pb =
- static_cast<cmdline_prompt_baton2_t *>(baton);
- stringbuf_t * buf = stringbuf_create("", pool);
- /*if (failures & WEBDAV_AUTH_SSL_UNKNOWNCA)
- {
- stringbuf_appendcstr(buf,
- " - The certificate is not issued by a trusted authority. Use the\n"
- " fingerprint to validate the certificate manually!\n");
- }*/
- if (failures & WEBDAV_AUTH_SSL_CNMISMATCH)
- {
- stringbuf_appendcstr(buf, "- The certificate hostname does not match.\n");
- }
- if (failures & WEBDAV_AUTH_SSL_NOTYETVALID)
- {
- stringbuf_appendcstr(buf, "- The certificate is not yet valid.\n");
- }
- if (failures & WEBDAV_AUTH_SSL_EXPIRED)
- {
- stringbuf_appendcstr(buf, "- The certificate has expired.\n");
- }
- if (failures & WEBDAV_AUTH_SSL_OTHER)
- {
- stringbuf_appendcstr(buf, "- The certificate has an unknown error.\n");
- }
- stringbuf_t * msg = stringbuf_createf(pool,
- // "Certificate information:\n"
- " - Hostname: %s\n"
- " - Valid: from %s until %s\n"
- " - Issuer: %s\n"
- " - Fingerprint: %s",
- cert_info->hostname,
- cert_info->valid_from,
- cert_info->valid_until,
- cert_info->issuer_dname,
- cert_info->fingerprint);
- stringbuf_appendstr(buf, msg);
- auth_baton_t * ab = static_cast<auth_baton_t *>(pb->cancel_baton);
- assert(ab);
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(ab->parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- unsigned int RequestResult = 0;
- WEBDAV_ERR(fs->VerifyCertificate(buf->data, cert_info->fingerprint, RequestResult));
- if (RequestResult == qaYes)
- {
- *cred_p = static_cast<auth_cred_ssl_server_trust_t *>(apr_pcalloc(pool, sizeof(**cred_p)));
- (*cred_p)->may_save = TRUE;
- (*cred_p)->accepted_failures = failures;
- }
- else if (RequestResult == qaNo)
- {
- *cred_p = static_cast<auth_cred_ssl_server_trust_t *>(apr_pcalloc(pool, sizeof(**cred_p)));
- (*cred_p)->may_save = FALSE;
- (*cred_p)->accepted_failures = failures;
- }
- else
- {
- *cred_p = NULL;
- }
- return WEBDAV_NO_ERROR;
- }
- // This implements 'auth_ssl_client_cert_prompt_func_t'.
- static error_t
- cmdline_auth_ssl_client_cert_prompt(
- auth_cred_ssl_client_cert_t ** cred_p,
- void * baton,
- const char * realm,
- bool may_save,
- apr_pool_t * pool)
- {
- auth_cred_ssl_client_cert_t * cred = NULL;
- const char * cert_file = NULL;
- const char * abs_cert_file = NULL;
- cmdline_prompt_baton2_t * pb =
- static_cast<cmdline_prompt_baton2_t *>(baton);
- auth_baton_t * ab = static_cast<auth_baton_t *>(pb->cancel_baton);
- assert(ab);
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(ab->parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- unsigned int RequestResult = 0;
- WEBDAV_ERR(fs->AskForClientCertificateFilename(&cert_file, RequestResult, pool));
- if (RequestResult != qaOK) return WEBDAV_NO_ERROR;
- WEBDAV_ERR(dirent_get_absolute(&abs_cert_file, cert_file, pool));
- cred = static_cast<auth_cred_ssl_client_cert_t *>(apr_pcalloc(pool, sizeof(*cred)));
- cred->cert_file = abs_cert_file;
- cred->may_save = may_save;
- *cred_p = cred;
- return WEBDAV_NO_ERROR;
- }
- // This implements 'auth_ssl_client_cert_pw_prompt_func_t'.
- static error_t
- cmdline_auth_ssl_client_cert_pw_prompt(
- auth_cred_ssl_client_cert_pw_t ** cred_p,
- void * baton,
- const char * realm,
- bool may_save,
- apr_pool_t * pool)
- {
- auth_cred_ssl_client_cert_pw_t * cred = NULL;
- cmdline_prompt_baton2_t * pb =
- static_cast<cmdline_prompt_baton2_t *>(baton);
- auth_baton_t * ab = static_cast<auth_baton_t *>(pb->cancel_baton);
- assert(ab);
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(ab->parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- unsigned int RequestResult = 0;
- const char * result = NULL;
- WEBDAV_ERR(fs->AskForPassphrase(&result, realm, RequestResult, pool));
- if (RequestResult != qaOK) return WEBDAV_NO_ERROR;
- cred = static_cast<auth_cred_ssl_client_cert_pw_t *>(apr_pcalloc(pool, sizeof(*cred)));
- cred->password = result;
- cred->may_save = may_save;
- *cred_p = cred;
- return WEBDAV_NO_ERROR;
- }
- // This implements 'auth_simple_prompt_func_t'.
- static error_t
- cmdline_auth_simple_prompt(
- auth_cred_simple_t ** cred_p,
- void * baton,
- const char * realm,
- const char * username,
- bool may_save,
- apr_pool_t * pool)
- {
- auth_cred_simple_t * ret =
- static_cast<auth_cred_simple_t *>(apr_pcalloc(pool, sizeof(*ret)));
- cmdline_prompt_baton2_t * pb =
- static_cast<cmdline_prompt_baton2_t *>(baton);
- auth_baton_t * ab = static_cast<auth_baton_t *>(pb->cancel_baton);
- assert(ab);
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(ab->parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- unsigned int RequestResult = 0;
- if (username)
- ret->username = apr_pstrdup(pool, username);
- else
- {
- WEBDAV_ERR(fs->AskForUsername(&ret->username, RequestResult, pool));
- if (RequestResult != qaOK) return WEBDAV_NO_ERROR;
- }
- WEBDAV_ERR(fs->AskForUserPassword(&ret->password, RequestResult, pool));
- if (RequestResult != qaOK) return WEBDAV_NO_ERROR;
- ret->may_save = may_save;
- *cred_p = ret;
- return WEBDAV_NO_ERROR;
- }
- // This implements 'auth_username_prompt_func_t'.
- static error_t
- cmdline_auth_username_prompt(
- auth_cred_username_t ** cred_p,
- void * baton,
- const char * realm,
- bool may_save,
- apr_pool_t * pool)
- {
- auth_cred_username_t * ret =
- static_cast<auth_cred_username_t *>(apr_pcalloc(pool, sizeof(*ret)));
- cmdline_prompt_baton2_t * pb =
- static_cast<cmdline_prompt_baton2_t *>(baton);
- auth_baton_t * ab = static_cast<auth_baton_t *>(pb->cancel_baton);
- assert(ab);
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(ab->parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- unsigned int RequestResult = 0;
- WEBDAV_ERR(fs->AskForUsername(&ret->username, RequestResult, pool));
- if (RequestResult != qaOK) return WEBDAV_NO_ERROR;
- ret->may_save = may_save;
- *cred_p = ret;
- return WEBDAV_NO_ERROR;
- }
- //---------------------------------------------------------------------------
- // from cmdline.c
- static error_t
- ssl_trust_unknown_server_cert(
- auth_cred_ssl_server_trust_t ** cred_p,
- void * baton,
- const char * realm,
- apr_uint32_t failures,
- const auth_ssl_server_cert_info_t * cert_info,
- bool may_save,
- apr_pool_t * pool)
- {
- *cred_p = NULL;
- if (failures == 0 || failures == WEBDAV_AUTH_SSL_UNKNOWNCA)
- {
- *cred_p = static_cast<auth_cred_ssl_server_trust_t *>(apr_pcalloc(pool, sizeof(**cred_p)));
- (*cred_p)->may_save = FALSE;
- (*cred_p)->accepted_failures = failures;
- }
- return WEBDAV_NO_ERROR;
- }
- static error_t
- auth_baton_init(
- auth_baton_t * ab,
- bool non_interactive,
- const char * auth_username,
- const char * auth_password,
- bool no_auth_cache,
- bool trust_server_cert,
- TWebDAVFileSystem * fs,
- cancel_func_t cancel_func,
- void * cancel_baton,
- apr_pool_t * pool)
- {
- bool store_password_val = TRUE;
- bool store_auth_creds_val = TRUE;
- auth_provider_object_t * provider = NULL;
- cmdline_prompt_baton2_t * pb = NULL;
- // The whole list of registered providers
- apr_array_header_t * providers = NULL;
- // Populate the registered providers with the platform-specific providers
- WEBDAV_ERR(auth_get_platform_specific_client_providers(&providers,
- pool));
- // If we have a cancellation function, cram it and the stuff it
- // needs into the prompt baton.
- if (cancel_func)
- {
- pb = static_cast<cmdline_prompt_baton2_t *>(apr_pcalloc(pool, sizeof(*pb)));
- pb->cancel_func = cancel_func;
- pb->cancel_baton = cancel_baton;
- }
- if (non_interactive == FALSE)
- {
- // This provider doesn't prompt the user in order to get creds;
- // it prompts the user regarding the caching of creds.
- auth_get_simple_provider2(&provider,
- cmdline_auth_plaintext_prompt,
- pb, pool);
- }
- else
- {
- auth_get_simple_provider2(&provider, NULL, NULL, pool);
- }
- APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
- auth_get_username_provider(&provider, pool);
- APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
- // The server-cert, client-cert, and client-cert-password providers.
- WEBDAV_ERR(auth_get_platform_specific_provider(&provider,
- "windows",
- "ssl_server_trust",
- pool));
- APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
- auth_get_ssl_server_trust_file_provider(&provider, pool);
- APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
- auth_get_ssl_client_cert_file_provider(&provider, pool);
- APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
- if (non_interactive == FALSE)
- {
- // This provider doesn't prompt the user in order to get creds;
- // it prompts the user regarding the caching of creds.
- auth_get_ssl_client_cert_pw_file_provider2(&provider, cmdline_auth_plaintext_passphrase_prompt,
- pb, pool);
- }
- else
- {
- auth_get_ssl_client_cert_pw_file_provider2(&provider, NULL, NULL,
- pool);
- }
- APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
- if (non_interactive == FALSE)
- {
- // Two basic prompt providers: username/password, and just username.
- auth_get_simple_prompt_provider(&provider,
- cmdline_auth_simple_prompt,
- pb,
- 2, // retry limit
- pool);
- APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
- auth_get_username_prompt_provider(&provider, cmdline_auth_username_prompt, pb,
- 2, /* retry limit */ pool);
- APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
- // Three ssl prompt providers, for server-certs, client-certs,
- // and client-cert-passphrases.
- auth_get_ssl_server_trust_prompt_provider(&provider, cmdline_auth_ssl_server_trust_prompt, pb, pool);
- APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
- auth_get_ssl_client_cert_prompt_provider(&provider, cmdline_auth_ssl_client_cert_prompt, pb, 2, pool);
- APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
- auth_get_ssl_client_cert_pw_prompt_provider(&provider, cmdline_auth_ssl_client_cert_pw_prompt, pb, 2, pool);
- APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
- }
- else if (trust_server_cert)
- {
- // Remember, only register this provider if non_interactive.
- auth_get_ssl_server_trust_prompt_provider(&provider, ssl_trust_unknown_server_cert, NULL, pool);
- APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
- }
- // Build an authentication baton to give to libclient.
- create_baton_open(ab, providers, pool);
- auth_baton_set_parameter(ab, CONST_FS_KEY, fs);
- // Place any default username or password credentials into the
- // auth_baton's run-time parameter hash.
- if (auth_username)
- auth_baton_set_parameter(ab, WEBDAV_AUTH_PARAM_DEFAULT_USERNAME,
- auth_username);
- if (auth_password)
- auth_baton_set_parameter(ab, WEBDAV_AUTH_PARAM_DEFAULT_PASSWORD,
- auth_password);
- // Same with the non-interactive option.
- if (non_interactive)
- auth_baton_set_parameter(ab, WEBDAV_AUTH_PARAM_NON_INTERACTIVE, "");
- if (!store_password_val)
- auth_baton_set_parameter(ab, WEBDAV_AUTH_PARAM_DONT_STORE_PASSWORDS, "");
- if (no_auth_cache || !store_auth_creds_val)
- auth_baton_set_parameter(ab, WEBDAV_AUTH_PARAM_NO_AUTH_CACHE, "");
- return WEBDAV_NO_ERROR;
- }
- //---------------------------------------------------------------------------
- // from main.c
- // A flag to see if we've been canceled by the client or not.
- static volatile atomic_t cancelled = FALSE;
- // Our cancellation callback.
- static error_t
- check_cancel(void * baton)
- {
- if (cancelled)
- return error_create(WEBDAV_ERR_CANCELLED, NULL, "Cancelled");
- else
- return WEBDAV_NO_ERROR;
- }
- //---------------------------------------------------------------------------
- // from ra.c
- static error_t
- cancel_callback(void * baton)
- {
- callback_baton_t * cb = static_cast<callback_baton_t *>(baton);
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(cb->ctx->auth_baton->parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- cancelled = static_cast<atomic_t>(fs->GetIsCancelled());
- return error_trace((cb->ctx->cancel_func)(cb->ctx->cancel_baton));
- }
- static error_t
- get_client_string(
- void * baton,
- const char ** name,
- apr_pool_t * pool)
- {
- callback_baton_t * b = static_cast<callback_baton_t *>(baton);
- *name = apr_pstrdup(pool, b->ctx->client_name);
- return WEBDAV_NO_ERROR;
- }
- // see ra.c::client_session_from_path
- static error_t
- init_session_from_path(
- session_t * session,
- const char ** url_p,
- const char * path_or_url,
- apr_pool_t * pool)
- {
- const char * initial_url, *url;
- neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
- assert(ras);
- WEBDAV_ERR(client_url_from_path2(&initial_url, path_or_url,
- ras->url, pool, pool));
- if (!initial_url)
- return error_createf(WEBDAV_ERR_ENTRY_MISSING_URL, NULL,
- "'%s' has no URL", path_or_url);
- url = initial_url;
- // Make the session point to the real URL.
- WEBDAV_ERR(reparent(session, url, pool));
- *url_p = url;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- client_open_session_internal(
- session_t ** ra_session,
- const char ** corrected_url,
- const char * base_url,
- client_ctx_t * ctx,
- apr_pool_t * pool)
- {
- // prepare callbacks, contexts
- callbacks2_t * cbtable = static_cast<callbacks2_t *>(apr_pcalloc(pool, sizeof(*cbtable)));
- callback_baton_t * cb = static_cast<callback_baton_t *>(apr_pcalloc(pool, sizeof(*cb)));
- cbtable->auth_baton = ctx->auth_baton;
- cbtable->progress_func = ctx->progress_func;
- cbtable->progress_baton = ctx->progress_baton;
- cbtable->cancel_func = ctx->cancel_func ? cancel_callback : NULL;
- cbtable->get_client_string = get_client_string;
- cb->pool = pool;
- cb->ctx = ctx;
- if (corrected_url)
- {
- apr_hash_t * attempted = apr_hash_make(pool);
- int attempts_left = MAX_REDIRECT_ATTEMPTS;
- while (attempts_left--)
- {
- const char * corrected = NULL;
- WEBDAV_ERR(session_open(
- ra_session,
- attempts_left == 0 ? NULL : &corrected,
- base_url, cbtable, cb,
- pool));
- // No error and no corrected URL? We're done here.
- if (!corrected)
- break;
- // Our caller will want to know what our final corrected URL was.
- *corrected_url = corrected;
- // Make sure we've not attempted this URL before.
- if (apr_hash_get(attempted, corrected, APR_HASH_KEY_STRING))
- return WEBDAV_ERR_CLIENT_CYCLE_DETECTED;
- // Remember this CORRECTED_URL so we don't wind up in a loop.
- apr_hash_set(attempted, apr_pstrdup(pool, corrected), APR_HASH_KEY_STRING, (void *)1);
- base_url = corrected;
- }
- }
- else
- {
- WEBDAV_ERR(session_open(ra_session, NULL, base_url,
- cbtable, cb,
- pool));
- }
- return WEBDAV_NO_ERROR;
- }
- //---------------------------------------------------------------------------
- // from list.c
- static error_t
- get_dir_contents(
- apr_uint32_t dirent_fields,
- const char * dir,
- session_t * ra_session,
- const char * fs_path,
- depth_t depth,
- client_list_func_t list_func,
- void * baton,
- apr_pool_t * pool)
- {
- apr_hash_t * tmpdirents = NULL;
- apr_pool_t * iterpool = webdav_pool_create(pool);
- apr_array_header_t * array = NULL;
- error_t err = 0;
- if (depth == depth_empty)
- return WEBDAV_NO_ERROR;
- // Get the directory's entries, but not its props. Ignore any
- // not-authorized errors.
- err = get_dir2(ra_session, &tmpdirents,
- dir,
- dirent_fields, pool);
- if (err && ((err == WEBDAV_ERR_NOT_AUTHORIZED) ||
- (err == WEBDAV_ERR_DAV_FORBIDDEN)))
- {
- error_clear(&err);
- return WEBDAV_NO_ERROR;
- }
- WEBDAV_ERR(err);
- neon_session_t * ras = static_cast<neon_session_t *>(ra_session->priv);
- assert(ras);
- if (ras->callbacks->cancel_func)
- WEBDAV_ERR(ras->callbacks->cancel_func(ras->callback_baton));
- // Sort the hash, so we can call the callback in a "deterministic" order.
- array = sort_hash(tmpdirents, sort_compare_items_lexically, pool);
- for (int i = 0; i < array->nelts; ++i)
- {
- sort_item_t * item = &APR_ARRAY_IDX(array, i, sort_item_t);
- dirent_t * the_ent = static_cast<dirent_t *>(apr_hash_get(tmpdirents, item->key, item->klen));
- webdav_pool_clear(iterpool);
- const char * path = relpath_join(dir, static_cast<const char *>(item->key), iterpool);
- if ((the_ent->kind == node_file) ||
- (depth == depth_immediates) ||
- (depth == depth_infinity))
- WEBDAV_ERR(list_func(baton, path,
- the_ent,
- fs_path, iterpool));
- if (depth == depth_infinity && the_ent->kind == node_dir)
- WEBDAV_ERR(get_dir_contents(dirent_fields, path,
- ra_session,
- fs_path, depth,
- list_func, baton, iterpool));
- }
- webdav_pool_destroy(iterpool);
- return WEBDAV_NO_ERROR;
- }
- //------------------------------------------------------------------------------
- // from options.c
- static const neon_xml_elm_t options_elements[] =
- {
- { "DAV:", "href", ELEM_href, NEON_XML_CDATA },
- { "DAV:", "options-response", ELEM_options_response, 0 },
- { NULL }
- };
- typedef struct options_ctx_t
- {
- // WARNING: WANT_CDATA should stay the first element in the baton:
- // neon_xml_collect_cdata() assumes the baton starts with a stringbuf.
- stringbuf_t * want_cdata;
- stringbuf_t * cdata;
- apr_pool_t * pool;
- } options_ctx_t;
- static int
- options_validate_element(
- neon_xml_elmid parent,
- neon_xml_elmid child)
- {
- switch (parent)
- {
- case ELEM_root:
- if (child == ELEM_options_response)
- return child;
- else
- return NEON_XML_INVALID;
- case ELEM_options_response:
- return NEON_XML_DECLINE; // not concerned with other response
- default:
- return NEON_XML_DECLINE;
- }
- // NOTREACHED
- }
- static error_t
- options_start_element(
- int * elem,
- void * baton,
- int parent,
- const char * nspace,
- const char * name,
- const char ** atts)
- {
- options_ctx_t * oc = static_cast<options_ctx_t *>(baton);
- const neon_xml_elm_t * elm = neon_lookup_xml_elem(options_elements, nspace, name);
- *elem = elm ? options_validate_element(parent, elm->id) : NEON_XML_DECLINE;
- if (*elem < 1) // Not a valid element
- return WEBDAV_NO_ERROR;
- if (elm->id == ELEM_href)
- oc->want_cdata = oc->cdata;
- else
- oc->want_cdata = NULL;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- options_end_element(
- void * baton,
- int state,
- const char * nspace,
- const char * name)
- {
- return WEBDAV_NO_ERROR;
- }
- static error_t
- neon_exchange_capabilities(
- neon_session_t * ras,
- const char ** relocation_location,
- apr_pool_t * pool)
- {
- neon_request_t * req = NULL;
- error_t err = WEBDAV_NO_ERROR;
- ne_xml_parser * parser = NULL;
- options_ctx_t oc = { 0 };
- int status_code = 0;
- oc.pool = pool;
- oc.cdata = stringbuf_create("", pool);
- if (relocation_location)
- *relocation_location = NULL;
- WEBDAV_ERR(neon_request_create(&req, ras,
- "OPTIONS", ras->url->data, pool));
- // Use a symbolic name somewhere for this MIME type?
- ne_add_request_header(req->ne_req, "Content-Type", "text/xml");
- apr_hash_t * extra_headers = apr_hash_make(pool);
- neon_add_depth_header(extra_headers, NEON_DEPTH_ZERO);
- // Create a parser to read the normal response body
- parser = neon_xml_parser_create(req, ne_accept_2xx, options_start_element,
- neon_xml_collect_cdata,
- options_end_element, &oc);
- // Run the request and get the resulting status code.
- if ((err = neon_request_dispatch(&status_code, req, extra_headers,
- "<?xml version=\"1.0\" "
- "encoding=\"utf-8\"?>"
- "<D:options xmlns:D=\"DAV:\">"
- "<D:resourcetype/>"
- "</D:options>",
- 200,
- relocation_location ? 301 : 0,
- false,
- pool)) != WEBDAV_NO_ERROR)
- goto cleanup;
- if (req->code == 301)
- {
- *relocation_location = neon_request_get_location(req, pool);
- goto cleanup;
- }
- // Was there an XML parse error somewhere?
- err = neon_check_parse_error("OPTIONS", parser, ras->url->data);
- if (err)
- goto cleanup;
- cleanup:
- neon_request_destroy(req);
- return err;
- }
- //------------------------------------------------------------------------------
- // from props.c
- typedef struct propfind_ctx_t
- {
- // WARNING: WANT_CDATA should stay the first element in the baton:
- // neon_xml_collect_cdata() assumes the baton starts with a stringbuf.
- stringbuf_t * cdata;
- apr_hash_t * props; // const char *URL-PATH -> neon_resource_t
- neon_resource_t * rsrc; // the current resource.
- const char * encoding; // property encoding (or NULL)
- int status; // status for the current <propstat> (or 0 if unknown).
- apr_hash_t * propbuffer; // holds properties until their status is known.
- neon_xml_elmid last_open_id; // the id of the last opened tag.
- ne_xml_parser * parser; // xml parser handling the PROPSET request.
- apr_pool_t * pool;
- } propfind_ctx_t;
- // When we begin a checkout, we fetch these from the "public" resources.
- // We fetch the resourcetype to
- // verify that we're accessing a collection.
- static const ne_propname starting_props[] =
- {
- { "DAV:", "resourcetype" },
- { "DAV:", "creationdate" },
- { "DAV:", "getlastmodified" },
- { "DAV:", "getcontentlength" },
- { NULL }
- };
- static error_t
- neon_get_starting_props(
- neon_resource_t ** rsrc,
- neon_session_t * sess,
- const char * url,
- bool check_errors,
- apr_pool_t * pool)
- {
- WEBDAV_ERR(neon_get_props_resource(rsrc, sess, url,
- starting_props, check_errors, pool));
- // Cache some of the resource information.
- if (!sess->webdav_root)
- {
- string_t * propval = NULL;
- if (propval)
- {
- ne_uri uri = {0};
- stringbuf_t * urlbuf = stringbuf_create(url, pool);
- path_remove_components(urlbuf,
- path_component_count(propval->data));
- uri = sess->root;
- uri.path = urlbuf->data;
- sess->webdav_root = neon_uri_unparse(&uri, sess->pool);
- }
- }
- return WEBDAV_NO_ERROR;
- }
- // Propfind Implementation
- typedef struct elem_defn
- {
- neon_xml_elmid id;
- const char * name;
- int is_property; // is it a property, or part of some structure?
- } elem_defn;
- static const elem_defn elem_definitions[] =
- {
- // NOTE: Make sure that every item in here is also represented in
- // propfind_elements[]
- // DAV elements
- { ELEM_multistatus, "DAV:multistatus", 0 },
- { ELEM_response, "DAV:response", 0 },
- { ELEM_href, "DAV:href", NEON_XML_CDATA },
- { ELEM_propstat, "DAV:propstat", 0 },
- { ELEM_prop, "DAV:prop", 0 },
- { ELEM_status, "DAV:status", NEON_XML_CDATA },
- { ELEM_collection, "DAV:collection", NEON_XML_CDATA },
- { ELEM_resourcetype, "DAV:resourcetype", 0 },
- { ELEM_get_content_length, NEON_PROP_GETCONTENTLENGTH, 1 },
- { ELEM_creationdate, NEON_PROP_CREATIONDATE, 1 },
- { 0 }
- };
- static const neon_xml_elm_t propfind_elements[] =
- {
- // NOTE: Make sure that every item in here is also represented in
- // elem_definitions[]
- // DAV elements
- { "DAV:", "multistatus", ELEM_multistatus, 0 },
- { "DAV:", "response", ELEM_response, 0 },
- { "DAV:", "href", ELEM_href, NEON_XML_CDATA },
- { "DAV:", "propstat", ELEM_propstat, 0 },
- { "DAV:", "prop", ELEM_prop, 0 },
- { "DAV:", "status", ELEM_status, NEON_XML_CDATA },
- { "DAV:", "collection", ELEM_collection, NEON_XML_CDATA },
- { "DAV:", "resourcetype", ELEM_resourcetype, 0 },
- { "DAV:", "getcontentlength", ELEM_get_content_length, NEON_XML_CDATA },
- { "DAV:", "getlastmodified", ELEM_get_last_modified, NEON_XML_CDATA },
- {
- "DAV:", "creator-displayname", ELEM_creator_displayname,
- NEON_XML_CDATA
- },
- // Unknowns
- { "", "", ELEM_unknown, NEON_XML_COLLECT },
- { NULL }
- };
- // Look up an element definition ID. May return NULL if the elem is
- // not recognized.
- static const elem_defn *
- defn_from_id(
- neon_xml_elmid id)
- {
- for (const elem_defn * defn = elem_definitions; defn->name != NULL; ++defn)
- {
- if (id == defn->id)
- return defn;
- }
- return NULL;
- }
- // Assign URL to RSRC. Use POOL for any allocations.
- static error_t
- assign_rsrc_url(
- neon_resource_t * rsrc,
- const char * url,
- apr_pool_t * pool)
- {
- char * url_path = NULL;
- apr_size_t len = 0;
- ne_uri parsed_url = {0};
- // Parse the PATH element out of the URL.
- // NOTE: mod_dav does not (currently) use an absolute URL, but simply a
- // server-relative path (i.e. this uri_parse is effectively a no-op).
- if (ne_uri_parse(url, &parsed_url) != 0)
- {
- ne_uri_free(&parsed_url);
- return error_createf(WEBDAV_ERR_DAV_MALFORMED_DATA, NULL,
- "Unable to parse URL '%s'", url);
- }
- url_path = apr_pstrdup(pool, parsed_url.path);
- ne_uri_free(&parsed_url);
- // Clean up trailing slashes from the URL.
- len = strlen(url_path);
- if ((len > 1) && (url_path[len - 1] == '/'))
- url_path[len - 1] = '\0';
- rsrc->url = url_path;
- return WEBDAV_NO_ERROR;
- }
- // Determine whether we're receiving the expected XML response.
- // Return CHILD when interested in receiving the child's contents
- // or one of NEON_XML_INVALID and NEON_XML_DECLINE
- // when respectively this is the incorrect response or
- // the element (and its children) are uninteresting
- static int
- props_validate_element(
- neon_xml_elmid parent,
- neon_xml_elmid child)
- {
- switch (parent)
- {
- case ELEM_root:
- if (child == ELEM_multistatus)
- return child;
- else
- return NEON_XML_INVALID;
- case ELEM_multistatus:
- if (child == ELEM_response)
- return child;
- else
- return NEON_XML_DECLINE;
- case ELEM_response:
- if ((child == ELEM_href) || (child == ELEM_propstat))
- return child;
- else
- return NEON_XML_DECLINE;
- case ELEM_propstat:
- if ((child == ELEM_prop) || (child == ELEM_status))
- return child;
- else
- return NEON_XML_DECLINE;
- case ELEM_prop:
- return child; // handle all children of <prop>
- case ELEM_resourcetype:
- if (child == ELEM_collection)
- return child;
- else
- return NEON_XML_DECLINE; // not concerned with other types (now)
- default:
- return NEON_XML_DECLINE;
- }
- // NOTREACHED
- }
- static error_t
- props_start_element(
- int * elem,
- void * baton,
- int parent,
- const char * nspace,
- const char * name,
- const char ** atts)
- {
- propfind_ctx_t * pc = static_cast<propfind_ctx_t *>(baton);
- const neon_xml_elm_t * elm = neon_lookup_xml_elem(propfind_elements, nspace, name);
- *elem = elm ? props_validate_element(parent, elm->id) : NEON_XML_DECLINE;
- if (*elem < 1) // not a valid element
- return WEBDAV_NO_ERROR;
- stringbuf_setempty(pc->cdata);
- *elem = elm ? elm->id : ELEM_unknown;
- switch (*elem)
- {
- case ELEM_response:
- if (pc->rsrc)
- return error_create(WEBDAV_ERR_XML_MALFORMED, NULL, NULL);
- // Create a new resource.
- pc->rsrc = static_cast<neon_resource_t *>(apr_pcalloc(pc->pool, sizeof(*(pc->rsrc))));
- pc->rsrc->pool = pc->pool;
- pc->rsrc->propset = apr_hash_make(pc->pool);
- pc->status = 0;
- break;
- case ELEM_propstat:
- pc->status = 0;
- break;
- case ELEM_href:
- pc->rsrc->href_parent = pc->last_open_id;
- break;
- case ELEM_collection:
- pc->rsrc->is_collection = 1;
- break;
- case ELEM_unknown:
- // these are our user-visible properties, presumably.
- if (pc->encoding)
- pc->encoding = apr_pstrdup(pc->pool, pc->encoding);
- break;
- default:
- // nothing to do for these
- break;
- }
- // Remember the last tag we opened.
- pc->last_open_id = *elem;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- props_end_element(
- void * baton,
- int state,
- const char * nspace,
- const char * name)
- {
- propfind_ctx_t * pc = static_cast<propfind_ctx_t *>(baton);
- neon_resource_t * rsrc = pc->rsrc;
- const string_t * value = NULL;
- const elem_defn * parent_defn = NULL;
- const elem_defn * defn = NULL;
- ne_status status = {0};
- const char * cdata = pc->cdata->data;
- switch (state)
- {
- case ELEM_response:
- // Verify that we've received a URL for this resource.
- if (!pc->rsrc->url)
- return error_create(WEBDAV_ERR_XML_MALFORMED, NULL, NULL);
- // Store the resource in the top-level hash table.
- apr_hash_set(pc->props, pc->rsrc->url, APR_HASH_KEY_STRING, pc->rsrc);
- pc->rsrc = NULL;
- return WEBDAV_NO_ERROR;
- case ELEM_propstat:
- // We're at the end of a set of properties. Do the right thing status-wise.
- if (pc->status)
- {
- for (apr_hash_index_t * hi = apr_hash_first(pc->pool, pc->propbuffer); hi;
- hi = apr_hash_next(hi))
- {
- const void * key;
- apr_ssize_t klen;
- void * val;
- apr_hash_this(hi, &key, &klen, &val);
- if (pc->status == 200)
- apr_hash_set(rsrc->propset, key, klen, val);
- apr_hash_set(pc->propbuffer, key, klen, NULL);
- }
- }
- else if (!pc->status)
- {
- // No status at all? Bogosity.
- return error_create(WEBDAV_ERR_XML_MALFORMED, NULL, NULL);
- }
- return WEBDAV_NO_ERROR;
- case ELEM_status:
- // Parse the <status> tag's CDATA for a status code.
- if (ne_parse_statusline(cdata, &status))
- return error_create(WEBDAV_ERR_XML_MALFORMED, NULL, NULL);
- ne_free(status.reason_phrase);
- pc->status = status.code;
- return WEBDAV_NO_ERROR;
- case ELEM_href:
- // Special handling for <href> that belongs to the <response> tag.
- if (rsrc->href_parent == ELEM_response)
- return assign_rsrc_url(pc->rsrc,
- urlpath_canonicalize(cdata, pc->pool),
- pc->pool);
- // Use the parent element's name, not the href.
- parent_defn = defn_from_id(rsrc->href_parent);
- // No known parent? Get outta here.
- if (!parent_defn)
- return WEBDAV_NO_ERROR;
- // All other href's we'll treat as property values.
- name = parent_defn->name;
- value = string_create(urlpath_canonicalize(cdata, pc->pool),
- pc->pool);
- break;
- default:
- if (state == ELEM_unknown)
- {
- name = apr_pstrcat(pc->pool, nspace, name, (char *)NULL);
- }
- else
- {
- defn = defn_from_id(state);
- if (!(defn && defn->is_property))
- return WEBDAV_NO_ERROR;
- name = defn->name;
- }
- // Check for encoding attribute.
- if (pc->encoding == NULL)
- {
- // Handle the property value by converting it to string.
- value = string_create(cdata, pc->pool);
- break;
- }
- // Check for known encoding type
- if (strcmp(pc->encoding, "base64") != 0)
- return error_create(WEBDAV_ERR_XML_MALFORMED, NULL, NULL);
- pc->encoding = NULL; // Reset encoding for future attribute(s).
- }
- // Handling resource properties from here out.
- // Add properties to the temporary propbuffer. At the end of the
- // <propstat>, we'll either dump the props as invalid or move them
- // into the resource's property hash.
- apr_hash_set(pc->propbuffer, name, APR_HASH_KEY_STRING, value);
- return WEBDAV_NO_ERROR;
- }
- static void
- props_set_parser(
- ne_xml_parser * parser,
- void * baton)
- {
- propfind_ctx_t * pc = static_cast<propfind_ctx_t *>(baton);
- pc->parser = parser;
- }
- static error_t
- neon_get_props(
- apr_hash_t ** results,
- neon_session_t * sess,
- const char * url,
- int depth,
- const ne_propname * which_props,
- bool check_errors,
- apr_pool_t * pool)
- {
- apr_hash_t * extra_headers = apr_hash_make(pool);
- neon_add_depth_header(extra_headers, depth);
- // It's easier to roll our own PROPFIND here than use neon's current interfaces.
- // The start of the request body is fixed:
- stringbuf_t * body = stringbuf_create("<?xml version=\"1.0\" encoding=\"utf-8\"?>" DEBUG_CR
- "<propfind xmlns=\"DAV:\">" DEBUG_CR, pool);
- // Are we asking for specific propert(y/ies), or just all of them?
- if (which_props)
- {
- apr_pool_t * iterpool = webdav_pool_create(pool);
- stringbuf_appendcstr(body, "<prop>" DEBUG_CR);
- for (int n = 0; which_props[n].name != NULL; n++)
- {
- webdav_pool_clear(iterpool);
- stringbuf_appendcstr(body, apr_pstrcat(iterpool, "<", which_props[n].name,
- " xmlns=\"", which_props[n].nspace, "\"/>" DEBUG_CR,
- (char *)NULL));
- }
- stringbuf_appendcstr(body, "</prop></propfind>" DEBUG_CR);
- webdav_pool_destroy(iterpool);
- }
- else
- {
- stringbuf_appendcstr(body, "<allprop/></propfind>" DEBUG_CR);
- }
- // Initialize our baton.
- propfind_ctx_t pc;
- memset(&pc, 0, sizeof(pc));
- pc.pool = pool;
- pc.propbuffer = apr_hash_make(pool);
- pc.props = apr_hash_make(pool);
- pc.cdata = stringbuf_create("", pool);
- // Create and dispatch the request!
- WEBDAV_ERR(neon_parsed_request(sess, "PROPFIND", url,
- body->data, 0,
- props_set_parser,
- props_start_element,
- neon_xml_collect_cdata,
- props_end_element,
- &pc, extra_headers, NULL,
- check_errors,
- pool));
- *results = pc.props;
- return WEBDAV_NO_ERROR;
- }
- static error_t
- neon_get_props_resource(
- neon_resource_t ** rsrc,
- neon_session_t * sess,
- const char * url,
- const ne_propname * which_props,
- bool check_errors,
- apr_pool_t * pool)
- {
- apr_hash_t * props = NULL;
- char * url_path = apr_pstrdup(pool, url);
- apr_size_t len = strlen(url);
- // Clean up any trailing slashes.
- if ((len > 1) && (url[len - 1] == '/'))
- url_path[len - 1] = '\0';
- WEBDAV_ERR(neon_get_props(&props, sess, url_path, NEON_DEPTH_ZERO,
- which_props, check_errors, pool));
- // HACK. We need to have the client canonicalize paths, get rid
- // of double slashes and such. This check is just a check against
- // non-SVN servers; in the long run we want to re-enable this.
- {
- // pick out the first response: the URL requested will not match
- // the response href.
- apr_hash_index_t * hi = apr_hash_first(pool, props);
- if (hi)
- {
- void * ent;
- apr_hash_this(hi, NULL, NULL, &ent);
- *rsrc = static_cast<neon_resource_t *>(ent);
- }
- else
- *rsrc = NULL;
- }
- if (*rsrc == NULL)
- {
- // hmmm, should have been in there...
- return error_createf(APR_EGENERAL, NULL,
- "Failed to find label '%s' for URL '%s'",
- "NULL", url_path);
- }
- return WEBDAV_NO_ERROR;
- }
- //------------------------------------------------------------------------------
- static error_t
- client_list2(
- session_t * session,
- const char * path_or_url,
- depth_t depth,
- apr_uint32_t dirent_fields,
- client_list_func_t list_func,
- void * baton,
- apr_pool_t * pool)
- {
- dirent_t * dirent = NULL;
- const char * url = NULL;
- const char * webdav_root = NULL;
- const char * fs_path = NULL;
- error_t err = 0;
- assert(session);
- // We use the kind field to determine if we should recurse, so we
- // always need it.
- dirent_fields |= WEBDAV_DIRENT_KIND;
- WEBDAV_ERR(init_session_from_path(session,
- &url, path_or_url,
- pool));
- WEBDAV_ERR(get_webdav_resource_root2(session, &webdav_root, pool));
- WEBDAV_ERR(client_path_relative_to_root(&fs_path,
- url,
- webdav_root, TRUE, session,
- pool, pool));
- err = stat(session, "", &dirent, pool);
- if (err)
- return error_trace(err);
- if (!dirent)
- return error_createf(WEBDAV_ERR_FS_NOT_FOUND, NULL,
- "URL '%s' non-existent",
- url);
- // Report the dirent for the target.
- WEBDAV_ERR(list_func(baton, "", dirent, fs_path, pool));
- if (dirent->kind == node_dir && (depth == depth_files ||
- depth == depth_immediates ||
- depth == depth_infinity))
- {
- WEBDAV_ERR(get_dir_contents(dirent_fields, "",
- session,
- fs_path, depth,
- list_func, baton, pool));
- }
- return WEBDAV_NO_ERROR;
- }
- static error_t
- client_get_file(
- session_t * session,
- const char * remote_path,
- apr_os_file_t * thefile,
- apr_pool_t * pool)
- {
- const char * remote_url = NULL;
- WEBDAV_ERR(init_session_from_path(session,
- &remote_url, path_uri_encode(remote_path, pool),
- pool));
- stream_t * fstream = NULL;
- WEBDAV_ERR(stream_open_writable(&fstream, thefile,
- pool, pool));
- const char * src_rel = NULL;
- WEBDAV_ERR(get_path_relative_to_session(session, &src_rel,
- remote_url,
- pool));
- WEBDAV_ERR(get_file(session, src_rel, fstream, NULL, pool));
- WEBDAV_ERR(stream_close(fstream));
- return WEBDAV_NO_ERROR;
- }
- static error_t
- client_put_file(
- session_t * session,
- const char * remote_path,
- const char * local_path,
- apr_pool_t * pool)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
- assert(ras);
- error_t err = 0;
- int code = 0;
- apr_hash_t * extra_headers = NULL; // apr_hash_make(pool);
- neon_request_t * request = NULL;
- const char * put_target = path_uri_encode(remote_path, pool);
- apr_file_t * body_file = NULL;
- WEBDAV_ERR(io_file_open(&body_file, local_path, APR_READ | APR_BUFFERED | APR_BINARY,
- APR_OS_DEFAULT, pool));
- // create/prep the request
- WEBDAV_ERR(neon_request_create(&request, ras, "PUT",
- put_target, pool));
- // Give the file to neon. The provider will rewind the file.
- err = neon_set_neon_body_provider(request, body_file);
- if (err)
- goto cleanup;
- // run the request and get the resulting status code (and error_t)
- err = neon_request_dispatch(&code, request, extra_headers, NULL,
- 201 /* Created */,
- 204 /* No Content */,
- false,
- pool);
- if (err && (err == WEBDAV_ERR_DAV_REQUEST_FAILED))
- {
- err = error_createf(WEBDAV_ERR_CANNOT_PUT_FILE, NULL,
- "Cannot create '%s'"
- " (Status %d on PUT Request)",
- put_target, code);
- }
- cleanup:
- neon_request_destroy(request);
- WEBDAV_ERR(err);
- return WEBDAV_NO_ERROR;
- }
- static error_t
- client_move_file_or_directory(
- session_t * session,
- const char * remote_path_from,
- const char * remote_path_to,
- void * baton,
- apr_pool_t * pool)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
- assert(ras);
- error_t err = 0;
- const char * target_from = path_uri_encode(remote_path_from, pool);
- const char * target_to = path_uri_encode(remote_path_to, pool);
- int code = 0;
- apr_hash_t * extra_headers = apr_hash_make(pool);
- apr_hash_set(extra_headers, "Destination", APR_HASH_KEY_STRING, target_to);
- neon_add_depth_header(extra_headers, NEON_DEPTH_INFINITE);
- err = neon_simple_request(&code, ras, "MOVE", target_from,
- extra_headers, NULL,
- 201 /* Created */,
- 204 /* No Content */,
- pool);
- if (err && (err == WEBDAV_ERR_DAV_REQUEST_FAILED))
- {
- err = error_createf(WEBDAV_ERR_CANNOT_MOVE, NULL,
- "Cannot move '%s' to '%s'"
- " (Status %d on MOVE Request)",
- target_from, target_to, code);
- }
- return err;
- }
- static error_t
- client_delete_file(
- session_t * session,
- const char * remote_path,
- void * baton,
- apr_pool_t * pool)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
- assert(ras);
- error_t err = 0;
- const char * target = path_uri_encode(remote_path, pool);
- int code = 0;
- err = neon_simple_request(&code, ras, "DELETE", target,
- NULL, NULL,
- 200,
- 204, // No Content
- pool);
- if (err && (err == WEBDAV_ERR_DAV_REQUEST_FAILED))
- {
- err = error_createf(WEBDAV_ERR_CANNOT_DELETE_FILE, NULL,
- "Cannot delete '%s'"
- " (Status %d on DELETE Request)",
- target, code);
- }
- return err;
- }
- static error_t
- client_check_path(
- session_t * session,
- const char * remote_path,
- node_kind_t * kind,
- apr_pool_t * pool)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
- assert(ras);
- *kind = node_none;
- error_t err = 0;
- char * target = apr_pstrdup(pool, path_uri_encode(remote_path, pool));
- const char * rel_path = NULL;
- apr_size_t len = strlen(target);
- if ((len > 1) && ((target)[len - 1] == '/'))
- {
- (target)[len - 1] = '\0';
- }
- if (*target == '/')
- {
- // check if root has trailing slash
- apr_size_t len = strlen(ras->webdav_root);
- if ((len > 1) && ((ras->webdav_root)[len - 1] == '/'))
- {
- target++;
- }
- const char * abs_path = apr_pstrcat(pool, ras->webdav_root, target, NULL);
- err = get_path_relative_to_root(
- session,
- &rel_path,
- abs_path,
- pool);
- WEBDAV_ERR(err);
- }
- else
- {
- rel_path = target;
- }
- err = check_path(
- session,
- rel_path,
- kind,
- pool
- );
- return err;
- }
- static error_t
- client_make_directory(
- session_t * session,
- const char * remote_path,
- void * baton,
- apr_pool_t * pool)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
- assert(ras);
- error_t err = 0;
- const char * target = path_uri_encode(remote_path, pool);
- int code = 0;
- err = neon_simple_request(
- &code, ras, "MKCOL", target,
- NULL, NULL,
- 201, 207, pool);
- if (err && (err == WEBDAV_ERR_DAV_REQUEST_FAILED))
- {
- err = error_createf(WEBDAV_ERR_CANNOT_MKCOL, NULL,
- "Cannot create directory '%s'"
- " (Status %d on MKCOL Request)",
- target, code);
- }
- return err;
- }
- static error_t
- client_send_propfind_request(
- session_t * session,
- const char * remote_path,
- int * response_code,
- apr_pool_t * pool)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
- assert(ras);
- error_t err = 0;
- int code = 0;
- apr_hash_t * props = NULL;
- const char * target = path_uri_encode(remote_path, pool);
- char * url_path = apr_pstrdup(pool, target);
- WEBDAV_ERR(neon_get_props(&props, ras, url_path, NEON_DEPTH_ZERO,
- starting_props,
- false,
- pool));
- if (err && (err == WEBDAV_ERR_DAV_REQUEST_FAILED))
- {
- err = error_createf(WEBDAV_ERR_CANNOT_PROPFIND, NULL,
- "Cannot execute PROPFIND on '%s'"
- " (Status %d on PROPFIND Request)",
- target, code);
- }
- if (response_code)
- *response_code = code;
- return err;
- }
- //------------------------------------------------------------------------------
- // from session.c
- typedef struct neonprogress_baton_t
- {
- neon_session_t * ras;
- apr_off_t last_progress;
- apr_time_t last_progress_time;
- apr_pool_t * pool;
- } neonprogress_baton_t;
- // Callback invoked to enter PKCS#11 PIN code.
- static int
- client_ssl_pkcs11_pin_entry(
- void * userdata,
- int attempt,
- const char * slot_descr,
- const char * token_label,
- unsigned int flags,
- char * pin)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(userdata);
- void * creds = NULL;
- auth_cred_ssl_client_cert_pw_t * pw_creds = NULL;
- // Always prevent PIN caching.
- auth_baton_set_parameter(ras->callbacks->auth_baton,
- AUTH_PARAM_NO_AUTH_CACHE, "");
- error_t err = 0;
- if (attempt == 0)
- {
- const char * realmstring;
- realmstring = apr_psprintf(ras->pool,
- "PIN for token \"%s\" in slot \"%s\"",
- token_label, slot_descr);
- err = auth_first_credentials(&creds,
- &(ras->auth_iterstate),
- AUTH_CRED_SSL_CLIENT_CERT_PW,
- realmstring,
- ras->callbacks->auth_baton,
- ras->pool);
- }
- else
- {
- err = auth_next_credentials(&creds, ras->auth_iterstate, ras->pool);
- }
- if (err || !creds)
- {
- error_clear(&err);
- return -1;
- }
- pw_creds = static_cast<auth_cred_ssl_client_cert_pw_t *>(creds);
- strncpy(pin, pw_creds->password, NE_SSL_P11PINLEN);
- return 0;
- }
- static bool
- client_ssl_decrypt_cert(
- neon_session_t * ras,
- const char * cert_file,
- ne_ssl_client_cert * clicert)
- {
- auth_iterstate_t * state = NULL;
- error_t error = 0;
- apr_pool_t * pool = NULL;
- bool ok = false;
- void * creds = NULL;
- int try_count = 0;
- apr_pool_create(&pool, ras->pool);
- for (try_count = 0; TRUE; ++try_count)
- {
- if (try_count == 0)
- {
- error = auth_first_credentials(&creds, &state,
- AUTH_CRED_SSL_CLIENT_CERT_PW,
- cert_file,
- ras->callbacks->auth_baton,
- pool);
- }
- else
- {
- error = auth_next_credentials(&creds, state, pool);
- }
- if (error || !creds)
- {
- // Failure or too many attempts
- error_clear(&error);
- break;
- }
- else
- {
- auth_cred_ssl_client_cert_pw_t * pw_creds = static_cast<auth_cred_ssl_client_cert_pw_t *>(creds);
- if (ne_ssl_clicert_decrypt(clicert, pw_creds->password) == 0)
- {
- error = auth_save_credentials(state, pool);
- if (error)
- error_clear(&error);
- // Success
- ok = TRUE;
- break;
- }
- }
- }
- webdav_pool_destroy(pool);
- return ok;
- }
- static void
- client_ssl_callback(
- void * userdata,
- ne_session * sess,
- const ne_ssl_dname * const * dnames,
- int dncount)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(userdata);
- ne_ssl_client_cert * clicert = NULL;
- void * creds = NULL;
- auth_iterstate_t * state = NULL;
- const char * realmstring = NULL;
- apr_pool_t * pool = NULL;
- error_t error = 0;
- int try_count = 0;
- apr_pool_create(&pool, ras->pool);
- realmstring = apr_psprintf(pool, "%s://%s:%d", ras->root.scheme,
- ras->root.host, ras->root.port);
- for (try_count = 0; TRUE; ++try_count)
- {
- if (try_count == 0)
- {
- error = auth_first_credentials(&creds, &state,
- AUTH_CRED_SSL_CLIENT_CERT,
- realmstring,
- ras->callbacks->auth_baton,
- pool);
- }
- else
- {
- error = auth_next_credentials(&creds, state, pool);
- }
- if (error || !creds)
- {
- // Failure or too many attempts
- error_clear(&error);
- break;
- }
- else
- {
- auth_cred_ssl_client_cert_t * client_creds = static_cast<auth_cred_ssl_client_cert_t *>(creds);
- clicert = ne_ssl_clicert_read(client_creds->cert_file);
- if (clicert)
- {
- if (!ne_ssl_clicert_encrypted(clicert) ||
- client_ssl_decrypt_cert(ras, client_creds->cert_file,
- clicert))
- {
- ne_ssl_set_clicert(sess, clicert);
- }
- ne_ssl_clicert_free(clicert);
- clicert = NULL;
- break;
- }
- }
- }
- webdav_pool_destroy(pool);
- }
- static const apr_uint32_t neon_failure_map[][2] =
- {
- { NE_SSL_NOTYETVALID, WEBDAV_AUTH_SSL_NOTYETVALID },
- { NE_SSL_EXPIRED, WEBDAV_AUTH_SSL_EXPIRED },
- { NE_SSL_IDMISMATCH, WEBDAV_AUTH_SSL_CNMISMATCH },
- { NE_SSL_UNTRUSTED, WEBDAV_AUTH_SSL_UNKNOWNCA }
- };
- // Convert neon's SSL failure mask to our own failure mask.
- static apr_uint32_t
- convert_neon_failures(
- int neon_failures)
- {
- apr_uint32_t failures = 0;
- for (apr_size_t i = 0; i < sizeof(neon_failure_map) / (2 * sizeof(int)); ++i)
- {
- if (neon_failures & neon_failure_map[i][0])
- {
- failures |= neon_failure_map[i][1];
- neon_failures &= ~neon_failure_map[i][0];
- }
- }
- // Map any remaining neon failure bits to our OTHER bit.
- if (neon_failures)
- {
- failures |= WEBDAV_AUTH_SSL_OTHER;
- }
- return failures;
- }
- // A neon-session callback to validate the SSL certificate when the CA
- // is unknown (e.g. a self-signed cert), or there are other SSL
- // certificate problems.
- static int
- server_ssl_callback(
- void * userdata,
- int failures,
- const ne_ssl_certificate * cert)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(userdata);
- auth_cred_ssl_server_trust_t * server_creds = NULL;
- void * creds = NULL;
- auth_iterstate_t * state = NULL;
- apr_pool_t * pool = NULL;
- error_t error = 0;
- char * ascii_cert = ne_ssl_cert_export(cert);
- char * issuer_dname = ne_ssl_readable_dname(ne_ssl_cert_issuer(cert));
- auth_ssl_server_cert_info_t cert_info = {0};
- char fingerprint[NE_SSL_DIGESTLEN] = {0};
- char valid_from[NE_SSL_VDATELEN] = {0}, valid_until[NE_SSL_VDATELEN] = {0};
- apr_uint32_t * webdav_failures = static_cast<apr_uint32_t *>(apr_pcalloc(ras->pool, sizeof(*webdav_failures)));
- // Construct the realmstring, e.g. https://svn.collab.net:80
- const char * realmstring = apr_pstrdup(ras->pool, Format("%s://%s:%d", ras->root.scheme,
- ras->root.host, ras->root.port).c_str());
- *webdav_failures = convert_neon_failures(failures);
- auth_baton_set_parameter(ras->callbacks->auth_baton,
- AUTH_PARAM_SSL_SERVER_FAILURES,
- webdav_failures);
- // Extract the info from the certificate
- cert_info.hostname = ne_ssl_cert_identity(cert);
- if (ne_ssl_cert_digest(cert, fingerprint) != 0)
- {
- strcpy(fingerprint, "<unknown>");
- }
- cert_info.fingerprint = fingerprint;
- ne_ssl_cert_validity(cert, valid_from, valid_until);
- cert_info.valid_from = valid_from;
- cert_info.valid_until = valid_until;
- cert_info.issuer_dname = issuer_dname;
- cert_info.ascii_cert = ascii_cert;
- auth_baton_set_parameter(ras->callbacks->auth_baton,
- AUTH_PARAM_SSL_SERVER_CERT_INFO,
- &cert_info);
- apr_pool_create(&pool, ras->pool);
- error = auth_first_credentials(&creds, &state,
- AUTH_CRED_SSL_SERVER_TRUST,
- realmstring,
- ras->callbacks->auth_baton,
- pool);
- if (error || !creds)
- {
- error_clear(&error);
- }
- else
- {
- server_creds = static_cast<auth_cred_ssl_server_trust_t *>(creds);
- error = auth_save_credentials(state, pool);
- if (error)
- {
- // It would be nice to show the error to the user somehow...
- error_clear(&error);
- }
- }
- free(issuer_dname);
- free(ascii_cert);
- auth_baton_set_parameter(ras->callbacks->auth_baton,
- AUTH_PARAM_SSL_SERVER_CERT_INFO, NULL);
- webdav_pool_destroy(pool);
- return !server_creds;
- }
- // An `ne_request_auth' callback, see ne_auth.h. USERDATA is a struct proxy_auth_baton_t *
- // If ATTEMPT < 10, copy USERDATA->username and USERDATA->password
- // into USERNAME and PASSWORD respectively (but do not copy more than
- // NE_ABUFSIZ bytes of either), and return zero to indicate to Neon
- // that authentication should be attempted.
- // If ATTEMPT >= 10, copy nothing into USERNAME and PASSWORD and
- // return 1, to cancel further authentication attempts.
- // Ignore REALM.
- static int
- proxy_auth(
- void * userdata,
- const char * realm,
- int attempt,
- char * username,
- char * password)
- {
- proxy_auth_baton_t * pab = static_cast<proxy_auth_baton_t *>(userdata);
- if (attempt >= 10)
- return 1;
- // Else.
- strncpy(username, pab->username, NE_ABUFSIZ);
- strncpy(password, pab->password, NE_ABUFSIZ);
- return 0;
- }
- // A neon-session callback to 'pull' authentication data when
- // challenged. In turn, this routine 'pulls' the data from the client
- // callbacks if needed.
- static int
- request_auth(
- void * userdata,
- const char * realm,
- int attempt,
- char * username,
- char * password)
- {
- error_t err = 0;
- neon_session_t * ras = static_cast<neon_session_t *>(userdata);
- void * creds = NULL;
- auth_cred_simple_t * simple_creds = NULL;
- // Start by marking the current credentials invalid.
- ras->auth_used = false;
- // No auth_baton? Give up.
- if (!ras->callbacks->auth_baton)
- return -1;
- // Neon automatically tries some auth protocols and bumps the attempt
- // count without using our callbacks, so we can't depend
- // on attempt == 0 the first time we are called -- we need to check
- // if the auth state has been initted as well.
- if (attempt == 0 || ras->auth_iterstate == NULL)
- {
- const char * realmstring = apr_psprintf(ras->pool, "<%s://%s:%d> %s",
- ras->root.scheme, ras->root.host,
- ras->root.port, realm);
- err = auth_first_credentials(&creds,
- &(ras->auth_iterstate),
- AUTH_CRED_SIMPLE,
- realmstring,
- ras->callbacks->auth_baton,
- ras->pool);
- }
- else // attempt > 0
- // TODO: if the http realm changed this time around, we
- // should be calling first_creds(), not next_creds().
- err = auth_next_credentials(&creds,
- ras->auth_iterstate,
- ras->pool);
- if (err || !creds)
- {
- error_clear(&err);
- return -1;
- }
- simple_creds = static_cast<auth_cred_simple_t *>(creds);
- // Make neon_request_dispatch store the credentials after it
- // sees a successful response
- ras->auth_used = true;
- // silently truncates username/password to 256 chars.
- if (simple_creds->username) strncpy(username, simple_creds->username, NE_ABUFSIZ);
- if (simple_creds->password) strncpy(password, simple_creds->password, NE_ABUFSIZ);
- return 0;
- }
- // a cleanup routine attached to the pool that contains the RA session baton.
- static apr_status_t
- cleanup_session(
- void * sess)
- {
- ne_session_destroy(static_cast<ne_session *>(sess));
- return APR_SUCCESS;
- }
- // a cleanup routine attached to the pool that contains the PKCS#11
- // provider object.
- static apr_status_t
- cleanup_p11provider(
- void * provider)
- {
- ne_ssl_pkcs11_provider * prov = static_cast<ne_ssl_pkcs11_provider *>(provider);
- ne_ssl_pkcs11_provider_destroy(prov);
- return APR_SUCCESS;
- }
- #ifdef NETBOX_DEBUG
- typedef struct debug_file_baton_t
- {
- FILE * file;
- } debug_file_baton_t;
- // a cleanup routine
- static apr_status_t
- cleanup_neon_debug_file(
- void * debug_file_baton)
- {
- debug_file_baton_t * baton = static_cast<debug_file_baton_t *>(debug_file_baton);
- if (baton->file) fclose(baton->file);
- return APR_SUCCESS;
- }
- #endif
- static void
- progress_func(
- apr_off_t progress,
- apr_off_t total,
- void * baton,
- apr_pool_t * pool)
- {
- client_ctx_t * ctx = static_cast<client_ctx_t *>(baton);
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(ctx->auth_baton->parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- if (total == -1)
- fs->ReadDirectoryProgress(progress);
- else
- fs->FileTransferProgress(total, progress);
- }
- static void
- ra_neon_neonprogress(
- void * baton,
- apr_off_t progress,
- apr_off_t total)
- {
- neonprogress_baton_t * pb = static_cast<neonprogress_baton_t *>(baton);
- neon_session_t * ras = pb->ras;
- if (ras->progress_func)
- {
- apr_time_t now = apr_time_now();
- if (now - pb->last_progress_time > 200000) // 0.2 sec
- {
- if (total < 0)
- {
- // Neon sends the total number of bytes sent for this specific
- // session and there are two sessions active at once.
- // For this case we combine the totals to allow clients to provide
- // a better progress indicator.
- if (progress >= pb->last_progress)
- ras->total_progress += (progress - pb->last_progress);
- else
- // Session total has been reset. A new stream started
- ras->total_progress += pb->last_progress;
- pb->last_progress = progress;
- ras->progress_func(ras->total_progress, -1, ras->progress_baton, pb->pool);
- }
- else
- {
- // Neon provides total bytes to receive information. Pass literally
- // to allow providing a percentage.
- ras->progress_func(progress, total, ras->progress_baton, pb->pool);
- }
- pb->last_progress_time = now;
- }
- }
- }
- static atomic_t neon_initialized = 0;
- static error_t
- initialize_neon(
- void * baton,
- apr_pool_t * scratch_pool)
- {
- if (ne_sock_init() != 0)
- return error_create(WEBDAV_ERR_DAV_SOCK_INIT, NULL,
- "Network socket initialization failed");
- return WEBDAV_NO_ERROR;
- }
- static error_t
- ensure_neon_initialized()
- {
- return atomic_init_once(&neon_initialized, initialize_neon, NULL, NULL);
- }
- static const char * const *
- ra_neon_get_schemes(apr_pool_t * pool)
- {
- static const char * schemes_no_ssl[] = { "http", NULL };
- static const char * schemes_ssl[] = { "http", "https", NULL };
- return ne_has_support(NE_FEATURE_SSL) ? schemes_ssl : schemes_no_ssl;
- }
- static error_t
- neon_open(
- session_t * session,
- const char ** corrected_url,
- const char * session_URL,
- const callbacks2_t * callbacks,
- void * callback_baton,
- apr_pool_t * pool)
- {
- assert(callback_baton);
- callback_baton_t * cb = static_cast<callback_baton_t *>(callback_baton);
- *corrected_url = NULL;
- ne_uri * uri = NULL;
- WEBDAV_ERR(parse_ne_uri(&uri, session_URL, pool));
- // Initialize neon if required
- WEBDAV_ERR(ensure_neon_initialized());
- int is_ssl_session = (strcmp(uri->scheme, "https") == 0);
- if (is_ssl_session)
- {
- if (ne_has_support(NE_FEATURE_SSL) == 0)
- return error_create(WEBDAV_ERR_DAV_SOCK_INIT, NULL,
- "TLS is not supported");
- }
- ne_session * sess = ne_session_create(uri->scheme, uri->host, uri->port);
- apr_pool_cleanup_register(pool, sess, cleanup_session, apr_pool_cleanup_null);
- bool compression = FALSE;
- unsigned int neon_auth_types = 0;
- const char * pkcs11_provider = NULL;
- const char * ssl_authority_file = NULL;
- {
- int proxy_method = 0;
- const char * proxy_host = NULL;
- unsigned int proxy_port = 0;
- const char * proxy_username = NULL;
- const char * proxy_password = NULL;
- int timeout = 0;
- int debug = 0;
- const char * neon_debug_file_name = NULL;
- TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(cb->ctx->auth_baton->parameters,
- CONST_FS_KEY,
- APR_HASH_KEY_STRING));
- assert(fs);
- WEBDAV_ERR(fs->GetServerSettings(
- &proxy_method,
- &proxy_host,
- &proxy_port,
- &proxy_username,
- &proxy_password,
- &timeout,
- &debug,
- &neon_debug_file_name,
- &compression,
- &pkcs11_provider,
- &ssl_authority_file,
- pool));
- if (neon_auth_types == 0)
- {
- // If there were no auth types specified in the configuration
- // file, provide the appropriate defaults.
- neon_auth_types = NE_AUTH_BASIC | NE_AUTH_DIGEST;
- if (is_ssl_session)
- neon_auth_types |= NE_AUTH_NEGOTIATE;
- }
- if (debug && neon_debug_file_name)
- {
- #ifdef NETBOX_DEBUG
- debug_file_baton_t * baton = static_cast<debug_file_baton_t *>(apr_pcalloc(pool, sizeof(*baton)));
- neon_debug_file_name = apr_pstrcat(pool, neon_debug_file_name, ".neondebug.log", NULL);
- baton->file = _fsopen(neon_debug_file_name, "w", SH_DENYWR);
- if (baton->file)
- {
- debug = NE_DBG_HTTP |
- // NE_DBG_XML | NE_DBG_HTTPAUTH |
- NE_DBG_HTTPPLAIN |
- // NE_DBG_XMLPARSE |
- NE_DBG_HTTPBODY |
- // NE_DBG_SSL |
- NE_DBG_FLUSH;
- ne_debug_init(baton->file, debug);
- }
- apr_pool_cleanup_register(pool, baton,
- cleanup_neon_debug_file,
- apr_pool_cleanup_null);
- #else
- ne_debug_init(NULL, 0);
- #endif // #ifdef NETBOX_DEBUG
- }
- TProxyMethod method = (TProxyMethod)proxy_method;
- if (method != ::pmNone)
- {
- if ((method == pmSocks4) || (method == pmSocks5))
- {
- enum ne_sock_sversion vers = method == pmSocks4 ? NE_SOCK_SOCKSV4A : NE_SOCK_SOCKSV5;
- ne_session_socks_proxy(sess, vers, proxy_host, proxy_port, proxy_username, proxy_password);
- }
- else if (proxy_host)
- {
- ne_session_proxy(sess, proxy_host, proxy_port);
- if (proxy_username)
- {
- proxy_auth_baton_t * pab = static_cast<proxy_auth_baton_t *>(apr_pcalloc(pool, sizeof(*pab)));
- pab->username = proxy_username;
- pab->password = proxy_password ? proxy_password : "";
- ne_set_proxy_auth(sess, proxy_auth, pab);
- }
- else
- {
- // Enable (only) the Negotiate scheme for proxy
- // authentication, if no username/password is
- // configured.
- ne_add_proxy_auth(sess, NE_AUTH_NEGOTIATE, NULL, NULL);
- }
- }
- }
- if (!timeout)
- timeout = DEFAULT_HTTP_TIMEOUT;
- ne_set_read_timeout(sess, timeout);
- ne_set_connect_timeout(sess, timeout);
- }
- {
- static std::string useragent = "WinSCP";
- ne_set_useragent(sess, useragent.c_str());
- }
- // Create and fill a session_baton.
- neon_session_t * ras = static_cast<neon_session_t *>(apr_pcalloc(pool, sizeof(*ras)));
- ras->pool = pool;
- {
- // canonicalize url
- const char * remote_url = urlpath_canonicalize(session_URL, pool);
- ras->url = stringbuf_create(remote_url, pool);
- }
- // copies uri pointer members, they get free'd in __close.
- ras->root = *uri;
- ras->ne_sess = sess;
- ras->callbacks = callbacks;
- ras->callback_baton = callback_baton;
- ras->compression = compression;
- ras->progress_baton = callbacks->progress_baton;
- ras->progress_func = callbacks->progress_func;
- ras->capabilities = apr_hash_make(ras->pool);
- // note that ras->username and ras->password are still NULL at this point.
- // Register an authentication 'pull' callback with the neon sessions
- ne_add_server_auth(sess, neon_auth_types, request_auth, ras);
- if (is_ssl_session)
- {
- bool trust_default_ca = false;
- // PEM-encoded Certificate Authority (CA) SSL certificate
- const char * authorities = ssl_authority_file;
- if (authorities != NULL && *authorities)
- {
- const char * file = authorities;
- ne_ssl_certificate * ca_cert = NULL;
- ca_cert = ne_ssl_cert_read(file);
- if (ca_cert == NULL)
- {
- return error_createf(
- WEBDAV_ERR_BAD_CONFIG_VALUE, NULL,
- "Invalid config: unable to load certificate file '%s'", file);
- }
- ne_ssl_trust_cert(sess, ca_cert);
- ne_ssl_cert_free(ca_cert);
- ca_cert = NULL;
- }
- // When the CA certificate or server certificate has
- // verification problems, neon will call our verify function before
- // outright rejection of the connection.*/
- ne_ssl_set_verify(sess, server_ssl_callback, ras);
- // For client connections, we register a callback for if the server
- // wants to authenticate the client via client certificate.
- if (pkcs11_provider && *pkcs11_provider)
- {
- ne_ssl_pkcs11_provider * provider;
- int rv;
- // Initialize the PKCS#11 provider.
- rv = ne_ssl_pkcs11_provider_init(&provider, pkcs11_provider);
- if (rv != NE_PK11_OK)
- {
- return error_createf(WEBDAV_ERR_BAD_CONFIG_VALUE, NULL,
- "Invalid config: unable to load PKCS#11 provider '%s'",
- pkcs11_provider);
- }
- // Share the provider between the two sessions.
- ne_ssl_set_pkcs11_provider(sess, provider);
- ne_ssl_pkcs11_provider_pin(provider, client_ssl_pkcs11_pin_entry, ras);
- apr_pool_cleanup_register(pool, provider, cleanup_p11provider,
- apr_pool_cleanup_null);
- }
- // Note the "else"; if a PKCS#11 provider is set up, a client
- // cert callback is already configured, so don't displace it
- // with the normal one here.
- else
- {
- ne_ssl_provide_clicert(sess, client_ssl_callback, ras);
- }
- // See if the user wants us to trust "default" openssl CAs.
- // TODO: option "trust default CA"
- trust_default_ca = true;
- if (trust_default_ca)
- {
- ne_ssl_trust_default_ca(sess);
- }
- }
- if (ras->progress_func)
- {
- neonprogress_baton_t * progress1 = static_cast<neonprogress_baton_t *>(apr_pcalloc(pool, sizeof(*progress1)));
- neonprogress_baton_t * progress2 = static_cast<neonprogress_baton_t *>(apr_pcalloc(pool, sizeof(*progress2)));
- progress1->pool = pool;
- progress1->ras = ras;
- progress1->last_progress = 0;
- progress2->pool = pool;
- progress2->ras = ras;
- progress2->last_progress = 0;
- ne_set_progress(sess, ra_neon_neonprogress, progress1);
- }
- session->priv = ras;
- const char * corrected = NULL;
- error_t err = neon_exchange_capabilities(ras, &corrected, pool);
- if (corrected)
- *corrected_url = corrected;
- return err;
- }
- static error_t
- neon_reparent(
- session_t * session,
- const char * url,
- apr_pool_t * pool)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
- ne_uri * uri = NULL;
- WEBDAV_ERR(parse_ne_uri(&uri, url, session->pool));
- ras->root = *uri;
- stringbuf_set(ras->url, url);
- ras->webdav_root = neon_uri_unparse(uri, session->pool);
- return WEBDAV_NO_ERROR;
- }
- static error_t
- neon_get_session_url(
- session_t * session,
- const char ** url,
- apr_pool_t * pool)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
- assert(ras);
- *url = apr_pstrmemdup(pool, ras->url->data, ras->url->len);
- return WEBDAV_NO_ERROR;
- }
- static const ne_propname restype_props[] =
- {
- { "DAV:", "resourcetype" },
- { NULL }
- };
- static error_t
- neon_get_file(
- session_t * session,
- const char * path,
- stream_t * stream,
- apr_hash_t ** props,
- apr_pool_t * pool)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
- assert(ras);
- const char * url = path_url_add_component2(ras->url->data, path, pool);
- const ne_propname * which_props = NULL;
- const char * final_url = url;
- if (props)
- {
- // Request all properties if caller requested them.
- which_props = starting_props;
- }
- else
- {
- // Request only resource type on other cases.
- which_props = restype_props;
- }
- neon_resource_t * rsrc = NULL;
- WEBDAV_ERR(neon_get_props_resource(&rsrc, ras, final_url,
- which_props,
- false,
- pool));
- if (rsrc->is_collection)
- {
- return error_create(WEBDAV_ERR_FS_NOT_FILE, NULL,
- "Can't get text contents of a directory");
- }
- if (stream)
- {
- file_write_ctx_t fwc = {0};
- fwc.stream = stream;
- // Fetch the file, shoving it at the provided stream.
- WEBDAV_ERR(custom_get_request(ras, final_url, path,
- get_file_reader, &fwc,
- ras->callback_baton,
- pool));
- }
- return WEBDAV_NO_ERROR;
- }
- static error_t
- neon_get_dir(
- session_t * session,
- apr_hash_t ** dirents,
- const char * path,
- apr_uint32_t dirent_fields,
- apr_pool_t * pool)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
- const char * url = path_url_add_component2(ras->url->data, path, pool);
- const char * final_url = url;
- if (dirents)
- {
- // Just like Nautilus, Cadaver, or any other browser, we do a
- // PROPFIND on the directory of depth 1.
- apr_hash_t * resources = NULL;
- WEBDAV_ERR(neon_get_props(&resources, ras,
- final_url, NEON_DEPTH_ONE,
- starting_props,
- false,
- pool));
- // Count the number of path components in final_url.
- apr_size_t final_url_n_components = path_component_count(final_url);
- // Now we have a hash that maps a bunch of url children to resource
- // objects. Each resource object contains the properties of the
- // child. Parse these resources into dirent_t structs.
- *dirents = apr_hash_make(pool);
- for (apr_hash_index_t * hi = apr_hash_first(pool, resources); hi;
- hi = apr_hash_next(hi))
- {
- const void * key = NULL;
- void * val = NULL;
- const char * childname = NULL;
- neon_resource_t * resource = NULL;
- const string_t * propval = NULL;
- dirent_t * entry = NULL;
- apr_hash_this(hi, &key, NULL, &val);
- childname = relpath_canonicalize(static_cast<const char *>(key), pool);
- resource = static_cast<neon_resource_t *>(val);
- // Skip the effective '.' entry that comes back from
- // NEON_DEPTH_ONE. The children must have one more
- // component then final_url.
- // Note that we can't just strcmp the URLs because of URL encoding
- // differences (i.e. %3c vs. %3C etc.)
- if (path_component_count(childname) < final_url_n_components - 1)
- continue;
- entry = static_cast<dirent_t *>(apr_pcalloc(pool, sizeof(*entry)));
- if (dirent_fields & WEBDAV_DIRENT_KIND)
- {
- // node kind
- entry->kind = resource->is_collection ? node_dir : node_file;
- }
- if (dirent_fields & WEBDAV_DIRENT_SIZE)
- {
- // size
- propval = static_cast<const string_t *>(apr_hash_get(resource->propset,
- NEON_PROP_GETCONTENTLENGTH,
- APR_HASH_KEY_STRING));
- if (propval == NULL)
- entry->size = 0;
- else
- entry->size = atoui64(propval->data);
- }
- if (dirent_fields & WEBDAV_DIRENT_TIME)
- {
- propval = static_cast<const string_t *>(apr_hash_get(resource->propset,
- NEON_PROP_CREATIONDATE,
- APR_HASH_KEY_STRING));
- if (propval != NULL)
- WEBDAV_ERR(time_from_cstring(&(entry->time),
- propval->data, pool));
- }
- apr_hash_set(*dirents,
- path_uri_decode(relpath_basename(childname,
- pool),
- pool),
- APR_HASH_KEY_STRING, entry);
- }
- }
- return WEBDAV_NO_ERROR;
- }
- static error_t
- neon_check_path(
- session_t * session,
- const char * path,
- node_kind_t * kind,
- apr_pool_t * pool)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
- assert(ras);
- const char * url = ras->url->data;
- error_t err = 0;
- bool is_dir = FALSE;
- // If we were given a relative path to append, append it.
- if (path)
- url = path_url_add_component2(url, path, pool);
- if (!err)
- {
- neon_resource_t * rsrc;
- const char * full_bc_url = url;
- // query the DAV:resourcetype of the full, assembled URL.
- err = neon_get_starting_props(&rsrc, ras, full_bc_url, true, pool);
- if (!err)
- is_dir = rsrc->is_collection != 0;
- }
- if (err == WEBDAV_NO_ERROR)
- {
- if (is_dir)
- *kind = node_dir;
- else
- *kind = node_file;
- }
- else if (err == WEBDAV_ERR_FS_NOT_FOUND)
- {
- error_clear(&err);
- err = WEBDAV_NO_ERROR;
- *kind = node_none;
- }
- return err;
- }
- static error_t
- neon_stat(
- session_t * session,
- const char * path,
- dirent_t ** dirent,
- apr_pool_t * pool)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
- assert(ras);
- const char * url = ras->url->data;
- // If we were given a relative path to append, append it.
- if (path)
- url = path_url_add_component2(url, path, pool);
- const char * final_url = url;
- // Depth-zero PROPFIND is the One True DAV Way.
- apr_hash_t * resources = NULL;
- error_t err = neon_get_props(&resources, ras, final_url,
- NEON_DEPTH_ZERO,
- starting_props,
- false,
- pool);
- if (err)
- {
- if (err == WEBDAV_ERR_FS_NOT_FOUND)
- {
- // easy out:
- error_clear(&err);
- *dirent = NULL;
- return WEBDAV_NO_ERROR;
- }
- else
- return err;
- }
- // Copying parsing code from neon_get_dir() here. The hash
- // of resources only contains one item, but there's no other way to
- // get the item.
- for (apr_hash_index_t * hi = apr_hash_first(pool, resources); hi;
- hi = apr_hash_next(hi))
- {
- void * val = NULL;
- apr_hash_this(hi, NULL, NULL, &val);
- neon_resource_t * resource = static_cast<neon_resource_t *>(val);
- dirent_t * entry = static_cast<dirent_t *>(apr_pcalloc(pool, sizeof(*entry)));
- entry->kind = resource->is_collection ? node_dir : node_file;
- const string_t * propval = NULL;
- // entry->size is already 0 by virtue of pcalloc().
- if (entry->kind == node_file)
- {
- propval = static_cast<const string_t *>(apr_hash_get(resource->propset,
- NEON_PROP_GETCONTENTLENGTH,
- APR_HASH_KEY_STRING));
- if (propval)
- entry->size = atoui64(propval->data);
- }
- propval = static_cast<const string_t *>(apr_hash_get(resource->propset,
- NEON_PROP_CREATIONDATE,
- APR_HASH_KEY_STRING));
- if (propval != NULL)
- WEBDAV_ERR(time_from_cstring(&(entry->time),
- propval->data, pool));
- *dirent = entry;
- }
- return WEBDAV_NO_ERROR;
- }
- static error_t
- neon_get_webdav_resource_root(
- session_t * session,
- const char ** url,
- apr_pool_t * pool)
- {
- neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
- assert(ras);
- *url = ras->webdav_root;
- return WEBDAV_NO_ERROR;
- }
- static const vtable_t neon_vtable =
- {
- NULL, // get_description
- ra_neon_get_schemes, // get_schemes
- neon_open, // open_session
- neon_reparent, // reparent
- neon_get_session_url, // get_session_url
- neon_get_file, // get_file
- neon_get_dir, // get_dir
- neon_check_path, // check_path
- neon_stat, // stat
- neon_get_webdav_resource_root, // get_webdav_resource_root
- };
- static error_t
- neon_init(
- const vtable_t ** vtable,
- apr_pool_t * pool)
- {
- *vtable = &neon_vtable;
- return WEBDAV_NO_ERROR;
- }
- } // namespace webdav
- //---------------------------------------------------------------------------
- class TSessionData;
- //---------------------------------------------------------------------------
- class TWebDAVFileListHelper
- {
- public:
- explicit TWebDAVFileListHelper(TWebDAVFileSystem * FileSystem, TRemoteFileList * FileList,
- bool IgnoreFileList) :
- FFileSystem(FileSystem),
- FFileList(FFileSystem->FFileList),
- FIgnoreFileList(FFileSystem->FIgnoreFileList)
- {
- FFileSystem->FFileList = FileList;
- FFileSystem->FIgnoreFileList = IgnoreFileList;
- }
- ~TWebDAVFileListHelper()
- {
- FFileSystem->FFileList = FFileList;
- FFileSystem->FIgnoreFileList = FIgnoreFileList;
- }
- private:
- TWebDAVFileSystem * FFileSystem;
- TRemoteFileList * FFileList;
- bool FIgnoreFileList;
- };
- //---------------------------------------------------------------------------
- #undef FILE_OPERATION_LOOP_EX
- #define FILE_OPERATION_LOOP_EX(ALLOW_SKIP, MESSAGE, OPERATION) \
- FILE_OPERATION_LOOP_CUSTOM(FTerminal, ALLOW_SKIP, MESSAGE, OPERATION, L"")
- //---------------------------------------------------------------------------
- static const UnicodeString CONST_WEBDAV_PROTOCOL_BASE_NAME = L"WebDAV";
- //===========================================================================
- TWebDAVFileSystem::TWebDAVFileSystem(TTerminal * ATerminal) :
- TCustomFileSystem(ATerminal),
- FFileList(NULL),
- FOnCaptureOutput(NULL),
- FPasswordFailed(false),
- FActive(false),
- FFileTransferAbort(ftaNone),
- FIgnoreFileList(false),
- FFileTransferCancelled(false),
- FFileTransferResumed(0),
- FFileTransferPreserveTime(false),
- FHasTrailingSlash(false),
- FFileTransferCPSLimit(0),
- FLastReadDirectoryProgress(0),
- FCurrentOperationProgress(NULL),
- FTransferStatusCriticalSection(new TCriticalSection()),
- webdav_pool(NULL),
- FSession(NULL)
- {
- FFileSystemInfo.ProtocolBaseName = CONST_WEBDAV_PROTOCOL_BASE_NAME;
- FFileSystemInfo.ProtocolName = FFileSystemInfo.ProtocolBaseName;
- if (apr_initialize() != APR_SUCCESS)
- throw ExtException(UnicodeString(L"Cannot init APR"), NULL);
- apr_pool_create(&webdav_pool, NULL);
- }
- //---------------------------------------------------------------------------
- __fastcall TWebDAVFileSystem::~TWebDAVFileSystem()
- {
- delete FTransferStatusCriticalSection;
- FTransferStatusCriticalSection = NULL;
- webdav_pool_destroy(webdav_pool);
- apr_terminate();
- webdav_pool = NULL;
- ne_sock_exit();
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::Open()
- {
- FCurrentDirectory = L"";
- FHasTrailingSlash = false;
- TSessionData * Data = FTerminal->SessionData;
- FSessionInfo.LoginTime = Now();
- bool Ssl = (FTerminal->SessionData->Ftps != ftpsNone);
- if (Ssl)
- {
- FSessionInfo.SecurityProtocolName = LoadStr(FTPS_IMPLICIT);
- }
- UnicodeString HostName = Data->HostName;
- size_t Port = Data->PortNumber;
- UnicodeString ProtocolName = !Ssl ? L"http" : L"https";
- UnicodeString UserName = Data->UserName;
- UnicodeString Path = Data->RemoteDirectory;
- UnicodeString Url = FORMAT(L"%s://%s:%d%s", (ProtocolName.c_str(), HostName.c_str(), Port, Path.c_str()));
- FPasswordFailed = false;
- FTerminal->Information(LoadStr(STATUS_CONNECT), true);
- for (int I = 0; I < 5; I++)
- {
- FActive = false;
- try
- {
- FActive = (WEBDAV_NO_ERROR == OpenURL(Url, webdav_pool));
- if (FActive)
- {
- break;
- }
- }
- catch (...)
- {
- if (FFileTransferCancelled)
- break;
- apr_sleep(200000); // 0.2 sec
- }
- }
- if (!FActive)
- {
- FTerminal->Closed();
- throw Exception(LoadStr(CONNECTION_FAILED));
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::Close()
- {
- assert(FActive);
- FTerminal->Closed();
- FActive = false;
- }
- //---------------------------------------------------------------------------
- bool __fastcall TWebDAVFileSystem::GetActive()
- {
- return FActive;
- }
- //---------------------------------------------------------------------------
- const TSessionInfo & __fastcall TWebDAVFileSystem::GetSessionInfo()
- {
- return FSessionInfo;
- }
- //---------------------------------------------------------------------------
- const TFileSystemInfo & __fastcall TWebDAVFileSystem::GetFileSystemInfo(bool Retrieve)
- {
- return FFileSystemInfo;
- }
- //---------------------------------------------------------------------------
- bool __fastcall TWebDAVFileSystem::TemporaryTransferFile(const UnicodeString & /*FileName*/)
- {
- return false;
- }
- //---------------------------------------------------------------------------
- bool __fastcall TWebDAVFileSystem::GetStoredCredentialsTried()
- {
- return false;
- }
- //---------------------------------------------------------------------------
- UnicodeString __fastcall TWebDAVFileSystem::GetUserName()
- {
- return FUserName;
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::Idle()
- {
- // TODO: Keep session alive
- return;
- }
- //---------------------------------------------------------------------------
- UnicodeString __fastcall TWebDAVFileSystem::AbsolutePath(const UnicodeString Path, bool /*Local*/)
- {
- return ::AbsolutePath(GetCurrentDirectory(), Path);
- }
- //---------------------------------------------------------------------------
- bool __fastcall TWebDAVFileSystem::IsCapable(int Capability) const
- {
- assert(FTerminal);
- switch (Capability)
- {
- case fcUserGroupListing:
- case fcModeChanging:
- case fcModeChangingUpload:
- case fcPreservingTimestampUpload:
- case fcGroupChanging:
- case fcOwnerChanging:
- case fcAnyCommand:
- case fcShellAnyCommand:
- case fcHardLink:
- case fcSymbolicLink:
- case fcResolveSymlink:
- return false;
- case fcRename:
- case fcRemoteMove:
- case fcRemoteCopy:
- return true;
- case fcTextMode:
- case fcNativeTextMode:
- case fcNewerOnlyUpload:
- case fcTimestampChanging:
- case fcLoadingAdditionalProperties:
- case fcCheckingSpaceAvailable:
- case fcIgnorePermErrors:
- case fcCalculatingChecksum:
- case fcSecondaryShell: // has fcShellAnyCommand
- case fcGroupOwnerChangingByID: // by name
- return false;
- default:
- assert(false);
- return false;
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::EnsureLocation()
- {
- if (!FCachedDirectoryChange.IsEmpty())
- {
- FTerminal->LogEvent(FORMAT(L"Locating to cached directory \"%s\".",
- (FCachedDirectoryChange.c_str())));
- UnicodeString Directory = FCachedDirectoryChange;
- FCachedDirectoryChange = L"";
- try
- {
- ChangeDirectory(Directory);
- }
- catch (...)
- {
- // when location to cached directory fails, pretend again
- // location in cached directory
- // here used to be check (CurrentDirectory != Directory), but it is
- // false always (currentdirectory is already set to cached directory),
- // making the condition below useless. check removed.
- if (FTerminal->GetActive())
- {
- FCachedDirectoryChange = Directory;
- }
- throw;
- }
- }
- }
- //---------------------------------------------------------------------------
- UnicodeString __fastcall TWebDAVFileSystem::GetCurrentDirectory()
- {
- return FCurrentDirectory;
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::DoStartup()
- {
- FTerminal->SetExceptionOnFail(true);
- // retrieve initialize working directory to save it as home directory
- ReadCurrentDirectory();
- FTerminal->SetExceptionOnFail(false);
- }
- //---------------------------------------------------------------------------
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::LookupUsersGroups()
- {
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::ReadCurrentDirectory()
- {
- if (FCachedDirectoryChange.IsEmpty())
- {
- FCurrentDirectory = FCurrentDirectory.IsEmpty() ? UnicodeString(L"/") : FCurrentDirectory;
- }
- else
- {
- FCurrentDirectory = FCachedDirectoryChange;
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::HomeDirectory()
- {
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::AnnounceFileListOperation()
- {
- // noop
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::DoChangeDirectory(const UnicodeString Directory)
- {
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::ChangeDirectory(const UnicodeString ADirectory)
- {
- UnicodeString Directory = ADirectory;
- bool HasTrailingSlash = (Directory.Length() > 0) && (Directory[Directory.Length()] == L'/');
- try
- {
- // For changing directory, we do not make paths absolute, instead we
- // delegate this to the server, hence we synchronize current working
- // directory with the server and only then we ask for the change with
- // relative path.
- // But if synchronization fails, typically because current working directory
- // no longer exists, we fall back to out own resolution, to give
- // user chance to leave the non-existing directory.
- EnsureLocation();
- }
- catch (...)
- {
- if (FTerminal->GetActive())
- {
- Directory = AbsolutePath(Directory, false);
- if (HasTrailingSlash)
- Directory = ::UnixIncludeTrailingBackslash(Directory);
- }
- else
- {
- throw;
- }
- }
- FCurrentDirectory = AbsolutePath(Directory, false);
- if (HasTrailingSlash)
- FCurrentDirectory = ::UnixIncludeTrailingBackslash(FCurrentDirectory);
- // make next ReadCurrentDirectory retrieve actual server-side current directory
- FCachedDirectoryChange = L"";
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::CachedChangeDirectory(const UnicodeString Directory)
- {
- FCachedDirectoryChange = UnixExcludeTrailingBackslash(Directory);
- }
- void __fastcall TWebDAVFileSystem::DoReadDirectory(TRemoteFileList * FileList)
- {
- FileList->Reset();
- // add parent directory
- FileList->AddFile(new TRemoteParentDirectory(FTerminal));
- FLastReadDirectoryProgress = 0;
- TWebDAVFileListHelper Helper(this, FileList, false);
- // always specify path to list, do not attempt to
- // list "current" dir as:
- // 1) List() lists again the last listed directory, not the current working directory
- // 2) we handle this way the cached directory change
- UnicodeString Directory = AbsolutePath(FileList->Directory, false);
- if (FHasTrailingSlash)
- Directory = ::UnixIncludeTrailingBackslash(Directory);
- WebDAVGetList(Directory);
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::ReadDirectory(TRemoteFileList * FileList)
- {
- assert(FileList);
- bool Repeat = false;
- do
- {
- Repeat = false;
- try
- {
- DoReadDirectory(FileList);
- }
- catch (Exception &)
- {
- if (!FTerminal->GetActive())
- {
- FTerminal->Reopen(ropNoReadDirectory);
- Repeat = true;
- }
- else
- {
- throw;
- }
- }
- }
- while (Repeat);
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::ReadSymlink(TRemoteFile * SymlinkFile,
- TRemoteFile *& File)
- {
- CustomReadFile(SymlinkFile->LinkTo, File, SymlinkFile);
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::ReadFile(const UnicodeString FileName,
- TRemoteFile *& File)
- {
- CustomReadFile(FileName, File, NULL);
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::CustomReadFile(const UnicodeString FileName,
- TRemoteFile *& File, TRemoteFile * ALinkedByFile)
- {
- File = NULL;
- bool isExist = false;
- int is_dir = 0;
- isExist = WebDAVCheckExisting(FileName.c_str(), is_dir);
- if (isExist)
- {
- File = new TRemoteFile();
- if (is_dir)
- File->Type = FILETYPE_DIRECTORY;
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::DeleteFile(const UnicodeString FileName,
- const TRemoteFile * File, int Params, TRmSessionAction & Action)
- {
- USEDPARAM(File);
- USEDPARAM(Params);
- UnicodeString FullFileName = File->FullFileName;
- bool res = WebDAVDeleteFile(FullFileName.c_str());
- if (!res)
- {
- THROW_SKIP_FILE(NULL, L"");
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::RenameFile(const UnicodeString FileName,
- const UnicodeString NewName)
- {
- UnicodeString FullFileName = ::UnixIncludeTrailingBackslash(FCurrentDirectory) + FileName;
- bool res = WebDAVRenameFile(FullFileName.c_str(), NewName.c_str());
- if (!res)
- {
- THROW_SKIP_FILE(NULL, L"");
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::CopyFile(const UnicodeString FileName,
- const UnicodeString NewName)
- {
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::CreateDirectory(const UnicodeString DirName)
- {
- UnicodeString FullDirName = AbsolutePath(DirName, true);
- bool res = WebDAVMakeDirectory(FullDirName.c_str());
- if (!res)
- {
- TStringList * Strings = new TStringList();
- Strings->Delimiter = L'/';
- Strings->DelimitedText = DirName;
- UnicodeString CurDir;
- for (int i = 0; i < Strings->Count; i++)
- {
- if (Strings->Strings[i].IsEmpty())
- {
- continue;
- }
- CurDir += L"/" + Strings->Strings[i];
- res = WebDAVMakeDirectory(CurDir.c_str());
- }
- if (!res)
- {
- THROW_SKIP_FILE(NULL, L"");
- }
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::CreateLink(const UnicodeString FileName,
- const UnicodeString PointTo, bool Symbolic)
- {
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::ChangeFileProperties(const UnicodeString FileName,
- const TRemoteFile * File, const TRemoteProperties * Properties,
- TChmodSessionAction & Action)
- {
- assert(Properties);
- }
- //---------------------------------------------------------------------------
- bool __fastcall TWebDAVFileSystem::LoadFilesProperties(TStrings * /*FileList*/)
- {
- assert(false);
- return false;
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::CalculateFilesChecksum(const UnicodeString & /*Alg*/,
- TStrings * /*FileList*/, TStrings * /*Checksums*/,
- TCalculatedChecksumEvent /*OnCalculatedChecksum*/)
- {
- assert(false);
- }
- //---------------------------------------------------------------------------
- bool __fastcall TWebDAVFileSystem::ConfirmOverwrite(UnicodeString & FileName,
- TOverwriteMode & OverwriteMode, TFileOperationProgressType * OperationProgress,
- const TOverwriteFileParams * FileParams, const TCopyParamType * CopyParam,
- int Params, bool AutoResume, unsigned int &Answer)
- {
- bool Result;
- bool CanAutoResume = FLAGSET(Params, cpNoConfirmation) && AutoResume;
- bool CanResume = false; // disable resume
- Answer = 0;
- if (CanAutoResume && CanResume)
- {
- Answer = qaRetry;
- }
- else
- {
- // retry = "resume"
- // all = "yes to newer"
- // ignore = "rename"
- int Answers = qaYes | qaNo | qaCancel | qaYesToAll | qaNoToAll | qaAll | qaIgnore;
- if (CanResume)
- {
- Answers |= qaRetry;
- }
- TQueryButtonAlias Aliases[3];
- Aliases[0].Button = qaRetry;
- Aliases[0].Alias = LoadStr(RESUME_BUTTON);
- Aliases[1].Button = qaAll;
- Aliases[1].Alias = LoadStr(YES_TO_NEWER_BUTTON);
- Aliases[2].Button = qaIgnore;
- Aliases[2].Alias = LoadStr(RENAME_BUTTON);
- TQueryParams QueryParams(qpNeverAskAgainCheck);
- QueryParams.Aliases = Aliases;
- QueryParams.AliasesCount = LENOF(Aliases);
- SUSPEND_OPERATION (
- Answer = FTerminal->ConfirmFileOverwrite(FileName, FileParams,
- Answers, &QueryParams,
- OperationProgress->Side == osLocal ? osRemote : osLocal,
- CopyParam, Params, OperationProgress);
- )
- }
- Result = true;
- switch (Answer)
- {
- // resume
- case qaRetry:
- OverwriteMode = omResume;
- assert(FileParams != NULL);
- assert(CanResume);
- FFileTransferResumed = FileParams->DestSize;
- break;
- // rename
- case qaIgnore:
- if (FTerminal->PromptUser(FTerminal->SessionData, pkFileName,
- LoadStr(RENAME_TITLE), L"", LoadStr(RENAME_PROMPT2), true, 0, FileName))
- {
- OverwriteMode = omOverwrite;
- }
- else
- {
- if (!OperationProgress->Cancel)
- {
- OperationProgress->Cancel = csCancel;
- }
- FFileTransferAbort = ftaCancel;
- Result = false;
- }
- break;
- case qaYes:
- OverwriteMode = omOverwrite;
- break;
- case qaNo:
- FFileTransferAbort = ftaSkip;
- Result = false;
- break;
- case qaCancel:
- if (!OperationProgress->Cancel)
- {
- OperationProgress->Cancel = csCancel;
- }
- FFileTransferAbort = ftaCancel;
- Result = false;
- break;
- default:
- assert(false);
- Result = false;
- break;
- }
- return Result;
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::CustomCommandOnFile(const UnicodeString FileName,
- const TRemoteFile * File, UnicodeString Command, int Params, TCaptureOutputEvent OutputEvent)
- {
- assert(File);
- bool Dir = File->IsDirectory && !File->IsSymLink;
- if (Dir && (Params & ccRecursive))
- {
- TCustomCommandParams AParams;
- AParams.Command = Command;
- AParams.Params = Params;
- AParams.OutputEvent = OutputEvent;
- FTerminal->ProcessDirectory(FileName, FTerminal->CustomCommandOnFile, &AParams);
- }
- if (!Dir || (Params & ccApplyToDirectories))
- {
- TCustomCommandData Data(FTerminal);
- UnicodeString Cmd = TRemoteCustomCommand(
- Data, FTerminal->GetCurrentDirectory(), FileName, L"").
- Complete(Command, true);
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::AnyCommand(const UnicodeString Command,
- TCaptureOutputEvent OutputEvent)
- {
- }
- //---------------------------------------------------------------------------
- UnicodeString __fastcall TWebDAVFileSystem::FileUrl(const UnicodeString FileName)
- {
- return FTerminal->FileUrl(FTerminal->SessionData->Ftps == ftpsNone ?
- L"http" : L"https", FileName);
- }
- //---------------------------------------------------------------------------
- TStrings * __fastcall TWebDAVFileSystem::GetFixedPaths()
- {
- return NULL;
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::SpaceAvailable(const UnicodeString Path,
- TSpaceAvailable & /*ASpaceAvailable*/)
- {
- assert(false);
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::CopyToRemote(TStrings * FilesToCopy,
- const UnicodeString ATargetDir, const TCopyParamType * CopyParam,
- int Params, TFileOperationProgressType * OperationProgress,
- TOnceDoneOperation & OnceDoneOperation)
- {
- assert((FilesToCopy != NULL) && (OperationProgress != NULL));
- Params &= ~cpAppend;
- UnicodeString FileName, FileNameOnly;
- UnicodeString TargetDir = AbsolutePath(ATargetDir, false);
- UnicodeString FullTargetDir = ::UnixIncludeTrailingBackslash(TargetDir);
- intptr_t Index = 0;
- while ((Index < FilesToCopy->Count) && !OperationProgress->Cancel)
- {
- bool Success = false;
- FileName = FilesToCopy->Strings[Index];
- FileNameOnly = ExtractFileName(FileName, false);
- try
- {
- try
- {
- if (FTerminal->SessionData->CacheDirectories)
- {
- FTerminal->DirectoryModified(TargetDir, false);
- if (::DirectoryExists(::ExtractFilePath(FileName)))
- {
- FTerminal->DirectoryModified(FullTargetDir + FileNameOnly, true);
- }
- }
- WebDAVSourceRobust(FileName, FullTargetDir, CopyParam, Params, OperationProgress,
- tfFirstLevel);
- Success = true;
- }
- catch (EScpSkipFile & E)
- {
- SUSPEND_OPERATION (
- if (!FTerminal->HandleException(&E))
- {
- throw;
- }
- );
- }
- }
- __finally
- {
- OperationProgress->Finish(FileName, Success, OnceDoneOperation);
- }
- Index++;
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::WebDAVSourceRobust(const UnicodeString FileName,
- const UnicodeString TargetDir, const TCopyParamType * CopyParam, int Params,
- TFileOperationProgressType * OperationProgress, unsigned int Flags)
- {
- bool Retry = false;
- TUploadSessionAction Action(FTerminal->ActionLog);
- do
- {
- Retry = false;
- try
- {
- WebDAVSource(FileName, TargetDir, CopyParam, Params, OperationProgress,
- Flags, Action);
- }
- catch (Exception & E)
- {
- Retry = true;
- if (FTerminal->GetActive() ||
- !FTerminal->QueryReopen(&E, ropNoReadDirectory, OperationProgress))
- {
- FTerminal->RollbackAction(Action, OperationProgress, &E);
- throw;
- }
- }
- if (Retry)
- {
- OperationProgress->RollbackTransfer();
- Action.Restart();
- // prevent overwrite confirmations
- // (should not be set for directories!)
- Params |= cpNoConfirmation;
- Flags |= tfAutoResume;
- }
- }
- while (Retry);
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::WebDAVSource(const UnicodeString FileName,
- const UnicodeString TargetDir, const TCopyParamType * CopyParam, int Params,
- TFileOperationProgressType * OperationProgress, unsigned int Flags,
- TUploadSessionAction & Action)
- {
- bool CheckExistence = UnixComparePaths(TargetDir, FTerminal->GetCurrentDirectory()) &&
- (FTerminal->FFiles != NULL) && FTerminal->FFiles->Loaded;
- FTerminal->LogEvent(FORMAT(L"File: \"%s\"", (FileName.c_str())));
- bool CanProceed = false;
- UnicodeString FileNameOnly =
- CopyParam->ChangeFileName(ExtractFileName(FileName, false), osLocal, true);
- if (CheckExistence)
- {
- TRemoteFile * File = FTerminal->FFiles->FindFile(FileNameOnly);
- if (File != NULL)
- {
- unsigned int Answer = 0;
- if (File->IsDirectory)
- {
- UnicodeString Message = FMTLOAD(DIRECTORY_OVERWRITE, (FileNameOnly.c_str()));
- TQueryParams QueryParams(qpNeverAskAgainCheck);
- SUSPEND_OPERATION (
- Answer = FTerminal->ConfirmFileOverwrite(
- FileNameOnly /*not used*/, NULL,
- qaYes | qaNo | qaCancel | qaYesToAll | qaNoToAll,
- &QueryParams, osRemote, CopyParam, Params, OperationProgress, Message);
- );
- switch (Answer)
- {
- case qaYes:
- CanProceed = true;
- break;
- case qaCancel:
- OperationProgress->Cancel = csCancel; // continue on next case
- // FALLTHROUGH
- case qaNo:
- CanProceed = false;
- break;
- default:
- break;
- }
- }
- else
- {
- __int64 Size;
- __int64 MTime;
- TOverwriteFileParams FileParams;
- FTerminal->OpenLocalFile(FileName, GENERIC_READ,
- NULL, NULL, NULL, &MTime, NULL,
- &Size);
- FileParams.SourceSize = Size;
- FileParams.SourceTimestamp = UnixToDateTime(MTime,
- FTerminal->SessionData->DSTMode);
- FileParams.DestSize = File->Size;
- FileParams.DestTimestamp = File->Modification;
- TOverwriteMode OverwriteMode = omOverwrite;
- bool AutoResume = false;
- ConfirmOverwrite(FileNameOnly, OverwriteMode, OperationProgress,
- &FileParams, CopyParam, Params, AutoResume, Answer);
- switch (Answer)
- {
- case qaYes:
- CanProceed = true;
- break;
- case qaCancel:
- OperationProgress->Cancel = csCancel; // continue on next case
- // FALLTHROUGH
- case qaNo:
- CanProceed = false;
- break;
- default:
- break;
- }
- }
- }
- else
- {
- CanProceed = true;
- }
- }
- else
- {
- CanProceed = true;
- }
- if (CanProceed)
- {
- Action.FileName(ExpandUNCFileName(FileName));
- OperationProgress->SetFile(FileName, false);
- if (!FTerminal->AllowLocalFileTransfer(FileName, CopyParam))
- {
- FTerminal->LogEvent(FORMAT(L"File \"%s\" excluded from transfer", (FileName.c_str())));
- THROW_SKIP_FILE_NULL;
- }
- __int64 Size;
- int Attrs;
- FTerminal->OpenLocalFile(FileName, GENERIC_READ, &Attrs,
- NULL, NULL, NULL, NULL, &Size);
- OperationProgress->SetFileInProgress();
- bool Dir = FLAGSET(Attrs, faDirectory);
- if (Dir)
- {
- Action.Cancel();
- WebDAVDirectorySource(IncludeTrailingBackslash(FileName), TargetDir,
- Attrs, CopyParam, Params, OperationProgress, Flags);
- }
- else
- {
- UnicodeString DestFileName = CopyParam->ChangeFileName(ExtractFileName(FileName, false),
- osLocal, FLAGSET(Flags, tfFirstLevel));
- FTerminal->LogEvent(FORMAT(L"Copying \"%s\" to remote directory started.", (FileName.c_str())));
- OperationProgress->SetLocalSize(Size);
- // Suppose same data size to transfer as to read
- // (not true with ASCII transfer)
- OperationProgress->SetTransferSize(OperationProgress->LocalSize);
- OperationProgress->TransferingFile = false;
- // Will we use ASCII of BINARY file transfer?
- TFileMasks::TParams MaskParams;
- MaskParams.Size = Size;
- ResetFileTransfer();
- TFileTransferData UserData;
- {
- unsigned int TransferType = 2;
- // ignore file list
- TWebDAVFileListHelper Helper(this, NULL, true);
- FFileTransferCPSLimit = OperationProgress->CPSLimit;
- // not used for uploads anyway
- FFileTransferPreserveTime = CopyParam->PreserveTime;
- // not used for uploads, but we get new name (if any) back in this field
- UserData.FileName = DestFileName;
- UserData.Params = Params;
- UserData.AutoResume = FLAGSET(Flags, tfAutoResume);
- UserData.CopyParam = CopyParam;
- FileTransfer(FileName, FileName, DestFileName,
- TargetDir, false, Size, TransferType, UserData, OperationProgress);
- }
- UnicodeString DestFullName = TargetDir + UserData.FileName;
- // only now, we know the final destination
- Action.Destination(DestFullName);
- }
- // TODO : Delete also read-only files.
- if (FLAGSET(Params, cpDelete))
- {
- if (!Dir)
- {
- FILE_OPERATION_LOOP (FMTLOAD(DELETE_LOCAL_FILE_ERROR, (FileName.c_str())),
- THROWOSIFFALSE(::DeleteFile(FileName.c_str()));
- )
- }
- }
- else if (CopyParam->ClearArchive && FLAGSET(Attrs, faArchive))
- {
- FILE_OPERATION_LOOP (FMTLOAD(CANT_SET_ATTRS, (FileName.c_str())),
- THROWOSIFFALSE(FileSetAttr(FileName, Attrs & ~faArchive) == 0);
- )
- }
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::WebDAVDirectorySource(const UnicodeString DirectoryName,
- const UnicodeString TargetDir, int Attrs, const TCopyParamType * CopyParam,
- int Params, TFileOperationProgressType * OperationProgress, unsigned int Flags)
- {
- UnicodeString DestDirectoryName = CopyParam->ChangeFileName(
- ExtractFileName(ExcludeTrailingBackslash(DirectoryName), false), osLocal,
- FLAGSET(Flags, tfFirstLevel));
- UnicodeString DestFullName = UnixIncludeTrailingBackslash(TargetDir + DestDirectoryName);
- // create DestFullName if it does not exist
- int IsDir = 0;
- bool Exists = WebDAVCheckExisting(DestFullName.c_str(), IsDir);
- if (!Exists)
- {
- CreateDirectory(DestFullName);
- }
- OperationProgress->SetFile(DirectoryName);
- WIN32_FIND_DATA SearchRec;
- bool FindOK = false;
- HANDLE findHandle = 0;
- FILE_OPERATION_LOOP (FMTLOAD(LIST_DIR_ERROR, (DirectoryName.c_str())),
- UnicodeString path = DirectoryName + L"*.*";
- findHandle = FindFirstFile(path.c_str(), &SearchRec);
- FindOK = (findHandle != 0);
- if (!FindOK)
- {
- FindCheck(GetLastError());
- }
- );
- bool CreateDir = true;
- try
- {
- while (FindOK && !OperationProgress->Cancel)
- {
- UnicodeString FileName = DirectoryName + SearchRec.cFileName;
- try
- {
- if ((wcscmp(SearchRec.cFileName, THISDIRECTORY) != 0) && (wcscmp(SearchRec.cFileName, PARENTDIRECTORY) != 0))
- {
- WebDAVSourceRobust(FileName, DestFullName, CopyParam, Params, OperationProgress,
- Flags & ~(tfFirstLevel | tfAutoResume));
- // if any file got uploaded (i.e. there were any file in the
- // directory and at least one was not skipped),
- // do not try to create the directory,
- // as it should be already created by FZAPI during upload
- CreateDir = false;
- }
- }
- catch (EScpSkipFile & E)
- {
- // If ESkipFile occurs, just log it and continue with next file
- SUSPEND_OPERATION (
- // here a message to user was displayed, which was not appropriate
- // when user refused to overwrite the file in subdirectory.
- // hopefully it won't be missing in other situations.
- if (!FTerminal->HandleException(&E))
- {
- throw;
- }
- );
- }
- FILE_OPERATION_LOOP (FMTLOAD(LIST_DIR_ERROR, (DirectoryName.c_str())),
- FindOK = (::FindNextFile(findHandle, &SearchRec) != 0);
- if (!FindOK)
- {
- FindCheck(GetLastError());
- }
- );
- }
- }
- __finally
- {
- ::FindClose(findHandle);
- }
- if (CreateDir)
- {
- TRemoteProperties Properties;
- if (CopyParam->PreserveRights)
- {
- Properties.Valid = TValidProperties() << vpRights;
- Properties.Rights = CopyParam->RemoteFileRights(Attrs);
- }
- try
- {
- FTerminal->SetExceptionOnFail(true);
- try
- {
- FTerminal->CreateDirectory(DestFullName, &Properties);
- }
- __finally
- {
- FTerminal->SetExceptionOnFail(false);
- }
- }
- catch (...)
- {
- TRemoteFile * File = NULL;
- // ignore non-fatal error when the directory already exists
- UnicodeString fn = UnixExcludeTrailingBackslash(DestFullName);
- if (fn.IsEmpty())
- {
- fn = L"/";
- }
- bool Rethrow =
- !FTerminal->GetActive() ||
- !FTerminal->FileExists(fn, &File) ||
- (File && !File->IsDirectory);
- delete File;
- if (Rethrow)
- {
- throw;
- }
- }
- }
- // TODO : Delete also read-only directories.
- // TODO : Show error message on failure.
- if (!OperationProgress->Cancel)
- {
- if (FLAGSET(Params, cpDelete))
- {
- RemoveDir(DirectoryName);
- }
- else if (CopyParam->ClearArchive && FLAGSET(Attrs, faArchive))
- {
- FILE_OPERATION_LOOP (FMTLOAD(CANT_SET_ATTRS, (DirectoryName.c_str())),
- THROWOSIFFALSE(FileSetAttr(DirectoryName, Attrs & ~faArchive) == 0);
- )
- }
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::CopyToLocal(TStrings * FilesToCopy,
- const UnicodeString TargetDir, const TCopyParamType * CopyParam,
- int Params, TFileOperationProgressType * OperationProgress,
- TOnceDoneOperation & OnceDoneOperation)
- {
- Params &= ~cpAppend;
- UnicodeString FullTargetDir = ::IncludeTrailingBackslash(TargetDir);
- int Index = 0;
- while (Index < FilesToCopy->Count && !OperationProgress->Cancel)
- {
- UnicodeString FileName = FilesToCopy->Strings[Index];
- const TRemoteFile * File = dynamic_cast<const TRemoteFile *>(FilesToCopy->Objects[Index]);
- bool Success = false;
- FTerminal->SetExceptionOnFail(true);
- try
- {
- try
- {
- SinkRobust(AbsolutePath(FileName, false), File, FullTargetDir, CopyParam, Params,
- OperationProgress, tfFirstLevel);
- Success = true;
- }
- catch (EScpSkipFile & E)
- {
- SUSPEND_OPERATION (
- if (!FTerminal->HandleException(&E))
- {
- throw;
- }
- );
- }
- }
- __finally
- {
- OperationProgress->Finish(FileName, Success, OnceDoneOperation);
- FTerminal->SetExceptionOnFail(false);
- }
- Index++;
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::SinkRobust(const UnicodeString FileName,
- const TRemoteFile * File, const UnicodeString TargetDir,
- const TCopyParamType * CopyParam, int Params,
- TFileOperationProgressType * OperationProgress, unsigned int Flags)
- {
- // the same in TSFTPFileSystem
- bool Retry;
- TDownloadSessionAction Action(FTerminal->ActionLog);
- do
- {
- Retry = false;
- try
- {
- Sink(FileName, File, TargetDir, CopyParam, Params, OperationProgress,
- Flags, Action);
- }
- catch (Exception & E)
- {
- Retry = true;
- if (FTerminal->GetActive() ||
- !FTerminal->QueryReopen(&E, ropNoReadDirectory, OperationProgress))
- {
- FTerminal->RollbackAction(Action, OperationProgress, &E);
- throw;
- }
- }
- if (Retry)
- {
- OperationProgress->RollbackTransfer();
- Action.Restart();
- assert(File != NULL);
- if (!File->IsDirectory)
- {
- // prevent overwrite confirmations
- Params |= cpNoConfirmation;
- Flags |= tfAutoResume;
- }
- }
- }
- while (Retry);
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::Sink(const UnicodeString FileName,
- const TRemoteFile * File, const UnicodeString TargetDir,
- const TCopyParamType * CopyParam, int Params,
- TFileOperationProgressType * OperationProgress, unsigned int Flags,
- TDownloadSessionAction & Action)
- {
- UnicodeString FileNameOnly = UnixExtractFileName(FileName);
- Action.FileName(FileName);
- assert(File);
- TFileMasks::TParams MaskParams;
- MaskParams.Size = File->Size;
- if (!CopyParam->AllowTransfer(FileName, osRemote, File->IsDirectory, MaskParams))
- {
- FTerminal->LogEvent(FORMAT(L"File \"%s\" excluded from transfer", (FileName.c_str())));
- THROW_SKIP_FILE_NULL;
- }
- FTerminal->LogEvent(FORMAT(L"File: \"%s\"", (FileName.c_str())));
- OperationProgress->SetFile(FileNameOnly);
- UnicodeString DestFileName = CopyParam->ChangeFileName(FileNameOnly,
- osRemote, FLAGSET(Flags, tfFirstLevel));
- UnicodeString DestFullName = TargetDir + DestFileName;
- if (File->IsDirectory)
- {
- bool CanProceed = true;
- if (::DirectoryExists(DestFullName))
- {
- unsigned int Answer = 0;
- UnicodeString Message = FMTLOAD(DIRECTORY_OVERWRITE, (FileNameOnly.c_str()));
- TQueryParams QueryParams(qpNeverAskAgainCheck);
- SUSPEND_OPERATION (
- Answer = FTerminal->ConfirmFileOverwrite(
- FileNameOnly /*not used*/, NULL,
- qaYes | qaNo | qaCancel | qaYesToAll | qaNoToAll,
- &QueryParams, osRemote, CopyParam, Params, OperationProgress, Message);
- );
- switch (Answer)
- {
- case qaCancel:
- OperationProgress->Cancel = csCancel; // continue on next case
- // FALLTHROUGH
- case qaNo:
- CanProceed = false;
- default:
- break;
- }
- }
- if (CanProceed)
- {
- Action.Cancel();
- if (!File->IsSymLink)
- {
- FILE_OPERATION_LOOP (FMTLOAD(NOT_DIRECTORY_ERROR, (DestFullName.c_str())),
- int Attrs = FileGetAttr(DestFullName);
- if (FLAGCLEAR(Attrs, faDirectory)) { EXCEPTION; }
- );
- FILE_OPERATION_LOOP (FMTLOAD(CREATE_DIR_ERROR, (DestFullName.c_str())),
- if (!ForceDirectories(DestFullName)) { RaiseLastOSError(); }
- );
- TSinkFileParams SinkFileParams;
- SinkFileParams.TargetDir = ::IncludeTrailingBackslash(DestFullName);
- SinkFileParams.CopyParam = CopyParam;
- SinkFileParams.Params = Params;
- SinkFileParams.OperationProgress = OperationProgress;
- SinkFileParams.Skipped = false;
- SinkFileParams.Flags = Flags & ~(tfFirstLevel | tfAutoResume);
- FTerminal->ProcessDirectory(FileName, SinkFile, &SinkFileParams);
- // Do not delete directory if some of its files were skip.
- // Throw "skip file" for the directory to avoid attempt to deletion
- // of any parent directory
- if (FLAGSET(Params, cpDelete) && SinkFileParams.Skipped)
- {
- THROW_SKIP_FILE_NULL;
- }
- }
- else
- {
- // file is symlink to directory, currently do nothing, but it should be
- // reported to user
- }
- }
- }
- else
- {
- FTerminal->LogEvent(FORMAT(L"Copying \"%s\" to local directory started.", (FileName.c_str())));
- bool CanProceed = true;
- if (FileExists(DestFullName))
- {
- __int64 Size;
- __int64 MTime;
- FTerminal->OpenLocalFile(DestFullName, GENERIC_READ, NULL,
- NULL, NULL, &MTime, NULL, &Size);
- TOverwriteFileParams FileParams;
- FileParams.SourceSize = File->Size;
- FileParams.SourceTimestamp = File->Modification;
- FileParams.DestSize = Size;
- FileParams.DestTimestamp = UnixToDateTime(MTime,
- FTerminal->SessionData->DSTMode);
- unsigned int Answer = 0;
- TOverwriteMode OverwriteMode = omOverwrite;
- bool AutoResume = false;
- ConfirmOverwrite(DestFullName, OverwriteMode, OperationProgress,
- &FileParams, CopyParam, Params, AutoResume, Answer);
- switch (Answer)
- {
- case qaCancel:
- OperationProgress->Cancel = csCancel; // continue on next case
- // FALLTHROUGH
- case qaNo:
- CanProceed = false;
- default:
- break;
- }
- }
- if (CanProceed)
- {
- // Suppose same data size to transfer as to write
- OperationProgress->SetTransferSize(File->Size);
- OperationProgress->SetLocalSize(OperationProgress->TransferSize);
- int Attrs = -1;
- FILE_OPERATION_LOOP (FMTLOAD(NOT_FILE_ERROR, (DestFullName.c_str())),
- Attrs = FileGetAttr(DestFullName);
- if ((Attrs >= 0) && FLAGSET(Attrs, faDirectory)) { EXCEPTION; }
- );
- OperationProgress->TransferingFile = false; // not set with FTP protocol
- ResetFileTransfer();
- TFileTransferData UserData;
- UnicodeString FilePath = ::UnixExtractFilePath(FileName);
- if (FilePath.IsEmpty())
- {
- FilePath = L"/";
- }
- {
- unsigned int TransferType = 2;
- // ignore file list
- TWebDAVFileListHelper Helper(this, NULL, true);
- FFileTransferCPSLimit = OperationProgress->CPSLimit;
- FFileTransferPreserveTime = CopyParam->PreserveTime;
- UserData.FileName = DestFileName;
- UserData.Params = Params;
- UserData.AutoResume = FLAGSET(Flags, tfAutoResume);
- UserData.CopyParam = CopyParam;
- FileTransfer(FileName, DestFullName, FileNameOnly,
- FilePath, true, File->Size, TransferType, UserData, OperationProgress);
- }
- // in case dest filename is changed from overwrite dialog
- if (DestFileName != UserData.FileName)
- {
- DestFullName = TargetDir + UserData.FileName;
- Attrs = FileGetAttr(DestFullName);
- }
- Action.Destination(ExpandUNCFileName(DestFullName));
- if (Attrs == -1)
- {
- Attrs = faArchive;
- }
- int NewAttrs = CopyParam->LocalFileAttrs(*File->Rights);
- if ((NewAttrs & Attrs) != NewAttrs)
- {
- FILE_OPERATION_LOOP (FMTLOAD(CANT_SET_ATTRS, (DestFullName.c_str())),
- THROWOSIFFALSE(FileSetAttr(DestFullName, Attrs | NewAttrs) == 0);
- );
- }
- // set time
- {
- FILE_OPERATION_LOOP (FMTLOAD(CANT_SET_ATTRS, (DestFullName.c_str())),
- HANDLE Handle;
- Handle = CreateFile(DestFullName.c_str(), GENERIC_WRITE,
- FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
- FILETIME WrTime = DateTimeToFileTime(File->Modification,
- FTerminal->SessionData->DSTMode);
- bool Result = SetFileTime(Handle, &WrTime, &WrTime, &WrTime) > 0;
- CloseHandle(Handle);
- if (!Result)
- {
- Abort();
- }
- );
- }
- }
- }
- if (FLAGSET(Params, cpDelete))
- {
- // If file is directory, do not delete it recursively, because it should be
- // empty already. If not, it should not be deleted (some files were
- // skipped or some new files were copied to it, while we were downloading)
- int Params = dfNoRecursive;
- FTerminal->DeleteFile(FileName, File, &Params);
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::SinkFile(const UnicodeString FileName,
- const TRemoteFile * File, void * Param)
- {
- TSinkFileParams * Params = static_cast<TSinkFileParams *>(Param);
- assert(Params->OperationProgress);
- try
- {
- SinkRobust(FileName, File, Params->TargetDir, Params->CopyParam,
- Params->Params, Params->OperationProgress, Params->Flags);
- }
- catch (EScpSkipFile & E)
- {
- TFileOperationProgressType * OperationProgress = Params->OperationProgress;
- Params->Skipped = true;
- SUSPEND_OPERATION (
- if (!FTerminal->HandleException(&E))
- {
- throw;
- }
- );
- if (OperationProgress->Cancel)
- {
- Abort();
- }
- }
- }
- //---------------------------------------------------------------------------
- bool __fastcall TWebDAVFileSystem::HandleListData(const wchar_t * Path,
- const TListDataEntry * Entries, unsigned int Count)
- {
- if (!FActive)
- {
- return false;
- }
- else if (FIgnoreFileList)
- {
- // directory listing provided implicitly by FZAPI during certain operations is ignored
- assert(FFileList == NULL);
- return false;
- }
- else
- {
- assert(FFileList != NULL);
- // this can actually fail in real life,
- // when connected to server with case insensitive paths
- assert(UnixComparePaths(AbsolutePath(FFileList->Directory, false), Path));
- USEDPARAM(Path);
- for (size_t Index = 0; Index < Count; Index++)
- {
- const TListDataEntry * Entry = &Entries[Index];
- TRemoteFile * File = new TRemoteFile();
- try
- {
- File->Terminal = FTerminal;
- File->FileName = UnicodeString(Entry->Name);
- if (wcslen(Entry->Permissions) >= 10)
- {
- try
- {
- File->Rights->Text = Entry->Permissions + 1;
- }
- catch (...)
- {
- // ignore permissions errors with WebDAV
- }
- }
- // FIXME
- UnicodeString own = Entry->OwnerGroup;
- const wchar_t * Space = wcschr(own.c_str(), ' ');
- if (Space != NULL)
- {
- File->Owner.Name = UnicodeString(own.c_str(), Space - own.c_str());
- File->Group.Name = Space + 1;
- }
- else
- {
- File->Owner.Name = Entry->OwnerGroup;
- }
- File->Size = Entry->Size;
- if (Entry->Link)
- {
- File->Type = FILETYPE_SYMLINK;
- }
- else if (Entry->Dir)
- {
- File->Type = FILETYPE_DIRECTORY;
- }
- else
- {
- File->Type = L'-';
- }
- // ModificationFmt must be set after Modification
- if (Entry->Time.HasDate)
- {
- // should be the same as ConvertRemoteTimestamp
- TDateTime Modification =
- EncodeDateVerbose(static_cast<unsigned short>(Entry->Time.Year), static_cast<unsigned short>(Entry->Time.Month),
- static_cast<unsigned short>(Entry->Time.Day));
- if (Entry->Time.HasTime)
- {
- unsigned short seconds = 0;
- if (Entry->Time.HasSeconds)
- seconds = static_cast<unsigned short>(Entry->Time.Second);
- File->Modification = Modification +
- EncodeTimeVerbose(static_cast<unsigned short>(Entry->Time.Hour),
- static_cast<unsigned short>(Entry->Time.Minute),
- seconds, 0);
- // not exact as we got year as well, but it is most probably
- // guessed by FZAPI anyway
- File->ModificationFmt = mfMDHM;
- }
- else
- {
- File->Modification = Modification;
- File->ModificationFmt = mfMDY;
- }
- }
- else
- {
- // We estimate date to be today, if we have at least time
- File->Modification = TDateTime(0.0);
- File->ModificationFmt = mfNone;
- }
- File->LastAccess = File->Modification;
- File->LinkTo = Entry->LinkTarget;
- File->Complete();
- }
- catch (Exception & E)
- {
- delete File;
- UnicodeString EntryData =
- FORMAT(L"%s/%s/%s/%lld/%d/%d/%d/%d/%d/%d/%d/%d/%d",
- (Entry->Name,
- Entry->Permissions,
- Entry->OwnerGroup,
- Entry->Size,
- int(Entry->Dir), int(Entry->Link), Entry->Time.Year, Entry->Time.Month, Entry->Time.Day,
- Entry->Time.Hour, Entry->Time.Minute, int(Entry->Time.HasTime), int(Entry->Time.HasDate)));
- throw ETerminal(&E, FMTLOAD(LIST_LINE_ERROR, (EntryData.c_str())), HELP_LIST_LINE_ERROR);
- }
- FFileList->AddFile(File);
- }
- return true;
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::ResetFileTransfer()
- {
- FFileTransferAbort = ftaNone;
- FFileTransferCancelled = false;
- FFileTransferResumed = 0;
- webdav::cancelled = FALSE;
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::ReadDirectoryProgress(__int64 Bytes)
- {
- // with WebDAV we do not know exactly how many entries we have received,
- // instead we know number of bytes received only.
- // so we report approximation based on average size of entry.
- size_t Progress = static_cast<size_t>(Bytes / 80);
- if (Progress - FLastReadDirectoryProgress >= 10)
- {
- bool Cancel = false;
- FLastReadDirectoryProgress = Progress;
- FTerminal->DoReadDirectoryProgress(Progress, Cancel);
- if (Cancel)
- {
- FTerminal->DoReadDirectoryProgress(-2, Cancel);
- }
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::DoFileTransferProgress(__int64 TransferSize,
- __int64 Bytes)
- {
- TFileOperationProgressType * OperationProgress = FTerminal->OperationProgress;
- if (!OperationProgress) return;
- OperationProgress->SetTransferSize(TransferSize);
- if (FFileTransferResumed > 0)
- {
- OperationProgress->AddResumed(FFileTransferResumed);
- FFileTransferResumed = 0;
- }
- __int64 Diff = Bytes - OperationProgress->TransferedSize;
- if (Diff >= 0)
- {
- OperationProgress->AddTransfered(Diff);
- }
- if (OperationProgress->Cancel == csCancel)
- {
- FFileTransferCancelled = true;
- FFileTransferAbort = ftaCancel;
- }
- if (FFileTransferCPSLimit != OperationProgress->CPSLimit)
- {
- FFileTransferCPSLimit = OperationProgress->CPSLimit;
- }
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::FileTransferProgress(__int64 TransferSize,
- __int64 Bytes)
- {
- TGuard Guard(FTransferStatusCriticalSection);
- DoFileTransferProgress(TransferSize, Bytes);
- }
- //---------------------------------------------------------------------------
- void __fastcall TWebDAVFileSystem::FileTransfer(const UnicodeString FileName,
- const UnicodeString LocalFile, const UnicodeString RemoteFile,
- const UnicodeString RemotePath, bool Get, __int64 Size, int Type,
- TFileTransferData & UserData, TFileOperationProgressType * OperationProgress)
- {
- FCurrentOperationProgress = OperationProgress;
- FILE_OPERATION_LOOP (FMTLOAD(TRANSFER_ERROR, (FileName.c_str())),
- UnicodeString FullRemoteFileName = RemotePath + RemoteFile;
- bool Result = false;
- if (Get)
- {
- HANDLE LocalFileHandle = 0;
- FTerminal->CreateLocalFile(LocalFile,
- OperationProgress, &LocalFileHandle, true);
- Result = WebDAVGetFile(FullRemoteFileName.c_str(), &LocalFileHandle);
- if (!Result)
- {
- ::CloseHandle(LocalFileHandle);
- }
- }
- else
- {
- Result = WebDAVPutFile(FullRemoteFileName.c_str(), LocalFile.c_str(), Size);
- }
- if (!Result)
- EXCEPTION;
- );
- switch (FFileTransferAbort)
- {
- case ftaSkip:
- THROW_SKIP_FILE(NULL, L"");
- case ftaCancel:
- Abort();
- break;
- }
- if (!FFileTransferCancelled)
- {
- // show completion of transfer
- // call non-guarded variant to avoid deadlock with keepalives
- // (we are not waiting for reply anymore so keepalives are free to proceed)
- DoFileTransferProgress(OperationProgress->TransferSize, OperationProgress->TransferSize);
- }
- }
- bool TWebDAVFileSystem::SendPropFindRequest(const wchar_t * path, int & responseCode)
- {
- assert(path);
- assert(FSession);
- apr_pool_t * pool = webdav_pool_create(webdav_pool);
- webdav::error_t err = 0;
- const char * remote_path = NULL;
- err = webdav::path_cstring_to_utf8(&remote_path, AnsiString(path).c_str(), pool);
- if (err) return false;
- err = webdav::client_send_propfind_request(
- FSession,
- remote_path,
- &responseCode,
- pool
- );
- webdav_pool_destroy(pool);
- return err == WEBDAV_NO_ERROR;
- }
- bool TWebDAVFileSystem::WebDAVCheckExisting(const wchar_t * path, int & is_dir)
- {
- assert(path);
- is_dir = 0;
- assert(FSession);
- apr_pool_t * pool = webdav_pool_create(webdav_pool);
- webdav::error_t err = 0;
- webdav::node_kind_t kind = webdav::node_none;
- const char * remote_path = NULL;
- err = webdav::path_cstring_to_utf8(&remote_path, AnsiString(path).c_str(), pool);
- if (err) return false;
- err = webdav::client_check_path(
- FSession,
- remote_path,
- &kind,
- pool
- );
- if (kind != webdav::node_none)
- is_dir = kind == webdav::node_dir;
- webdav_pool_destroy(pool);
- return (err == WEBDAV_NO_ERROR) && (kind != webdav::node_none);
- }
- bool TWebDAVFileSystem::WebDAVMakeDirectory(const wchar_t * path)
- {
- assert(path);
- assert(FSession);
- apr_pool_t * pool = webdav_pool_create(webdav_pool);
- webdav::error_t err = 0;
- const char * remote_path = NULL;
- err = webdav::path_cstring_to_utf8(&remote_path, AnsiString(path).c_str(), pool);
- if (err) return false;
- err = webdav::client_make_directory(
- FSession,
- remote_path,
- NULL,
- pool
- );
- webdav_pool_destroy(pool);
- return err == WEBDAV_NO_ERROR;
- }
- bool TWebDAVFileSystem::WebDAVGetList(const UnicodeString Directory)
- {
- webdav::listdataentry_vector_t Entries;
- assert(FSession);
- webdav::list_func_baton_t baton = {0};
- baton.verbose = true;
- baton.entries = &Entries;
- baton.session = FSession;
- baton.pool = webdav_pool_create(webdav_pool);
- webdav::error_t err = 0;
- const char * remote_path = NULL;
- err = webdav::path_cstring_to_utf8(&remote_path, AnsiString(Directory).c_str(), baton.pool);
- if (err) return false;
- err = webdav::client_list2(
- FSession,
- remote_path,
- webdav::depth_immediates,
- WEBDAV_DIRENT_ALL,
- webdav::list_func,
- &baton,
- baton.pool
- );
- TListDataEntry * pEntries = !Entries.empty() ? &Entries[0] : NULL;
- HandleListData(Directory.c_str(), pEntries, Entries.size());
- webdav_pool_destroy(baton.pool);
- return err == WEBDAV_NO_ERROR;
- }
- bool TWebDAVFileSystem::WebDAVGetFile(const wchar_t * remotePath,
- HANDLE * LocalFileHandle)
- {
- assert(remotePath && *remotePath);
- assert(LocalFileHandle);
- assert(FSession);
- apr_pool_t * pool = webdav_pool_create(webdav_pool);
- webdav::error_t err = 0;
- const char * remote_path = NULL;
- err = webdav::path_cstring_to_utf8(&remote_path, AnsiString(remotePath).c_str(), pool);
- if (err) return false;
- err = webdav::client_get_file(
- FSession,
- remote_path,
- LocalFileHandle,
- pool);
- webdav_pool_destroy(pool);
- return err == WEBDAV_NO_ERROR;
- }
- bool TWebDAVFileSystem::WebDAVPutFile(const wchar_t * remotePath, const wchar_t * localPath, const unsigned __int64 /*fileSize*/)
- {
- assert(remotePath && *remotePath);
- assert(localPath && *localPath);
- assert(FSession);
- apr_pool_t * pool = webdav_pool_create(webdav_pool);
- webdav::error_t err = 0;
- const char * remote_path = NULL;
- const char * local_path = NULL;
- err = webdav::path_cstring_to_utf8(&remote_path, AnsiString(remotePath).c_str(), pool);
- if (err) return false;
- err = webdav::path_cstring_to_utf8(&local_path, AnsiString(localPath).c_str(), pool);
- if (err) return false;
- err = webdav::client_put_file(
- FSession,
- remote_path,
- local_path,
- pool
- );
- webdav_pool_destroy(pool);
- return err == WEBDAV_NO_ERROR;
- }
- bool TWebDAVFileSystem::WebDAVRenameFile(const wchar_t * srcPath, const wchar_t * dstPath)
- {
- assert(srcPath && *srcPath);
- assert(dstPath && *dstPath);
- assert(FSession);
- apr_pool_t * pool = webdav_pool_create(webdav_pool);
- webdav::error_t err = 0;
- const char * src_path = NULL;
- const char * dst_path = NULL;
- err = webdav::path_cstring_to_utf8(&src_path, AnsiString(srcPath).c_str(), pool);
- if (err) return false;
- err = webdav::path_cstring_to_utf8(&dst_path, AnsiString(dstPath).c_str(), pool);
- if (err) return false;
- err = webdav::client_move_file_or_directory(
- FSession,
- src_path,
- dst_path,
- NULL,
- pool
- );
- webdav_pool_destroy(pool);
- return err == WEBDAV_NO_ERROR;
- }
- bool TWebDAVFileSystem::WebDAVDeleteFile(const wchar_t * path)
- {
- assert(path);
- assert(FSession);
- apr_pool_t * pool = webdav_pool_create(webdav_pool);
- webdav::error_t err = 0;
- const char * remote_path = NULL;
- err = webdav::path_cstring_to_utf8(&remote_path, AnsiString(path).c_str(), pool);
- if (err) return false;
- err = webdav::client_delete_file(
- FSession,
- remote_path,
- NULL,
- pool
- );
- webdav_pool_destroy(pool);
- return err == WEBDAV_NO_ERROR;
- }
- webdav::error_t TWebDAVFileSystem::OpenURL(const UnicodeString & session_URL,
- apr_pool_t * pool)
- {
- webdav::client_ctx_t * ctx = NULL;
- WEBDAV_ERR(client_create_context(&ctx, pool));
- const char * auth_username = NULL;
- const char * auth_password = NULL;
- WEBDAV_ERR(webdav::utf_cstring_to_utf8(&auth_username,
- AnsiString(FTerminal->SessionData->UserNameExpanded).c_str(), pool));
- WEBDAV_ERR(webdav::utf_cstring_to_utf8(&auth_password,
- AnsiString(FTerminal->SessionData->Password).c_str(), pool));
- webdav::auth_baton_t * ab = NULL;
- webdav::auth_baton_create(&ab, pool);
- webdav::auth_baton_init(ab,
- FALSE, // non_interactive
- auth_username,
- auth_password,
- FALSE, // no_auth_cache
- TRUE, // trust_server_cert
- this,
- webdav::check_cancel, ab,
- pool);
- ctx->auth_baton = ab;
- // Set up our cancellation support.
- ctx->cancel_func = webdav::check_cancel;
- ctx->cancel_baton = ab;
- ctx->progress_func = webdav::progress_func;
- ctx->progress_baton = ctx;
- webdav::session_t * session_p = NULL;
- const char * corrected_url = NULL;
- AnsiString base_url = AnsiString(session_URL).c_str();
- const char * base_url_encoded = webdav::path_uri_encode(base_url.c_str(), pool);
- WEBDAV_ERR(webdav::client_open_session_internal(
- &session_p,
- &corrected_url,
- base_url_encoded,
- ctx,
- pool));
- const char * url = NULL;
- if (corrected_url)
- {
- url = apr_pstrdup(pool, corrected_url);
- }
- else
- {
- url = apr_pstrdup(pool, base_url_encoded);
- }
- ne_uri * uri = NULL;
- if (WEBDAV_NO_ERROR == webdav::parse_ne_uri(&uri, url, pool))
- {
- FCurrentDirectory = uri->path;
- FHasTrailingSlash = (FCurrentDirectory.Length() > 0) && (FCurrentDirectory[FCurrentDirectory.Length()] == L'/');
- }
- FSession = session_p;
- return WEBDAV_NO_ERROR;
- }
- //---------------------------------------------------------------------------
- webdav::error_t TWebDAVFileSystem::GetServerSettings(
- int * proxy_method,
- const char ** proxy_host,
- unsigned int * proxy_port,
- const char ** proxy_username,
- const char ** proxy_password,
- int * timeout_seconds,
- int * neon_debug,
- const char ** neon_debug_file_name,
- bool * compression,
- const char ** pk11_provider,
- const char ** ssl_authority_file,
- apr_pool_t * pool)
- {
- // If we find nothing, default to nulls.
- *proxy_method = 0;
- *proxy_host = NULL;
- *proxy_port = (unsigned int)-1;
- *proxy_username = NULL;
- *proxy_password = NULL;
- *pk11_provider = NULL;
- *ssl_authority_file = NULL;
- TSessionData * Data = FTerminal->SessionData;
- TConfiguration * Configuration = FTerminal->Configuration;
- {
- TProxyMethod ProxyMethod = Data->ProxyMethod;
- *proxy_method = (int)ProxyMethod;
- if (ProxyMethod != (TProxyMethod)::pmNone)
- {
- WEBDAV_ERR(webdav::path_cstring_to_utf8(proxy_host, AnsiString(Data->ProxyHost).c_str(), pool));
- WEBDAV_ERR(webdav::path_cstring_to_utf8(proxy_username, AnsiString(Data->ProxyUsername).c_str(), pool));
- WEBDAV_ERR(webdav::path_cstring_to_utf8(proxy_password, AnsiString(Data->ProxyPassword).c_str(), pool));
- }
- }
- // Apply non-proxy-specific settings regardless of exceptions:
- if (compression)
- *compression = Data->Compression;
- int l_debug = Configuration->ActualLogProtocol >= 1 ? 1 : 0;
- *pk11_provider = "";
- *ssl_authority_file = apr_pstrdup(pool, AnsiString(Data->PublicKeyFile).c_str());
- {
- int l_proxy_port = Data->ProxyPort;
- if (l_proxy_port < 0)
- {
- return webdav::error_create(WEBDAV_ERR_ILLEGAL_URL, NULL,
- "Invalid URL: negative proxy port number");
- }
- if (l_proxy_port > 65535)
- {
- return webdav::error_create(WEBDAV_ERR_ILLEGAL_URL, NULL,
- "Invalid URL: proxy port number greater "
- "than maximum TCP port number 65535");
- }
- *proxy_port = l_proxy_port;
- }
- {
- int l_timeout = Data->Timeout;
- if (l_timeout < 0)
- return webdav::error_create(WEBDAV_ERR_BAD_CONFIG_VALUE, NULL,
- "Invalid config: negative timeout value");
- *timeout_seconds = l_timeout;
- }
- if (l_debug)
- {
- *neon_debug = l_debug;
- if (Configuration->LogToFile)
- {
- WEBDAV_ERR(webdav::path_cstring_to_utf8(neon_debug_file_name,
- AnsiString(GetExpandedLogFileName(
- Configuration->LogFileName,
- Data)).c_str(), pool));
- }
- else
- {
- *neon_debug_file_name = NULL;
- }
- }
- else
- {
- *neon_debug = 0;
- *neon_debug_file_name = NULL;
- }
- return WEBDAV_NO_ERROR;
- }
- webdav::error_t TWebDAVFileSystem::VerifyCertificate(
- const char * Prompt, const char * fingerprint,
- unsigned int & RequestResult)
- {
- RequestResult = 0;
- TClipboardHandler ClipboardHandler;
- ClipboardHandler.Text = fingerprint;
- TQueryButtonAlias Aliases[1];
- Aliases[0].Button = qaRetry;
- Aliases[0].Alias = LoadStr(COPY_KEY_BUTTON);
- Aliases[0].OnClick = &ClipboardHandler.Copy;
- TQueryParams Params;
- Params.HelpKeyword = HELP_VERIFY_CERTIFICATE;
- Params.NoBatchAnswers = qaYes | qaRetry;
- Params.Aliases = Aliases;
- Params.AliasesCount = LENOF(Aliases);
- unsigned int Answer = FTerminal->QueryUser(
- FMTLOAD(VERIFY_CERT_PROMPT2, (UnicodeString(Prompt).c_str())),
- NULL, qaYes | qaNo | qaCancel | qaRetry, &Params, qtWarning);
- RequestResult = Answer;
- switch (RequestResult)
- {
- case qaCancel:
- FFileTransferCancelled = true;
- FFileTransferAbort = ftaCancel;
- break;
- }
- return WEBDAV_NO_ERROR;
- }
- webdav::error_t TWebDAVFileSystem::AskForClientCertificateFilename(
- const char ** cert_file, unsigned int & RequestResult,
- apr_pool_t * pool)
- {
- RequestResult = 0;
- TSessionData * Data = FTerminal->SessionData;
- UnicodeString FileName;
- if (!FTerminal->PromptUser(Data, pkFileName, LoadStr(CERT_FILENAME_PROMPT_TITLE), L"",
- LoadStr(CERT_FILENAME_PROMPT), true, 0, FileName))
- {
- FFileTransferCancelled = true;
- FFileTransferAbort = ftaCancel;
- return WEBDAV_ERR_CANCELLED;
- }
- WEBDAV_ERR(webdav::path_cstring_to_utf8(cert_file, AnsiString(FileName).c_str(), pool));
- RequestResult = qaOK;
- return WEBDAV_NO_ERROR;
- }
- webdav::error_t TWebDAVFileSystem::AskForUsername(
- const char ** user_name, unsigned int & RequestResult,
- apr_pool_t * pool)
- {
- RequestResult = 0;
- TSessionData * Data = FTerminal->SessionData;
- UnicodeString UserName = Data->UserNameExpanded;
- if (!FTerminal->PromptUser(Data, pkUserName, LoadStr(USERNAME_TITLE), L"",
- LoadStr(USERNAME_PROMPT2), true, 0, UserName))
- {
- FFileTransferCancelled = true;
- FFileTransferAbort = ftaCancel;
- return WEBDAV_ERR_CANCELLED;
- }
- WEBDAV_ERR(webdav::path_cstring_to_utf8(user_name, AnsiString(UserName).c_str(), pool));
- RequestResult = qaOK;
- return WEBDAV_NO_ERROR;
- }
- webdav::error_t TWebDAVFileSystem::AskForUserPassword(
- const char ** password,
- unsigned int & RequestResult,
- apr_pool_t * pool)
- {
- RequestResult = 0;
- TSessionData * Data = FTerminal->SessionData;
- UnicodeString Password = Data->Password;
- if (!FTerminal->PromptUser(Data, pkPassword, LoadStr(PASSWORD_TITLE), L"",
- LoadStr(PASSWORD_PROMPT), false, 0, Password))
- {
- FFileTransferCancelled = true;
- FFileTransferAbort = ftaCancel;
- return WEBDAV_ERR_CANCELLED;
- }
- WEBDAV_ERR(webdav::path_cstring_to_utf8(password, AnsiString(Password).c_str(), pool));
- RequestResult = qaOK;
- return WEBDAV_NO_ERROR;
- }
- //------------------------------------------------------------------------------
- webdav::error_t TWebDAVFileSystem::AskForPassphrase(
- const char ** passphrase,
- const char * realm,
- unsigned int & RequestResult,
- apr_pool_t * pool)
- {
- RequestResult = 0;
- TSessionData * Data = FTerminal->SessionData;
- UnicodeString Passphrase = Data->UserNameExpanded;
- UnicodeString Prompt = FORMAT(LoadStr(PROMPT_KEY_PASSPHRASE), (UnicodeString(realm)));
- if (!FTerminal->PromptUser(Data, pkPassphrase, LoadStr(PASSPHRASE_TITLE), L"",
- Prompt, false, 0, Passphrase))
- {
- FFileTransferCancelled = true;
- FFileTransferAbort = ftaCancel;
- return WEBDAV_ERR_CANCELLED;
- }
- WEBDAV_ERR(webdav::path_cstring_to_utf8(passphrase, AnsiString(Passphrase).c_str(), pool));
- RequestResult = qaOK;
- return WEBDAV_NO_ERROR;
- }
- webdav::error_t TWebDAVFileSystem::SimplePrompt(
- const char * prompt_text,
- const char * prompt_string,
- unsigned int & RequestResult)
- {
- RequestResult = 0;
- TStrings * MoreMessages = new TStringList();
- try
- {
- MoreMessages->Add(UnicodeString(prompt_string));
- unsigned int Answer = FTerminal->QueryUser(
- UnicodeString(prompt_text),
- MoreMessages, qaYes | qaNo | qaCancel, NULL, qtConfirmation);
- RequestResult = Answer;
- }
- __finally
- {
- delete MoreMessages;
- }
- return RequestResult == qaCancel ? WEBDAV_ERR_CANCELLED : WEBDAV_NO_ERROR;
- }
- webdav::error_t TWebDAVFileSystem::CreateStorage(
- THierarchicalStorage *& Storage)
- {
- Storage =
- FTerminal->Configuration->CreateScpStorage(false);
- return WEBDAV_NO_ERROR;
- }
- unsigned long TWebDAVFileSystem::AdjustToCPSLimit(unsigned long len)
- {
- return FCurrentOperationProgress ? FCurrentOperationProgress->AdjustToCPSLimit(len) : len;
- }
- bool TWebDAVFileSystem::GetIsCancelled()
- {
- TFileOperationProgressType * OperationProgress = FCurrentOperationProgress;
- return (OperationProgress && OperationProgress->Cancel == csCancel);
- }
- //------------------------------------------------------------------------------
|