WebDAVFileSystem.cpp 400 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230
  1. //---------------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include <malloc.h>
  5. #include <stdio.h>
  6. #include <wincrypt.h>
  7. #include <apr_hash.h>
  8. #include <apr_strings.h>
  9. #include <apr_tables.h>
  10. #include <apr_file_io.h>
  11. #include <apr_portable.h>
  12. #include <apr_atomic.h>
  13. #include <ne_basic.h>
  14. #include <ne_auth.h>
  15. #include <ne_compress.h>
  16. #include <ne_props.h>
  17. #include <ne_defs.h>
  18. #include <ne_uri.h>
  19. #include <ne_session.h>
  20. #include <ne_request.h>
  21. #include <ne_xml.h>
  22. #include <ne_pkcs11.h>
  23. #include "WebDAVFileSystem.h"
  24. #include "Interface.h"
  25. #include "Common.h"
  26. #include "Exceptions.h"
  27. #include "Terminal.h"
  28. #include "TextsCore.h"
  29. #include "SecureShell.h"
  30. #include "FileZillaIntf.h"
  31. #include "HelpCore.h"
  32. //---------------------------------------------------------------------------
  33. #pragma package(smart_init)
  34. //---------------------------------------------------------------------------
  35. const int tfFirstLevel = 0x01;
  36. const int tfAutoResume = 0x02;
  37. //---------------------------------------------------------------------------
  38. struct TSinkFileParams
  39. {
  40. UnicodeString TargetDir;
  41. const TCopyParamType * CopyParam;
  42. int Params;
  43. TFileOperationProgressType * OperationProgress;
  44. bool Skipped;
  45. unsigned int Flags;
  46. };
  47. //---------------------------------------------------------------------------
  48. struct TFileTransferData
  49. {
  50. TFileTransferData()
  51. {
  52. Params = 0;
  53. AutoResume = false;
  54. OverwriteResult = -1;
  55. CopyParam = NULL;
  56. }
  57. UnicodeString FileName;
  58. int Params;
  59. bool AutoResume;
  60. int OverwriteResult;
  61. const TCopyParamType * CopyParam;
  62. };
  63. //---------------------------------------------------------------------------
  64. struct TClipboardHandler
  65. {
  66. UnicodeString Text;
  67. void __fastcall Copy(TObject * /*Sender*/)
  68. {
  69. TInstantOperationVisualizer Visualizer;
  70. CopyToClipboard(Text);
  71. }
  72. };
  73. //---------------------------------------------------------------------------
  74. namespace webdav {
  75. #pragma warn -8004
  76. const AnsiString __cdecl Format(const char * format, va_list args)
  77. {
  78. int len = AnsiString().vprintf(format, args);
  79. AnsiString Result;
  80. Result.SetLength(len + 1);
  81. vsprintf(&Result[1], format, args);
  82. return Result.c_str();
  83. }
  84. const AnsiString __cdecl Format(const char * format, ...)
  85. {
  86. va_list args;
  87. va_start(args, format);
  88. AnsiString Result = Format(format, args);
  89. va_end(args);
  90. return Result;
  91. }
  92. //---------------------------------------------------------------------------
  93. struct auth_baton_t;
  94. struct vtable_t;
  95. struct stream_t;
  96. struct client_ctx_t;
  97. struct auth_iterstate_t;
  98. //---------------------------------------------------------------------------
  99. typedef enum tristate_t
  100. {
  101. tristate_false = 2,
  102. tristate_true,
  103. tristate_unknown
  104. } tristate_t;
  105. //------------------------------------------------------------------------------
  106. // Userdata for the `proxy_auth' function.
  107. struct proxy_auth_baton_t
  108. {
  109. const char * username; // Cannot be NULL, but "" is okay.
  110. const char * password; // Cannot be NULL, but "" is okay.
  111. };
  112. //------------------------------------------------------------------------------
  113. // from svn_types.h
  114. typedef error_t (*cancel_func_t)(void * cancel_baton);
  115. //------------------------------------------------------------------------------
  116. // from svn_ra.h
  117. typedef void (*progress_notify_func_t)(
  118. apr_off_t progress,
  119. apr_off_t total,
  120. void * baton,
  121. apr_pool_t * pool);
  122. typedef error_t (*get_client_string_func_t)(void * baton,
  123. const char ** name,
  124. apr_pool_t * pool);
  125. typedef struct callbacks2_t
  126. {
  127. auth_baton_t * auth_baton;
  128. progress_notify_func_t progress_func;
  129. void * progress_baton;
  130. cancel_func_t cancel_func;
  131. get_client_string_func_t get_client_string;
  132. } callbacks2_t;
  133. typedef struct callback_baton_t
  134. {
  135. client_ctx_t * ctx;
  136. apr_pool_t * pool;
  137. } callback_baton_t;
  138. //------------------------------------------------------------------------------
  139. // from ra_loader.h
  140. typedef error_t (*init_func_t)(const vtable_t ** vtable,
  141. apr_pool_t * pool);
  142. //------------------------------------------------------------------------------
  143. // from svn_string.h
  144. // A simple counted string.
  145. typedef struct string_t
  146. {
  147. const char * data; //< pointer to the bytestring
  148. apr_size_t len; //< length of bytestring
  149. } string_t;
  150. // A buffered string, capable of appending without an allocation and copy
  151. // for each append.
  152. typedef struct stringbuf_t
  153. {
  154. apr_pool_t * pool;
  155. char * data;
  156. apr_size_t len;
  157. apr_size_t blocksize;
  158. } stringbuf_t;
  159. //------------------------------------------------------------------------------
  160. // from ra_neon.h
  161. // Rename these types and constants to abstract from Neon
  162. #define NEON_XML_DECLINE NE_XML_DECLINE
  163. #define NEON_XML_INVALID NE_XML_ABORT
  164. #define NEON_XML_CDATA (1<<1)
  165. #define NEON_XML_COLLECT ((1<<2) | NEON_XML_CDATA)
  166. // Related to anonymous enum below?
  167. typedef int neon_xml_elmid;
  168. typedef struct neon_xml_elm_t
  169. {
  170. const char * nspace;
  171. const char * name;
  172. neon_xml_elmid id;
  173. // Processing flags for this namespace:tag.
  174. // 0 (zero) - regular element, may have children,
  175. // NEON_XML_CDATA - child-less element,
  176. // NEON_XML_COLLECT - complete contents of such element must be
  177. // collected as CDATA, includes *_CDATA flag.
  178. unsigned int flags;
  179. } neon_xml_elm_t;
  180. typedef struct neon_session_t
  181. {
  182. apr_pool_t * pool;
  183. stringbuf_t * url; // original, unparsed session url
  184. ne_uri root; // parsed version of above
  185. const char * webdav_root; // URL for WebDAV resource root
  186. ne_session * ne_sess; // HTTP session to server
  187. const callbacks2_t * callbacks; // callbacks to get auth data
  188. void * callback_baton;
  189. auth_iterstate_t * auth_iterstate; // state of authentication retries
  190. bool auth_used; // Save authorization state after
  191. // successful usage
  192. auth_iterstate_t * p11pin_iterstate; // state of PKCS#11 pin retries
  193. bool compression; // should we use http compression?
  194. progress_notify_func_t progress_func;
  195. void * progress_baton;
  196. apr_off_t total_progress; // Total number of bytes sent in this
  197. // session with a -1 total marker
  198. apr_hash_t * capabilities;
  199. } neon_session_t;
  200. typedef struct neon_request_t
  201. {
  202. ne_request * ne_req; // neon request structure
  203. ne_session * ne_sess; // neon session structure
  204. neon_session_t * sess; // DAV session structure
  205. const char * method;
  206. const char * url;
  207. int rv; // Return value from
  208. // ne_request_dispatch() or -1 if
  209. // not dispatched yet.
  210. int code; // HTTP return code, or 0 if none
  211. const char * code_desc; // Textual description of CODE
  212. error_t err; // error encountered while executing
  213. // the request
  214. bool marshalled_error; // TRUE if the error was server-side
  215. apr_pool_t * pool; // where this struct is allocated
  216. apr_pool_t * iterpool; // iteration pool
  217. // for use within callbacks
  218. } neon_request_t;
  219. // Related to neon_xml_elmid?
  220. // add WEBDAV_NEON_ to these to prefix conflicts with (sys) headers?
  221. enum
  222. {
  223. // Redefine Neon elements
  224. // With the new API, we need to be able to use element id also as a return
  225. // value from the new `startelm' callback, hence all element ids must be
  226. // positive. Root element id is the only id that is not positive, it's zero.
  227. // `Root state' is never returned by a callback, it's only passed into it.
  228. // Therefore, negative element ids are forbidden from now on.
  229. ELEM_unknown = 1, // was (-1), see above why it's (1) now
  230. ELEM_root = NE_XML_STATEROOT, // (0)
  231. ELEM_UNUSED = 100,
  232. ELEM_207_first = ELEM_UNUSED,
  233. ELEM_multistatus = ELEM_207_first,
  234. ELEM_response = ELEM_207_first + 1,
  235. ELEM_responsedescription = ELEM_207_first + 2,
  236. ELEM_href = ELEM_207_first + 3,
  237. ELEM_propstat = ELEM_207_first + 4,
  238. ELEM_prop = ELEM_207_first + 5, // `prop' tag in the DAV namespace
  239. ELEM_status = ELEM_207_first + 6,
  240. ELEM_207_UNUSED = ELEM_UNUSED + 100,
  241. ELEM_PROPS_UNUSED = ELEM_207_UNUSED + 100,
  242. // DAV elements
  243. ELEM_collection = ELEM_207_UNUSED,
  244. ELEM_comment,
  245. ELEM_creationdate,
  246. ELEM_creator_displayname,
  247. ELEM_options_response,
  248. ELEM_set_prop,
  249. ELEM_remove_prop,
  250. ELEM_resourcetype,
  251. ELEM_get_content_length,
  252. ELEM_get_last_modified,
  253. ELEM_updated_set,
  254. ELEM_error,
  255. ELEM_human_readable,
  256. };
  257. // The session object.
  258. struct session_t
  259. {
  260. const vtable_t * vtable;
  261. // Pool used to manage this session.
  262. apr_pool_t * pool;
  263. // Private data for the RA implementation.
  264. void * priv;
  265. };
  266. typedef std::vector<TListDataEntry> listdataentry_vector_t;
  267. // Baton used when listing directory entries.
  268. typedef struct list_func_baton_t
  269. {
  270. bool verbose;
  271. listdataentry_vector_t * entries;
  272. session_t * session;
  273. apr_pool_t * pool;
  274. } list_func_baton_t;
  275. //------------------------------------------------------------------------------
  276. // timeout (in seconds)
  277. #define DEFAULT_HTTP_TIMEOUT 10
  278. #define WEBDAV_ERR_DAV_SOCK_INIT 1000
  279. #define WEBDAV_ERR_XML_MALFORMED 1001
  280. #define WEBDAV_ERR_DAV_OPTIONS_REQ_FAILED 1002
  281. #define WEBDAV_ERR_DAV_REQUEST_FAILED 1003
  282. #define WEBDAV_ERR_INCORRECT_PARAMS 1004
  283. #define WEBDAV_ERR_FS_NOT_FOUND 1005
  284. #define WEBDAV_ERR_FS_PROP_BASEVALUE_MISMATCH 1006
  285. #define WEBDAV_ERR_DAV_FORBIDDEN 1010
  286. #define WEBDAV_ERR_DAV_RELOCATED 1011
  287. #define WEBDAV_ERR_NOT_AUTHORIZED 1012
  288. #define WEBDAV_ERR_ILLEGAL_URL 1013
  289. #define WEBDAV_ERR_DAV_NOT_IMPLEMENTED 1014
  290. #define WEBDAV_ERR_NOT_IMPLEMENTED 1015
  291. #define WEBDAV_ERR_AUTHN_NO_PROVIDER 1020
  292. #define WEBDAV_ERR_CLIENT_CYCLE_DETECTED 1021
  293. #define WEBDAV_ERR_DAV_MALFORMED_DATA 1022
  294. #define WEBDAV_ERR_IO_PIPE_WRITE_ERROR 1023
  295. #define WEBDAV_ERR_BAD_DATE 1024
  296. #define WEBDAV_ERR_CLIENT_UNRELATED_RESOURCES 1025
  297. #define WEBDAV_ERR_ROOT_URL_MISMATCH 1027
  298. #define WEBDAV_ERR_BAD_FILENAME 1028
  299. #define WEBDAV_ERR_ENTRY_MISSING_URL 1029
  300. #define WEBDAV_ERR_FS_NOT_FILE 1030
  301. #define WEBDAV_ERR_ATOMIC_INIT_FAILURE 1033
  302. #define WEBDAV_ERR_IO_UNIQUE_NAMES_EXHAUSTED 1034
  303. #define WEBDAV_ERR_STREAM_SEEK_NOT_SUPPORTED 1035
  304. #define WEBDAV_ERR_BAD_CONFIG_VALUE 1040
  305. #define WEBDAV_ERR_CANCELLED 1050
  306. #define WEBDAV_ERR_DAV_INVALID_CONFIG_VALUE 1051
  307. #define WEBDAV_ERR_DAV_PROPPATCH_FAILED 1060
  308. #define WEBDAV_ERR_CANNOT_PUT_FILE 1061
  309. #define WEBDAV_ERR_CANNOT_DELETE_FILE 1062
  310. #define WEBDAV_ERR_CANNOT_MKCOL 1063
  311. #define WEBDAV_ERR_CANNOT_MOVE 1064
  312. #define WEBDAV_ERR_CANNOT_PROPFIND 1065
  313. #define WEBDAV_ERR_BAD_PARAM 1070
  314. // The application doesn't want any providers to save credentials
  315. // to disk. Property value is irrelevant; only property's existence
  316. // matters.
  317. #define AUTH_PARAM_NO_AUTH_CACHE AUTH_PARAM_PREFIX "no-auth-cache"
  318. // #define HASH_KEY_STRING ""
  319. #define MAX_REDIRECT_ATTEMPTS 3 // TODO: Make configurable.
  320. //---------------------------------------------------------------------------
  321. // #define WEBDAV_ARRAY_IDX(ary,i,type) ((type)(ary)[i])
  322. #define WEBDAV_NO_ERROR 0
  323. #define WEBDAV_UNKNOWN_ERROR 1
  324. #define WEBDAV_ERR(expr) \
  325. do { \
  326. webdav::error_t err__temp = (expr); \
  327. if (err__temp) \
  328. return err__temp; \
  329. } while (0)
  330. // A statement macro, very similar to WEBDAV_ERR.
  331. // This macro will wrap the error with the specified text before
  332. // returning the error.
  333. #define WEBDAV_ERR_W(expr, wrap_msg) \
  334. do { \
  335. webdav::error_t err__temp = (expr); \
  336. if (err__temp) \
  337. return webdav::error_create(err__temp, NULL, wrap_msg); \
  338. } while (0)
  339. #define WEBDAV_ERR_ASSERT(expr) \
  340. do { \
  341. if (!(expr)) \
  342. WEBDAV_ERR(WEBDAV_UNKNOWN_ERROR); \
  343. } while (0)
  344. #define error_trace(expr) (expr)
  345. // Create a pool as a subpool of parent_pool
  346. #define webdav_pool_create(parent_pool) webdav::pool_create_ex(parent_pool, NULL)
  347. #define webdav_pool_clear apr_pool_clear
  348. // Destroy a pool and all of its children.
  349. // This define for webdav_pool_destroy exists for symmetry and
  350. // completeness.
  351. #define webdav_pool_destroy apr_pool_destroy
  352. // Destroy request REQ and any associated resources
  353. #define neon_request_destroy(req) webdav_pool_destroy((req)->pool)
  354. // Statement macro to set the request error,
  355. // making sure we don't leak any in case we encounter more than one error.
  356. // Sets the 'err' field of REQ to the value obtained by evaluating NEW_ERR.
  357. #define NEON_REQ_ERR(req, new_err) \
  358. do { \
  359. error_t err__tmp = (new_err); \
  360. if ((req)->err && !(req)->marshalled_error) \
  361. error_clear(&err__tmp); \
  362. else if (err__tmp) \
  363. { \
  364. error_clear(&(req)->err); \
  365. (req)->err = err__tmp; \
  366. (req)->marshalled_error = false; \
  367. } \
  368. } while (0)
  369. //===========================================================================
  370. //------------------------------------------------------------------------------
  371. // from error.c
  372. static void
  373. error_clear(error_t * err)
  374. {
  375. if (err) *err = 0;
  376. }
  377. static error_t
  378. make_error_internal(
  379. apr_status_t apr_err,
  380. error_t * child)
  381. {
  382. error_t new_error = apr_err;
  383. return new_error;
  384. }
  385. static error_t
  386. error_create(
  387. apr_status_t apr_err,
  388. error_t * child,
  389. const char * message)
  390. {
  391. return apr_err;
  392. }
  393. static error_t
  394. error_createf(
  395. apr_status_t apr_err,
  396. error_t * child,
  397. const char * fmt,
  398. ...)
  399. {
  400. va_list args;
  401. va_start(args, fmt);
  402. AnsiString Message = Format(fmt, args);
  403. va_end(args);
  404. AnsiString Message2 = Format("Error, code: %d, message: %s", apr_err, Message.c_str());
  405. throw ExtException(UnicodeString(Message2), NULL);
  406. }
  407. static error_t
  408. error_wrap_apr(
  409. apr_status_t status,
  410. const char * fmt,
  411. ...)
  412. {
  413. error_t err = 0;
  414. va_list args;
  415. err = make_error_internal(status, NULL);
  416. va_start(args, fmt);
  417. AnsiString Message = Format(fmt, args);
  418. va_end(args);
  419. err = error_create(err, NULL, Message.c_str());
  420. return err;
  421. }
  422. //------------------------------------------------------------------------------
  423. // from utils.c
  424. // a cleanup routine attached to the pool that contains the RA session
  425. // root URI.
  426. static apr_status_t
  427. cleanup_uri(void * uri)
  428. {
  429. ne_uri_free(static_cast<ne_uri *>(uri));
  430. return APR_SUCCESS;
  431. }
  432. static error_t
  433. parse_url(
  434. const char * url, ne_uri * uri)
  435. {
  436. if (ne_uri_parse(url, uri) ||
  437. (uri->host == NULL) || (uri->path == NULL) || (uri->scheme == NULL))
  438. {
  439. ne_uri_free(uri);
  440. return 0;
  441. }
  442. if (uri->port == 0)
  443. uri->port = ne_uri_defaultport(uri->scheme);
  444. return 1;
  445. }
  446. static error_t
  447. parse_ne_uri(
  448. ne_uri ** uri,
  449. const char * webdav_url,
  450. apr_pool_t * pool)
  451. {
  452. // Sanity check the URI
  453. *uri = static_cast<ne_uri *>(apr_pcalloc(pool, sizeof(**uri)));
  454. if (!parse_url(webdav_url, *uri))
  455. {
  456. return error_createf(WEBDAV_ERR_ILLEGAL_URL, NULL,
  457. "URL '%s' is malformed or the "
  458. "scheme or host or path is missing", webdav_url);
  459. }
  460. // make sure we eventually destroy the uri
  461. apr_pool_cleanup_register(pool, *uri, cleanup_uri, apr_pool_cleanup_null);
  462. return WEBDAV_NO_ERROR;
  463. }
  464. //------------------------------------------------------------------------------
  465. // from svn_types.h
  466. #define atoui64(X) ((apr_uint64_t) apr_atoi64(X))
  467. // An indication that you are interested in the kind field
  468. #define WEBDAV_DIRENT_KIND 0x00001
  469. // An indication that you are interested in the size field
  470. #define WEBDAV_DIRENT_SIZE 0x00002
  471. // An indication that you are interested in the time field
  472. #define WEBDAV_DIRENT_TIME 0x00010
  473. // A combination of all the dirent fields
  474. #define WEBDAV_DIRENT_ALL ~((apr_uint32_t ) 0)
  475. // The various types of nodes in filesystem.
  476. typedef enum node_kind_t
  477. {
  478. // absent
  479. node_none,
  480. // regular file
  481. node_file,
  482. // directory
  483. node_dir,
  484. // something's here, but we don't know what
  485. node_unknown
  486. } node_kind_t;
  487. // A general directory entry.
  488. typedef struct dirent_t
  489. {
  490. // node kind
  491. node_kind_t kind;
  492. // length of file text, or 0 for directories
  493. apr_int64_t size;
  494. // time of mod-time
  495. apr_time_t time;
  496. } dirent_t;
  497. typedef enum depth_t
  498. {
  499. // Just the named directory D, no entries. Updates will not pull in
  500. // any files or subdirectories not already present.
  501. depth_empty = 0,
  502. // D + its file children, but not subdirs. Updates will pull in any
  503. // files not already present, but not subdirectories.
  504. depth_files = 1,
  505. // D + immediate children (D and its entries). Updates will pull in
  506. // any files or subdirectories not already present; those
  507. // subdirectories' this_dir entries will have depth-empty.
  508. depth_immediates = 2,
  509. // D + all descendants (full recursion from D). Updates will pull
  510. // in any files or subdirectories not already present; those
  511. // subdirectories' this_dir entries will have depth-infinity.
  512. // Equivalent to the pre-1.5 default update behavior.
  513. depth_infinity = 3
  514. } depth_t;
  515. //------------------------------------------------------------------------------
  516. // from utf.h
  517. static error_t
  518. utf_cstring_to_utf8(
  519. const char ** dest,
  520. const char * src,
  521. apr_pool_t * pool);
  522. static error_t
  523. utf_cstring_from_utf8(
  524. const char ** dest,
  525. const char * src,
  526. apr_pool_t * pool);
  527. // Local wrapper of path_cstring_from_utf8() that does no copying on
  528. // operating systems where APR always uses utf-8 as native path format
  529. static error_t
  530. cstring_from_utf8(
  531. const char ** path_apr,
  532. const char * path_utf8,
  533. apr_pool_t * pool);
  534. //------------------------------------------------------------------------------
  535. // from ra_neon.h
  536. #ifdef WEBDAV_DEBUG
  537. #define DEBUG_CR "\n"
  538. #else
  539. #define DEBUG_CR ""
  540. #endif
  541. #define NEON_DEPTH_ZERO 0
  542. #define NEON_DEPTH_ONE 1
  543. #define NEON_DEPTH_INFINITE -1
  544. // NEON_PROP_*: properties that we fetch from the server
  545. // These are simply symbolic names for some standard properties that we fetch.
  546. #define NEON_PROP_CREATIONDATE "DAV:creationdate"
  547. #define NEON_PROP_GETCONTENTLENGTH "DAV:getcontentlength"
  548. typedef struct neon_resource_t
  549. {
  550. // what is the URL for this resource
  551. const char * url;
  552. // is this resource a collection? (from the DAV:resourcetype element)
  553. int is_collection;
  554. // PROPSET: NAME -> VALUE (const char * -> const string_t *)
  555. apr_hash_t * propset;
  556. // --- only used during response processing ---
  557. // when we see a DAV:href element, what element is the parent?
  558. int href_parent;
  559. apr_pool_t * pool;
  560. } neon_resource_t;
  561. // Our equivalent of ne_xml_startelm_cb, the difference being that it
  562. // returns errors in a error_t, and returns the element type via
  563. // ELEM. To ignore the element *ELEM should be set to
  564. // NEON_XML_DECLINE and WEBDAV_NO_ERROR should be returned.
  565. // *ELEM can be set to NEON_XML_INVALID to indicate invalid XML
  566. // (and abort the parse).
  567. typedef error_t (*neon_startelm_cb_t)(int * elem,
  568. void * baton,
  569. int parent,
  570. const char * nspace,
  571. const char * name,
  572. const char ** atts);
  573. // Our equivalent of ne_xml_cdata_cb, the difference being that it returns
  574. // errors in a error_t.
  575. typedef error_t (*neon_cdata_cb_t)(void * baton,
  576. int state,
  577. const char * cdata,
  578. size_t len);
  579. // Our equivalent of ne_xml_endelm_cb, the difference being that it returns
  580. // errors in a error_t.
  581. typedef error_t (*neon_endelm_cb_t)(void * baton,
  582. int state,
  583. const char * nspace,
  584. const char * name);
  585. static ne_xml_parser *
  586. neon_xml_parser_create(
  587. neon_request_t * req,
  588. ne_accept_response accpt,
  589. neon_startelm_cb_t startelm_cb,
  590. neon_cdata_cb_t cdata_cb,
  591. neon_endelm_cb_t endelm_cb,
  592. void * baton);
  593. static error_t
  594. neon_request_dispatch(
  595. int * code_p,
  596. neon_request_t * req,
  597. apr_hash_t * extra_headers,
  598. const char * body,
  599. int okay_1,
  600. int okay_2,
  601. bool check_errors,
  602. apr_pool_t * pool);
  603. static error_t
  604. neon_check_parse_error(
  605. const char * method,
  606. ne_xml_parser * xml_parser,
  607. const char * url);
  608. static error_t
  609. neon_request_create(
  610. neon_request_t ** request,
  611. neon_session_t * sess,
  612. const char * method, const char * url,
  613. apr_pool_t * pool);
  614. static const neon_xml_elm_t *
  615. neon_lookup_xml_elem(
  616. const neon_xml_elm_t * table,
  617. const char * nspace,
  618. const char * name);
  619. static error_t
  620. neon_xml_collect_cdata(
  621. void * baton, int state,
  622. const char * cdata, size_t len);
  623. static const char *
  624. neon_request_get_location(
  625. neon_request_t * request,
  626. apr_pool_t * pool);
  627. // Our version of ne_block_reader, which returns an
  628. // error_t instead of an int.
  629. typedef error_t (*neon_block_reader)(
  630. void * baton,
  631. const char * data,
  632. size_t len);
  633. //------------------------------------------------------------------------------
  634. // from dirent_uri.h
  635. static bool
  636. dirent_is_root(
  637. const char * dirent,
  638. apr_size_t len);
  639. //------------------------------------------------------------------------------
  640. // from svn_props.h
  641. static error_t
  642. neon_get_props_resource(
  643. neon_resource_t ** rsrc,
  644. neon_session_t * sess,
  645. const char * url,
  646. const ne_propname * which_props,
  647. bool check_errors,
  648. apr_pool_t * pool);
  649. //------------------------------------------------------------------------------
  650. // from ra_loader.h
  651. // The RA layer vtable.
  652. typedef struct vtable_t
  653. {
  654. // Return a short description of the RA implementation, as a localized
  655. // string.
  656. const char * (*get_description)(void);
  657. // Return a list of actual URI schemes supported by this implementation.
  658. // The returned array is NULL-terminated.
  659. const char * const * (*get_schemes)(apr_pool_t * pool);
  660. // Implementations of the public API functions.
  661. // See session_open().
  662. // All fields in SESSION, except priv, have been initialized by the
  663. // time this is called. SESSION->priv may be set by this function.
  664. error_t (*open_session)(session_t * session,
  665. const char ** corrected_url,
  666. const char * session_URL,
  667. const callbacks2_t * callbacks,
  668. void * callback_baton,
  669. apr_pool_t * pool);
  670. // See reparent().
  671. // URL is guaranteed to have what get_webdav_resource_root() returns as a prefix.
  672. error_t (*reparent)(session_t * session,
  673. const char * url,
  674. apr_pool_t * pool);
  675. // See get_session_url().
  676. error_t (*get_session_url)(session_t * session,
  677. const char ** url,
  678. apr_pool_t * pool);
  679. // See get_file().
  680. error_t (*get_file)(session_t * session,
  681. const char * path,
  682. stream_t * stream,
  683. apr_hash_t ** props,
  684. apr_pool_t * pool);
  685. // See get_dir2().
  686. error_t (*get_dir)(session_t * session,
  687. apr_hash_t ** dirents,
  688. const char * path,
  689. apr_uint32_t dirent_fields,
  690. apr_pool_t * pool);
  691. // See check_path().
  692. error_t (*check_path)(session_t * session,
  693. const char * path,
  694. node_kind_t * kind,
  695. apr_pool_t * pool);
  696. // See stat().
  697. error_t (*stat)(session_t * session,
  698. const char * path,
  699. dirent_t ** dirent,
  700. apr_pool_t * pool);
  701. // See get_webdav_resource_root2().
  702. error_t (*get_webdav_resource_root)(session_t * session,
  703. const char ** url,
  704. apr_pool_t * pool);
  705. // See has_capability().
  706. // error_t (*has_capability)(session_t *session,
  707. // bool *has,
  708. // const char *capability,
  709. // apr_pool_t *pool);
  710. } vtable_t;
  711. static error_t
  712. get_path_relative_to_root(
  713. session_t * session,
  714. const char ** rel_path,
  715. const char * url,
  716. apr_pool_t * pool);
  717. static error_t
  718. neon_init(
  719. const vtable_t ** vtable,
  720. apr_pool_t * pool);
  721. //------------------------------------------------------------------------------
  722. // from svn_ctype.h
  723. // Table of flags for character classification.
  724. extern const apr_uint32_t * const ctype_table;
  725. // Check if c is in the character class described by flags.
  726. // The flags is a bitwise-or combination of WEBDAV_CTYPE_*
  727. // constants. Uses #ctype_table.
  728. #define ctype_test(c, flags) \
  729. (0 != (ctype_table[(unsigned char)(c)] & (flags)))
  730. // Basic character classes
  731. #define WEBDAV_CTYPE_CNTRL 0x0001 //< Control character
  732. #define WEBDAV_CTYPE_SPACE 0x0002 //< Whitespace
  733. #define WEBDAV_CTYPE_DIGIT 0x0004 //< Decimal digit
  734. #define WEBDAV_CTYPE_UPPER 0x0008 //< Uppercase letter
  735. #define WEBDAV_CTYPE_LOWER 0x0010 //< Lowercase letter
  736. #define WEBDAV_CTYPE_PUNCT 0x0020 //< Punctuation mark
  737. #define WEBDAV_CTYPE_XALPHA 0x0040 //< Hexadecimal digits A to F
  738. #define WEBDAV_CTYPE_ASCII 0x0080 //< ASCII subset*/
  739. // Derived character classes
  740. // ASCII letter
  741. #define WEBDAV_CTYPE_ALPHA (WEBDAV_CTYPE_LOWER | WEBDAV_CTYPE_UPPER)
  742. // ASCII letter or decimal digit
  743. #define WEBDAV_CTYPE_ALNUM (WEBDAV_CTYPE_ALPHA | WEBDAV_CTYPE_DIGIT)
  744. // ASCII hexadecimal digit
  745. #define WEBDAV_CTYPE_XDIGIT (WEBDAV_CTYPE_DIGIT | WEBDAV_CTYPE_XALPHA)
  746. // Printable ASCII except space
  747. #define WEBDAV_CTYPE_GRAPH (WEBDAV_CTYPE_PUNCT | WEBDAV_CTYPE_ALNUM)
  748. // All printable ASCII
  749. #define WEBDAV_CTYPE_PRINT (WEBDAV_CTYPE_GRAPH | WEBDAV_CTYPE_SPACE)
  750. // Check if c is an ASCII control character.
  751. #define ctype_iscntrl(c) ctype_test((c), WEBDAV_CTYPE_CNTRL)
  752. // Check if c is an ASCII whitespace character.
  753. #define ctype_isspace(c) ctype_test((c), WEBDAV_CTYPE_SPACE)
  754. // Check if c is an ASCII digit.
  755. #define ctype_isdigit(c) ctype_test((c), WEBDAV_CTYPE_DIGIT)
  756. // Check if c is an ASCII uppercase letter.
  757. #define ctype_isupper(c) ctype_test((c), WEBDAV_CTYPE_UPPER)
  758. // Check if c is an ASCII lowercase letter.
  759. #define ctype_islower(c) ctype_test((c), WEBDAV_CTYPE_LOWER)
  760. // Check if c is an ASCII punctuation mark.
  761. #define ctype_ispunct(c) ctype_test((c), WEBDAV_CTYPE_PUNCT)
  762. // Check if c is an ASCII character.
  763. #define ctype_isascii(c) ctype_test((c), WEBDAV_CTYPE_ASCII)
  764. // Check if c is an ASCII letter.
  765. #define ctype_isalpha(c) ctype_test((c), WEBDAV_CTYPE_ALPHA)
  766. // Check if c is an ASCII letter or decimal digit.
  767. #define ctype_isalnum(c) ctype_test((c), WEBDAV_CTYPE_ALNUM)
  768. // Check if c is an ASCII hexadecimal digit.
  769. #define ctype_isxdigit(c) ctype_test((c), WEBDAV_CTYPE_XDIGIT)
  770. // Check if c is an ASCII graphical (visible printable) character.
  771. #define ctype_isgraph(c) ctype_test((c), WEBDAV_CTYPE_GRAPH)
  772. // Check if c is an ASCII printable character.
  773. #define ctype_isprint(c) ctype_test((c), WEBDAV_CTYPE_PRINT)
  774. // Basic extended character classes
  775. #define WEBDAV_CTYPE_UTF8LEAD 0x0100 //< UTF-8 multibyte lead byte
  776. #define WEBDAV_CTYPE_UTF8CONT 0x0200 //< UTF-8 multibyte non-lead byte
  777. #define WEBDAV_CTYPE_XMLNAME 0x0400
  778. #define WEBDAV_CTYPE_URISAFE 0x0800
  779. // Derived extended character classes
  780. // Part of a UTF-8 multibyte character.
  781. #define WEBDAV_CTYPE_UTF8MBC (WEBDAV_CTYPE_UTF8LEAD | WEBDAV_CTYPE_UTF8CONT)
  782. // All valid UTF-8 bytes.
  783. #define WEBDAV_CTYPE_UTF8 (WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UTF8MBC)
  784. // Check if c is a UTF-8 multibyte lead byte.
  785. #define ctype_isutf8lead(c) ctype_test((c), WEBDAV_CTYPE_UTF8LEAD)
  786. // Check if c is a UTF-8 multibyte continuation (non-lead) byte.
  787. #define ctype_isutf8cont(c) ctype_test((c), WEBDAV_CTYLE_UTF8CONT)
  788. // Check if c is part of a UTF-8 multibyte character.
  789. #define ctype_isutf8mbc(c) ctype_test((c), WEBDAV_CTYPE_UTF8MBC)
  790. // Check if c is valid in UTF-8.
  791. #define ctype_isutf8(c) ctype_test((c), WEBDAV_CTYPE_UTF8)
  792. #define WEBDAV_CTYPE_ASCII_MINUS 45 //< ASCII value of '-'
  793. #define WEBDAV_CTYPE_ASCII_DOT 46 //< ASCII value of '.'
  794. #define WEBDAV_CTYPE_ASCII_COLON 58 //< ASCII value of ':'
  795. #define WEBDAV_CTYPE_ASCII_UNDERSCORE 95 //< ASCII value of '_'
  796. #define WEBDAV_CTYPE_ASCII_TAB 9 //< ASCII value of a tab
  797. #define WEBDAV_CTYPE_ASCII_LINEFEED 10 //< ASCII value of a line feed
  798. #define WEBDAV_CTYPE_ASCII_CARRIAGERETURN 13
  799. //< ASCII value of a carriage return
  800. #define WEBDAV_CTYPE_ASCII_DELETE 127
  801. //< ASCII value of a delete character
  802. /*
  803. * Compare two characters a and b, treating case-equivalent
  804. * unaccented Latin (ASCII subset) letters as equal.
  805. *
  806. * Returns in integer greater than, equal to, or less than 0,
  807. * according to whether a is considered greater than, equal to,
  808. * or less than b.
  809. */
  810. static int
  811. ctype_casecmp(int a, int b);
  812. //------------------------------------------------------------------------------
  813. // from svn_string.c
  814. static APR_INLINE bool
  815. string_compare(
  816. const char * str1,
  817. const char * str2,
  818. apr_size_t len1,
  819. apr_size_t len2)
  820. {
  821. // easy way out :)
  822. if (len1 != len2)
  823. return FALSE;
  824. // now the strings must have identical lengths
  825. if ((memcmp(str1, str2, len1)) == 0)
  826. return TRUE;
  827. else
  828. return FALSE;
  829. }
  830. // Our own realloc, since APR doesn't have one. Note: this is a
  831. // generic realloc for memory pools, *not* for strings.
  832. static void *
  833. my_realloc(
  834. char * data,
  835. apr_size_t oldsize,
  836. apr_size_t request,
  837. apr_pool_t * pool)
  838. {
  839. void * new_area = NULL;
  840. // todo: it's a pity APR doesn't give us this -- sometimes it
  841. // could realloc the block merely by extending in place, sparing us
  842. // a memcpy(), but only the pool would know enough to be able to do
  843. // this. We should add a realloc() to APR if someone hasn't
  844. // already.
  845. // malloc new area
  846. new_area = apr_pcalloc(pool, request);
  847. // copy data to new area
  848. memcpy(new_area, data, oldsize);
  849. // I'm NOT freeing old area here -- cuz we're using pools, ugh.
  850. // return new area
  851. return new_area;
  852. }
  853. // string functions
  854. static stringbuf_t *
  855. stringbuf_create_ensure(
  856. apr_size_t blocksize,
  857. apr_pool_t * pool)
  858. {
  859. void * mem = NULL;
  860. stringbuf_t * new_string = NULL;
  861. // apr_pcalloc will allocate multiples of 8.
  862. // Thus, we would waste some of that memory if we stuck to the
  863. // smaller size. Note that this is safe even if apr_pcalloc would
  864. // use some other alignment or none at all.
  865. ++blocksize; // + space for '\0'
  866. blocksize = APR_ALIGN_DEFAULT(blocksize);
  867. // Allocate memory for string_t and data in one chunk.
  868. mem = apr_pcalloc(pool, sizeof(*new_string) + blocksize);
  869. // Initialize header and string
  870. new_string = static_cast<stringbuf_t *>(mem);
  871. new_string->data = (char *)mem + sizeof(*new_string);
  872. new_string->data[0] = '\0';
  873. new_string->len = 0;
  874. new_string->blocksize = blocksize;
  875. new_string->pool = pool;
  876. return new_string;
  877. }
  878. static stringbuf_t *
  879. stringbuf_ncreate(
  880. const char * bytes,
  881. apr_size_t size,
  882. apr_pool_t * pool)
  883. {
  884. stringbuf_t * strbuf = stringbuf_create_ensure(size, pool);
  885. memcpy(strbuf->data, bytes, size);
  886. // Null termination is the convention -- even if we suspect the data
  887. // to be binary, it's not up to us to decide, it's the caller's
  888. // call. Heck, that's why they call it the caller!
  889. strbuf->data[size] = '\0';
  890. strbuf->len = size;
  891. return strbuf;
  892. }
  893. static stringbuf_t *
  894. stringbuf_create(
  895. const char * cstring,
  896. apr_pool_t * pool)
  897. {
  898. return stringbuf_ncreate(cstring, strlen(cstring), pool);
  899. }
  900. static void
  901. stringbuf_ensure(
  902. stringbuf_t * str,
  903. apr_size_t minimum_size)
  904. {
  905. // Keep doubling capacity until have enough.
  906. if (str->blocksize < minimum_size)
  907. {
  908. if (str->blocksize == 0)
  909. // APR will increase odd allocation sizes to the next
  910. // multiple for 8, for instance. Take advantage of that
  911. // knowledge and allow for the extra size to be used.
  912. str->blocksize = APR_ALIGN_DEFAULT(minimum_size);
  913. else
  914. while (str->blocksize < minimum_size)
  915. {
  916. // str->blocksize is aligned;
  917. // doubling it should keep it aligned
  918. apr_size_t prev_size = str->blocksize;
  919. str->blocksize *= 2;
  920. // check for apr_size_t overflow
  921. if (prev_size > str->blocksize)
  922. {
  923. str->blocksize = minimum_size;
  924. break;
  925. }
  926. }
  927. str->data = (char *) my_realloc(str->data,
  928. str->len + 1,
  929. // We need to maintain (and thus copy)
  930. // the trailing null
  931. str->blocksize,
  932. str->pool);
  933. }
  934. }
  935. static void
  936. stringbuf_set(
  937. stringbuf_t * str,
  938. const char * value)
  939. {
  940. apr_size_t amt = strlen(value);
  941. stringbuf_ensure(str, amt + 1);
  942. memcpy(str->data, value, amt + 1);
  943. str->len = amt;
  944. }
  945. static void
  946. stringbuf_setempty(
  947. stringbuf_t * str)
  948. {
  949. if (str->len > 0)
  950. str->data[0] = '\0';
  951. str->len = 0;
  952. }
  953. static bool
  954. stringbuf_isempty(
  955. const stringbuf_t * str)
  956. {
  957. return (str->len == 0);
  958. }
  959. // Return a new string_t object, allocated in POOL, initialized with
  960. // DATA and SIZE. Do not copy the contents of DATA, just store the pointer.
  961. // SIZE is the length in bytes of DATA, excluding the required NUL
  962. // terminator.
  963. static string_t *
  964. create_string(
  965. const char * data,
  966. apr_size_t size,
  967. apr_pool_t * pool)
  968. {
  969. string_t * new_string;
  970. new_string = static_cast<string_t *>(apr_pcalloc(pool, sizeof(*new_string)));
  971. new_string->data = data;
  972. new_string->len = size;
  973. return new_string;
  974. }
  975. static string_t *
  976. string_ncreate(
  977. const char * bytes,
  978. apr_size_t size,
  979. apr_pool_t * pool)
  980. {
  981. void * mem = NULL;
  982. char * data = NULL;
  983. string_t * new_string;
  984. // Allocate memory for string_t and data in one chunk.
  985. mem = apr_pcalloc(pool, sizeof(*new_string) + size + 1);
  986. data = (char *)mem + sizeof(*new_string);
  987. new_string = static_cast<string_t *>(mem);
  988. new_string->data = data;
  989. new_string->len = size;
  990. memcpy(data, bytes, size);
  991. // Null termination is the convention -- even if we suspect the data
  992. // to be binary, it's not up to us to decide, it's the caller's
  993. // call. Heck, that's why they call it the caller!
  994. data[size] = '\0';
  995. return new_string;
  996. }
  997. static string_t *
  998. string_create(
  999. const char * cstring,
  1000. apr_pool_t * pool)
  1001. {
  1002. return string_ncreate(cstring, strlen(cstring), pool);
  1003. }
  1004. static string_t *
  1005. string_createv(
  1006. apr_pool_t * pool,
  1007. const char * fmt,
  1008. va_list ap)
  1009. {
  1010. char * data = apr_pvsprintf(pool, fmt, ap);
  1011. // wrap an string_t around the new data
  1012. return create_string(data, strlen(data), pool);
  1013. }
  1014. static string_t *
  1015. string_createf(
  1016. apr_pool_t * pool,
  1017. const char * fmt,
  1018. ...)
  1019. {
  1020. string_t * str = NULL;
  1021. va_list ap;
  1022. va_start(ap, fmt);
  1023. str = string_createv(pool, fmt, ap);
  1024. va_end(ap);
  1025. return str;
  1026. }
  1027. static bool
  1028. string_compare(
  1029. const string_t * str1,
  1030. const string_t * str2)
  1031. {
  1032. return
  1033. string_compare(str1->data, str2->data, str1->len, str2->len);
  1034. }
  1035. static void
  1036. stringbuf_appendbytes(
  1037. stringbuf_t * str,
  1038. const char * bytes,
  1039. apr_size_t count)
  1040. {
  1041. apr_size_t total_len = 0;
  1042. void * start_address = NULL;
  1043. total_len = str->len + count; // total size needed
  1044. // +1 for null terminator.
  1045. stringbuf_ensure(str, (total_len + 1));
  1046. // get address 1 byte beyond end of original bytestring
  1047. start_address = (str->data + str->len);
  1048. memcpy(start_address, bytes, count);
  1049. str->len = total_len;
  1050. str->data[str->len] = '\0'; // We don't know if this is binary
  1051. // data or not, but convention is
  1052. // to null-terminate.
  1053. }
  1054. static void
  1055. stringbuf_appendstr(
  1056. stringbuf_t * targetstr,
  1057. const stringbuf_t * appendstr)
  1058. {
  1059. stringbuf_appendbytes(targetstr, appendstr->data, appendstr->len);
  1060. }
  1061. static void
  1062. stringbuf_appendcstr(
  1063. stringbuf_t * targetstr,
  1064. const char * cstr)
  1065. {
  1066. stringbuf_appendbytes(targetstr, cstr, strlen(cstr));
  1067. }
  1068. static error_t
  1069. cstring_strtoi64(
  1070. apr_int64_t * n,
  1071. const char * str,
  1072. apr_int64_t minval,
  1073. apr_int64_t maxval,
  1074. int base)
  1075. {
  1076. apr_int64_t val = 0;
  1077. char * endptr = NULL;
  1078. // We assume errno is thread-safe.
  1079. errno = 0; // APR-0.9 doesn't always set errno
  1080. val = apr_strtoi64(str, &endptr, base);
  1081. if (errno == EINVAL || endptr == str || str[0] == '\0' || *endptr != '\0')
  1082. return error_createf(WEBDAV_ERR_INCORRECT_PARAMS, NULL,
  1083. "Could not convert '%s' into a number",
  1084. str);
  1085. if ((errno == ERANGE && (val == APR_INT64_MIN || val == APR_INT64_MAX)) ||
  1086. val < minval || val > maxval)
  1087. // Mark this for translation when gettext doesn't choke on macros.
  1088. return error_createf(WEBDAV_ERR_INCORRECT_PARAMS, NULL,
  1089. "Number '%s' is out of range "
  1090. "'[%" APR_INT64_T_FMT ", %" APR_INT64_T_FMT "]'",
  1091. str, minval, maxval);
  1092. *n = val;
  1093. return WEBDAV_NO_ERROR;
  1094. }
  1095. static error_t
  1096. cstring_atoi64(
  1097. apr_int64_t * n,
  1098. const char * str)
  1099. {
  1100. return error_trace(cstring_strtoi64(n, str, APR_INT64_MIN,
  1101. APR_INT64_MAX, 10));
  1102. }
  1103. static int
  1104. cstring_casecmp(
  1105. const char * str1,
  1106. const char * str2)
  1107. {
  1108. for (;;)
  1109. {
  1110. const int a = *str1++;
  1111. const int b = *str2++;
  1112. const int cmp = ctype_casecmp(a, b);
  1113. if (cmp || !a || !b)
  1114. return cmp;
  1115. }
  1116. }
  1117. static stringbuf_t *
  1118. create_stringbuf(
  1119. char * data,
  1120. apr_size_t size,
  1121. apr_size_t blocksize,
  1122. apr_pool_t * pool)
  1123. {
  1124. stringbuf_t * new_string;
  1125. new_string = static_cast<stringbuf_t *>(apr_pcalloc(pool, sizeof(*new_string)));
  1126. new_string->data = data;
  1127. new_string->len = size;
  1128. new_string->blocksize = blocksize;
  1129. new_string->pool = pool;
  1130. return new_string;
  1131. }
  1132. static stringbuf_t *
  1133. stringbuf_createv(
  1134. apr_pool_t * pool,
  1135. const char * fmt,
  1136. va_list ap)
  1137. {
  1138. char * data = apr_pvsprintf(pool, fmt, ap);
  1139. apr_size_t size = strlen(data);
  1140. // wrap an stringbuf_t around the new data
  1141. return create_stringbuf(data, size, size + 1, pool);
  1142. }
  1143. static stringbuf_t *
  1144. stringbuf_createf(
  1145. apr_pool_t * pool,
  1146. const char * fmt,
  1147. ...)
  1148. {
  1149. stringbuf_t * str = NULL;
  1150. va_list ap;
  1151. va_start(ap, fmt);
  1152. str = stringbuf_createv(pool, fmt, ap);
  1153. va_end(ap);
  1154. return str;
  1155. }
  1156. static void
  1157. cstring_split_append(
  1158. apr_array_header_t * array,
  1159. const char * input,
  1160. const char * sep_chars,
  1161. bool chop_whitespace,
  1162. apr_pool_t * pool)
  1163. {
  1164. char * last = NULL;
  1165. char * pats = apr_pstrdup(pool, input); // strtok wants non-const data
  1166. char * p = apr_strtok(pats, sep_chars, &last);
  1167. while (p)
  1168. {
  1169. if (chop_whitespace)
  1170. {
  1171. while (ctype_isspace(*p))
  1172. p++;
  1173. {
  1174. char * e = p + (strlen(p) - 1);
  1175. while ((e >= p) && (ctype_isspace(*e)))
  1176. e--;
  1177. *(++e) = '\0';
  1178. }
  1179. }
  1180. if (p[0] != '\0')
  1181. APR_ARRAY_PUSH(array, const char *) = p;
  1182. p = apr_strtok(NULL, sep_chars, &last);
  1183. }
  1184. return;
  1185. }
  1186. static apr_array_header_t *
  1187. cstring_split(
  1188. const char * input,
  1189. const char * sep_chars,
  1190. bool chop_whitespace,
  1191. apr_pool_t * pool)
  1192. {
  1193. apr_array_header_t * a = apr_array_make(pool, 5, sizeof(input));
  1194. cstring_split_append(a, input, sep_chars, chop_whitespace, pool);
  1195. return a;
  1196. }
  1197. //------------------------------------------------------------------------------
  1198. // from ctype.c
  1199. static const apr_uint32_t ctype_table_internal[256] =
  1200. {
  1201. // **** DO NOT EDIT! ****
  1202. // This table was generated by genctype.py, make changes there.
  1203. /* nul */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1204. /* soh */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1205. /* stx */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1206. /* etx */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1207. /* eot */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1208. /* enq */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1209. /* ack */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1210. /* bel */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1211. /* bs */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1212. /* ht */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL | WEBDAV_CTYPE_SPACE,
  1213. /* nl */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL | WEBDAV_CTYPE_SPACE,
  1214. /* vt */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL | WEBDAV_CTYPE_SPACE,
  1215. /* np */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL | WEBDAV_CTYPE_SPACE,
  1216. /* cr */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL | WEBDAV_CTYPE_SPACE,
  1217. /* so */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1218. /* si */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1219. /* dle */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1220. /* dc1 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1221. /* dc2 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1222. /* dc3 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1223. /* dc4 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1224. /* nak */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1225. /* syn */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1226. /* etb */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1227. /* can */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1228. /* em */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1229. /* sub */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1230. /* esc */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1231. /* fs */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1232. /* gs */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1233. /* rs */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1234. /* us */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1235. /* sp */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_SPACE,
  1236. /* ! */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1237. /* " */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1238. /* # */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1239. /* $ */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1240. /* % */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1241. /* & */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1242. /* ' */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1243. /* ( */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1244. /* ) */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1245. /* * */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1246. /* + */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1247. /* , */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1248. /* - */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1249. /* . */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1250. /* / */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1251. /* 0 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
  1252. /* 1 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
  1253. /* 2 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
  1254. /* 3 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
  1255. /* 4 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
  1256. /* 5 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
  1257. /* 6 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
  1258. /* 7 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
  1259. /* 8 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
  1260. /* 9 */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_DIGIT,
  1261. /* : */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1262. /* ; */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1263. /* < */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1264. /* = */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1265. /* > */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1266. /* ? */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1267. /* @ */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1268. /* A */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER | WEBDAV_CTYPE_XALPHA,
  1269. /* B */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER | WEBDAV_CTYPE_XALPHA,
  1270. /* C */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER | WEBDAV_CTYPE_XALPHA,
  1271. /* D */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER | WEBDAV_CTYPE_XALPHA,
  1272. /* E */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER | WEBDAV_CTYPE_XALPHA,
  1273. /* F */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER | WEBDAV_CTYPE_XALPHA,
  1274. /* G */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1275. /* H */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1276. /* I */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1277. /* J */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1278. /* K */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1279. /* L */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1280. /* M */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1281. /* N */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1282. /* O */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1283. /* P */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1284. /* Q */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1285. /* R */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1286. /* S */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1287. /* T */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1288. /* U */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1289. /* V */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1290. /* W */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1291. /* X */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1292. /* Y */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1293. /* Z */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_UPPER,
  1294. /* [ */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1295. /* \ */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1296. /* ] */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1297. /* ^ */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1298. /* _ */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1299. /* ` */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1300. /* a */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER | WEBDAV_CTYPE_XALPHA,
  1301. /* b */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER | WEBDAV_CTYPE_XALPHA,
  1302. /* c */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER | WEBDAV_CTYPE_XALPHA,
  1303. /* d */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER | WEBDAV_CTYPE_XALPHA,
  1304. /* e */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER | WEBDAV_CTYPE_XALPHA,
  1305. /* f */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER | WEBDAV_CTYPE_XALPHA,
  1306. /* g */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1307. /* h */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1308. /* i */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1309. /* j */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1310. /* k */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1311. /* l */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1312. /* m */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1313. /* n */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1314. /* o */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1315. /* p */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1316. /* q */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1317. /* r */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1318. /* s */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1319. /* t */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1320. /* u */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1321. /* v */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1322. /* w */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1323. /* x */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1324. /* y */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1325. /* z */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_LOWER,
  1326. /* { */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1327. /* | */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1328. /* } */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1329. /* ~ */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_PUNCT,
  1330. /* del */ WEBDAV_CTYPE_ASCII | WEBDAV_CTYPE_CNTRL,
  1331. /* x80 */ WEBDAV_CTYPE_UTF8CONT,
  1332. /* x81 */ WEBDAV_CTYPE_UTF8CONT,
  1333. /* x82 */ WEBDAV_CTYPE_UTF8CONT,
  1334. /* x83 */ WEBDAV_CTYPE_UTF8CONT,
  1335. /* x84 */ WEBDAV_CTYPE_UTF8CONT,
  1336. /* x85 */ WEBDAV_CTYPE_UTF8CONT,
  1337. /* x86 */ WEBDAV_CTYPE_UTF8CONT,
  1338. /* x87 */ WEBDAV_CTYPE_UTF8CONT,
  1339. /* x88 */ WEBDAV_CTYPE_UTF8CONT,
  1340. /* x89 */ WEBDAV_CTYPE_UTF8CONT,
  1341. /* x8a */ WEBDAV_CTYPE_UTF8CONT,
  1342. /* x8b */ WEBDAV_CTYPE_UTF8CONT,
  1343. /* x8c */ WEBDAV_CTYPE_UTF8CONT,
  1344. /* x8d */ WEBDAV_CTYPE_UTF8CONT,
  1345. /* x8e */ WEBDAV_CTYPE_UTF8CONT,
  1346. /* x8f */ WEBDAV_CTYPE_UTF8CONT,
  1347. /* x90 */ WEBDAV_CTYPE_UTF8CONT,
  1348. /* x91 */ WEBDAV_CTYPE_UTF8CONT,
  1349. /* x92 */ WEBDAV_CTYPE_UTF8CONT,
  1350. /* x93 */ WEBDAV_CTYPE_UTF8CONT,
  1351. /* x94 */ WEBDAV_CTYPE_UTF8CONT,
  1352. /* x95 */ WEBDAV_CTYPE_UTF8CONT,
  1353. /* x96 */ WEBDAV_CTYPE_UTF8CONT,
  1354. /* x97 */ WEBDAV_CTYPE_UTF8CONT,
  1355. /* x98 */ WEBDAV_CTYPE_UTF8CONT,
  1356. /* x99 */ WEBDAV_CTYPE_UTF8CONT,
  1357. /* x9a */ WEBDAV_CTYPE_UTF8CONT,
  1358. /* x9b */ WEBDAV_CTYPE_UTF8CONT,
  1359. /* x9c */ WEBDAV_CTYPE_UTF8CONT,
  1360. /* x9d */ WEBDAV_CTYPE_UTF8CONT,
  1361. /* x9e */ WEBDAV_CTYPE_UTF8CONT,
  1362. /* x9f */ WEBDAV_CTYPE_UTF8CONT,
  1363. /* xa0 */ WEBDAV_CTYPE_UTF8CONT,
  1364. /* xa1 */ WEBDAV_CTYPE_UTF8CONT,
  1365. /* xa2 */ WEBDAV_CTYPE_UTF8CONT,
  1366. /* xa3 */ WEBDAV_CTYPE_UTF8CONT,
  1367. /* xa4 */ WEBDAV_CTYPE_UTF8CONT,
  1368. /* xa5 */ WEBDAV_CTYPE_UTF8CONT,
  1369. /* xa6 */ WEBDAV_CTYPE_UTF8CONT,
  1370. /* xa7 */ WEBDAV_CTYPE_UTF8CONT,
  1371. /* xa8 */ WEBDAV_CTYPE_UTF8CONT,
  1372. /* xa9 */ WEBDAV_CTYPE_UTF8CONT,
  1373. /* xaa */ WEBDAV_CTYPE_UTF8CONT,
  1374. /* xab */ WEBDAV_CTYPE_UTF8CONT,
  1375. /* xac */ WEBDAV_CTYPE_UTF8CONT,
  1376. /* xad */ WEBDAV_CTYPE_UTF8CONT,
  1377. /* xae */ WEBDAV_CTYPE_UTF8CONT,
  1378. /* xaf */ WEBDAV_CTYPE_UTF8CONT,
  1379. /* xb0 */ WEBDAV_CTYPE_UTF8CONT,
  1380. /* xb1 */ WEBDAV_CTYPE_UTF8CONT,
  1381. /* xb2 */ WEBDAV_CTYPE_UTF8CONT,
  1382. /* xb3 */ WEBDAV_CTYPE_UTF8CONT,
  1383. /* xb4 */ WEBDAV_CTYPE_UTF8CONT,
  1384. /* xb5 */ WEBDAV_CTYPE_UTF8CONT,
  1385. /* xb6 */ WEBDAV_CTYPE_UTF8CONT,
  1386. /* xb7 */ WEBDAV_CTYPE_UTF8CONT,
  1387. /* xb8 */ WEBDAV_CTYPE_UTF8CONT,
  1388. /* xb9 */ WEBDAV_CTYPE_UTF8CONT,
  1389. /* xba */ WEBDAV_CTYPE_UTF8CONT,
  1390. /* xbb */ WEBDAV_CTYPE_UTF8CONT,
  1391. /* xbc */ WEBDAV_CTYPE_UTF8CONT,
  1392. /* xbd */ WEBDAV_CTYPE_UTF8CONT,
  1393. /* xbe */ WEBDAV_CTYPE_UTF8CONT,
  1394. /* xbf */ WEBDAV_CTYPE_UTF8CONT,
  1395. /* xc0 */ 0,
  1396. /* xc1 */ WEBDAV_CTYPE_UTF8LEAD,
  1397. /* xc2 */ WEBDAV_CTYPE_UTF8LEAD,
  1398. /* xc3 */ WEBDAV_CTYPE_UTF8LEAD,
  1399. /* xc4 */ WEBDAV_CTYPE_UTF8LEAD,
  1400. /* xc5 */ WEBDAV_CTYPE_UTF8LEAD,
  1401. /* xc6 */ WEBDAV_CTYPE_UTF8LEAD,
  1402. /* xc7 */ WEBDAV_CTYPE_UTF8LEAD,
  1403. /* xc8 */ WEBDAV_CTYPE_UTF8LEAD,
  1404. /* xc9 */ WEBDAV_CTYPE_UTF8LEAD,
  1405. /* xca */ WEBDAV_CTYPE_UTF8LEAD,
  1406. /* xcb */ WEBDAV_CTYPE_UTF8LEAD,
  1407. /* xcc */ WEBDAV_CTYPE_UTF8LEAD,
  1408. /* xcd */ WEBDAV_CTYPE_UTF8LEAD,
  1409. /* xce */ WEBDAV_CTYPE_UTF8LEAD,
  1410. /* xcf */ WEBDAV_CTYPE_UTF8LEAD,
  1411. /* xd0 */ WEBDAV_CTYPE_UTF8LEAD,
  1412. /* xd1 */ WEBDAV_CTYPE_UTF8LEAD,
  1413. /* xd2 */ WEBDAV_CTYPE_UTF8LEAD,
  1414. /* xd3 */ WEBDAV_CTYPE_UTF8LEAD,
  1415. /* xd4 */ WEBDAV_CTYPE_UTF8LEAD,
  1416. /* xd5 */ WEBDAV_CTYPE_UTF8LEAD,
  1417. /* xd6 */ WEBDAV_CTYPE_UTF8LEAD,
  1418. /* xd7 */ WEBDAV_CTYPE_UTF8LEAD,
  1419. /* xd8 */ WEBDAV_CTYPE_UTF8LEAD,
  1420. /* xd9 */ WEBDAV_CTYPE_UTF8LEAD,
  1421. /* xda */ WEBDAV_CTYPE_UTF8LEAD,
  1422. /* xdb */ WEBDAV_CTYPE_UTF8LEAD,
  1423. /* xdc */ WEBDAV_CTYPE_UTF8LEAD,
  1424. /* xdd */ WEBDAV_CTYPE_UTF8LEAD,
  1425. /* xde */ WEBDAV_CTYPE_UTF8LEAD,
  1426. /* xdf */ WEBDAV_CTYPE_UTF8LEAD,
  1427. /* xe0 */ 0,
  1428. /* xe1 */ WEBDAV_CTYPE_UTF8LEAD,
  1429. /* xe2 */ WEBDAV_CTYPE_UTF8LEAD,
  1430. /* xe3 */ WEBDAV_CTYPE_UTF8LEAD,
  1431. /* xe4 */ WEBDAV_CTYPE_UTF8LEAD,
  1432. /* xe5 */ WEBDAV_CTYPE_UTF8LEAD,
  1433. /* xe6 */ WEBDAV_CTYPE_UTF8LEAD,
  1434. /* xe7 */ WEBDAV_CTYPE_UTF8LEAD,
  1435. /* xe8 */ WEBDAV_CTYPE_UTF8LEAD,
  1436. /* xe9 */ WEBDAV_CTYPE_UTF8LEAD,
  1437. /* xea */ WEBDAV_CTYPE_UTF8LEAD,
  1438. /* xeb */ WEBDAV_CTYPE_UTF8LEAD,
  1439. /* xec */ WEBDAV_CTYPE_UTF8LEAD,
  1440. /* xed */ WEBDAV_CTYPE_UTF8LEAD,
  1441. /* xee */ WEBDAV_CTYPE_UTF8LEAD,
  1442. /* xef */ WEBDAV_CTYPE_UTF8LEAD,
  1443. /* xf0 */ 0,
  1444. /* xf1 */ WEBDAV_CTYPE_UTF8LEAD,
  1445. /* xf2 */ WEBDAV_CTYPE_UTF8LEAD,
  1446. /* xf3 */ WEBDAV_CTYPE_UTF8LEAD,
  1447. /* xf4 */ WEBDAV_CTYPE_UTF8LEAD,
  1448. /* xf5 */ WEBDAV_CTYPE_UTF8LEAD,
  1449. /* xf6 */ WEBDAV_CTYPE_UTF8LEAD,
  1450. /* xf7 */ WEBDAV_CTYPE_UTF8LEAD,
  1451. /* xf8 */ 0,
  1452. /* xf9 */ WEBDAV_CTYPE_UTF8LEAD,
  1453. /* xfa */ WEBDAV_CTYPE_UTF8LEAD,
  1454. /* xfb */ WEBDAV_CTYPE_UTF8LEAD,
  1455. /* xfc */ 0,
  1456. /* xfd */ WEBDAV_CTYPE_UTF8LEAD,
  1457. /* xfe */ 0,
  1458. /* xff */ 0
  1459. };
  1460. const apr_uint32_t * const ctype_table = ctype_table_internal;
  1461. static const unsigned char casefold_table[256] =
  1462. {
  1463. // Identity, except {97:122} => {65:90}
  1464. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
  1465. 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
  1466. 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
  1467. 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
  1468. 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
  1469. 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
  1470. 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
  1471. 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,123,124,125,126,127,
  1472. 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
  1473. 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
  1474. 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
  1475. 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
  1476. 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
  1477. 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
  1478. 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
  1479. 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
  1480. };
  1481. static int
  1482. ctype_casecmp(int a, int b)
  1483. {
  1484. const int A = casefold_table[(unsigned char)a];
  1485. const int B = casefold_table[(unsigned char)b];
  1486. return A - B;
  1487. }
  1488. //------------------------------------------------------------------------------
  1489. // from svn_pool.c
  1490. // Pool allocation handler which just aborts, since we aren't generally
  1491. // prepared to deal with out-of-memory errors.
  1492. static int
  1493. abort_on_pool_failure(int retcode)
  1494. {
  1495. // Don't translate this string! It requires memory allocation to do so!
  1496. // And we don't have any of it...
  1497. printf("Out of memory - terminating application.\n");
  1498. abort();
  1499. }
  1500. static apr_pool_t *
  1501. pool_create_ex(
  1502. apr_pool_t * parent_pool,
  1503. apr_allocator_t * allocator)
  1504. {
  1505. apr_pool_t * pool;
  1506. apr_pool_create_ex(&pool, parent_pool, abort_on_pool_failure, allocator);
  1507. return pool;
  1508. }
  1509. //------------------------------------------------------------------------------
  1510. // from time.c
  1511. #define OLD_TIMESTAMP_FORMAT \
  1512. "%3s %d %3s %d %02d:%02d:%02d.%06d (day %03d, dst %d, gmt_off %06d)"
  1513. static apr_size_t
  1514. find_matching_string(
  1515. char * str,
  1516. apr_size_t size,
  1517. const char strings[][4])
  1518. {
  1519. for (apr_size_t i = 0; i < size; i++)
  1520. if (strings[i] && (strcmp(str, strings[i]) == 0))
  1521. return i;
  1522. return (apr_size_t)-1;
  1523. }
  1524. static error_t
  1525. time_from_cstring(
  1526. apr_time_t * when,
  1527. const char * data,
  1528. apr_pool_t * pool)
  1529. {
  1530. apr_time_exp_t exploded_time;
  1531. apr_status_t apr_err = 0;
  1532. char wday[4] = {0}, month[4] = {0};
  1533. char * c = NULL;
  1534. // Open-code parsing of the new timestamp format, as this
  1535. // is a hot path for reading the entries file. This format looks
  1536. // like: "2001-08-31T04:24:14.966996Z"
  1537. exploded_time.tm_year = strtol(data, &c, 10);
  1538. if (*c++ != '-') goto fail;
  1539. exploded_time.tm_mon = strtol(c, &c, 10);
  1540. if (*c++ != '-') goto fail;
  1541. exploded_time.tm_mday = strtol(c, &c, 10);
  1542. if (*c++ != 'T') goto fail;
  1543. exploded_time.tm_hour = strtol(c, &c, 10);
  1544. if (*c++ != ':') goto fail;
  1545. exploded_time.tm_min = strtol(c, &c, 10);
  1546. if (*c++ != ':') goto fail;
  1547. exploded_time.tm_sec = strtol(c, &c, 10);
  1548. if (*c != 'Z')
  1549. {
  1550. if (*c++ != '.') goto fail;
  1551. exploded_time.tm_usec = strtol(c, &c, 10);
  1552. if (*c++ != 'Z') goto fail;
  1553. }
  1554. exploded_time.tm_year -= 1900;
  1555. exploded_time.tm_mon -= 1;
  1556. exploded_time.tm_wday = 0;
  1557. exploded_time.tm_yday = 0;
  1558. exploded_time.tm_isdst = 0;
  1559. exploded_time.tm_gmtoff = 0;
  1560. apr_err = apr_time_exp_gmt_get(when, &exploded_time);
  1561. if (apr_err == APR_SUCCESS)
  1562. return WEBDAV_NO_ERROR;
  1563. return error_createf(WEBDAV_ERR_BAD_DATE, NULL, "error parsing date: %s", data);
  1564. fail:
  1565. // 2012-09-11T14:18:40+07:00
  1566. char gmt_shift = 0;
  1567. int gmt_hour = 0;
  1568. int gmt_min = 0;
  1569. if (sscanf(data,
  1570. "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
  1571. &exploded_time.tm_year,
  1572. &exploded_time.tm_mon,
  1573. &exploded_time.tm_mday,
  1574. &exploded_time.tm_hour,
  1575. &exploded_time.tm_min,
  1576. &exploded_time.tm_sec,
  1577. &gmt_shift,
  1578. &gmt_hour,
  1579. &gmt_min) == 9)
  1580. {
  1581. exploded_time.tm_year -= 1900;
  1582. exploded_time.tm_mon -= 1;
  1583. exploded_time.tm_wday = 0;
  1584. exploded_time.tm_yday = 0;
  1585. exploded_time.tm_isdst = 0;
  1586. exploded_time.tm_gmtoff = (gmt_shift == '-' ? -1 : 1) * gmt_hour * SecsPerHour + gmt_min * SecsPerMin;
  1587. exploded_time.tm_usec = 0;
  1588. apr_err = apr_time_exp_gmt_get(when, &exploded_time);
  1589. if (apr_err != APR_SUCCESS)
  1590. return error_createf(WEBDAV_ERR_BAD_DATE, NULL, "error parsing date: %s", data);
  1591. return WEBDAV_NO_ERROR;
  1592. }
  1593. // 2012-09-11T03:56:20
  1594. if (sscanf(data,
  1595. "%04d-%02d-%02dT%02d:%02d:%02d",
  1596. &exploded_time.tm_year,
  1597. &exploded_time.tm_mon,
  1598. &exploded_time.tm_mday,
  1599. &exploded_time.tm_hour,
  1600. &exploded_time.tm_min,
  1601. &exploded_time.tm_sec) == 6)
  1602. {
  1603. exploded_time.tm_year -= 1900;
  1604. exploded_time.tm_mon -= 1;
  1605. exploded_time.tm_wday = 0;
  1606. exploded_time.tm_yday = 0;
  1607. exploded_time.tm_isdst = 0;
  1608. exploded_time.tm_gmtoff = 0;
  1609. exploded_time.tm_usec = 0;
  1610. apr_err = apr_time_exp_gmt_get(when, &exploded_time);
  1611. if (apr_err != APR_SUCCESS)
  1612. return error_createf(WEBDAV_ERR_BAD_DATE, NULL, "error parsing date: %s", data);
  1613. return WEBDAV_NO_ERROR;
  1614. }
  1615. // Try the compatibility option. This does not need to be fast,
  1616. // as this format is no longer generated and the client will convert
  1617. // an old-format entries file the first time it reads it.
  1618. if (sscanf(data,
  1619. OLD_TIMESTAMP_FORMAT,
  1620. wday,
  1621. &exploded_time.tm_mday,
  1622. month,
  1623. &exploded_time.tm_year,
  1624. &exploded_time.tm_hour,
  1625. &exploded_time.tm_min,
  1626. &exploded_time.tm_sec,
  1627. &exploded_time.tm_usec,
  1628. &exploded_time.tm_yday,
  1629. &exploded_time.tm_isdst,
  1630. &exploded_time.tm_gmtoff) == 11)
  1631. {
  1632. exploded_time.tm_year -= 1900;
  1633. exploded_time.tm_yday -= 1;
  1634. // Using hard coded limits for the arrays - they are going away
  1635. // soon in any case.
  1636. exploded_time.tm_wday = (apr_int32_t)find_matching_string(wday, 7, apr_day_snames);
  1637. exploded_time.tm_mon = (apr_int32_t)find_matching_string(month, 12, apr_month_snames);
  1638. apr_err = apr_time_exp_gmt_get(when, &exploded_time);
  1639. if (apr_err != APR_SUCCESS)
  1640. return error_createf(WEBDAV_ERR_BAD_DATE, NULL, "error parsing date: %s", data);
  1641. return WEBDAV_NO_ERROR;
  1642. }
  1643. // Timestamp is something we do not recognize.
  1644. // return error_createf(WEBDAV_ERR_BAD_DATE, NULL, "error parsing date: %s", data);
  1645. *when = apr_time_now();
  1646. return WEBDAV_NO_ERROR;
  1647. }
  1648. //------------------------------------------------------------------------------
  1649. // from path.c
  1650. // TRUE if s is the canonical empty path, FALSE otherwise
  1651. #define WEBDAV_PATH_IS_EMPTY(s) ((s)[0] == '\0')
  1652. // TRUE if s,n is the platform's empty path ("."), FALSE otherwise. Can
  1653. // this be changed? Well, the path library will work, not so sure about
  1654. // the OS!
  1655. #define WEBDAV_PATH_IS_PLATFORM_EMPTY(s,n) ((n) == 1 && (s)[0] == '.')
  1656. /* Here is the BNF for path components in a URI. "pchar" is a
  1657. character in a path component.
  1658. pchar = unreserved | escaped |
  1659. ":" | "@" | "&" | "=" | "+" | "$" | ","
  1660. unreserved = alphanum | mark
  1661. mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
  1662. Note that "escaped" doesn't really apply to what users can put in
  1663. their paths, so that really means the set of characters is:
  1664. alphanum | mark | ":" | "@" | "&" | "=" | "+" | "$" | ","
  1665. */
  1666. static const char uri_char_validity[256] =
  1667. {
  1668. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1669. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1670. 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  1671. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0,
  1672. // 64
  1673. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  1674. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
  1675. 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  1676. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0,
  1677. // 128
  1678. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1679. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1680. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1681. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1682. // 192
  1683. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1684. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1685. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1686. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1687. };
  1688. // URI-encode each character c in PATH for which TABLE[c] is 0.
  1689. // If no encoding was needed, return PATH, else return a new string allocated
  1690. // in POOL.
  1691. static const char *
  1692. uri_escape(
  1693. const char * path,
  1694. const char table[],
  1695. apr_pool_t * pool)
  1696. {
  1697. stringbuf_t * retstr = NULL;
  1698. size_t i = 0, copied = 0;
  1699. int c = 0;
  1700. retstr = stringbuf_create_ensure(strlen(path), pool);
  1701. for (i = 0; path[i]; i++)
  1702. {
  1703. c = (unsigned char)path[i];
  1704. if (table[c])
  1705. continue;
  1706. // If we got here, we're looking at a character that isn't
  1707. // supported by the (or at least, our) URI encoding scheme. We
  1708. // need to escape this character.
  1709. // First things first, copy all the good stuff that we haven't
  1710. // yet copied into our output buffer.
  1711. if (i - copied)
  1712. stringbuf_appendbytes(retstr, path + copied,
  1713. i - copied);
  1714. // Now, write in our escaped character, consisting of the
  1715. // '%' and two digits. We cast the C to unsigned char here because
  1716. // the 'X' format character will be tempted to treat it as an unsigned
  1717. // int...which causes problem when messing with 0x80-0xFF chars.
  1718. // We also need space for a null as apr_snprintf will write one.
  1719. stringbuf_ensure(retstr, retstr->len + 4);
  1720. apr_snprintf(retstr->data + retstr->len, 4, "%%%02X", (unsigned char)c);
  1721. retstr->len += 3;
  1722. // Finally, update our copy counter.
  1723. copied = i + 1;
  1724. }
  1725. // If we didn't encode anything, we don't need to duplicate the string.
  1726. if (retstr->len == 0)
  1727. return path;
  1728. // Anything left to copy?
  1729. if (i - copied)
  1730. stringbuf_appendbytes(retstr, path + copied, i - copied);
  1731. // retstr is null-terminated either by apr_snprintf or the stringbuf
  1732. // functions.
  1733. return retstr->data;
  1734. }
  1735. static const char *
  1736. path_uri_decode(
  1737. const char * path,
  1738. apr_pool_t * pool)
  1739. {
  1740. stringbuf_t * retstr = NULL;
  1741. size_t i = 0;
  1742. bool query_start = FALSE;
  1743. // avoid repeated realloc
  1744. retstr = stringbuf_create_ensure(strlen(path) + 1, pool);
  1745. retstr->len = 0;
  1746. for (i = 0; path[i]; i++)
  1747. {
  1748. char c = path[i];
  1749. if (c == '?')
  1750. {
  1751. // Mark the start of the query string, if it exists.
  1752. query_start = TRUE;
  1753. }
  1754. else if (c == '+' && query_start)
  1755. {
  1756. // Only do this if we are into the query string.
  1757. // RFC 2396, section 3.3
  1758. c = ' ';
  1759. }
  1760. else if (c == '%' && ctype_isxdigit(path[i + 1]) && ctype_isxdigit(path[i+2]))
  1761. {
  1762. char digitz[3];
  1763. digitz[0] = path[++i];
  1764. digitz[1] = path[++i];
  1765. digitz[2] = '\0';
  1766. c = (char)(strtol(digitz, NULL, 16));
  1767. }
  1768. retstr->data[retstr->len++] = c;
  1769. }
  1770. // Null-terminate this bad-boy.
  1771. retstr->data[retstr->len] = 0;
  1772. return retstr->data;
  1773. }
  1774. static const char *
  1775. path_uri_encode(
  1776. const char * path,
  1777. apr_pool_t * pool)
  1778. {
  1779. const char * ret = uri_escape(path, uri_char_validity, pool);
  1780. // Our interface guarantees a copy.
  1781. if (ret == path)
  1782. return apr_pstrdup(pool, path);
  1783. else
  1784. return ret;
  1785. }
  1786. static char *
  1787. path_join(
  1788. const char * base,
  1789. const char * component,
  1790. apr_pool_t * pool)
  1791. {
  1792. apr_size_t blen = strlen(base);
  1793. apr_size_t clen = strlen(component);
  1794. char * path = NULL;
  1795. // assert(path_is_canonical(base, pool));
  1796. // assert(path_is_canonical(component, pool));
  1797. // If the component is absolute, then return it.
  1798. if (*component == '/')
  1799. return (char *)apr_pmemdup(pool, component, clen + 1);
  1800. // If either is empty return the other
  1801. if (WEBDAV_PATH_IS_EMPTY(base))
  1802. return (char *)apr_pmemdup(pool, component, clen + 1);
  1803. if (WEBDAV_PATH_IS_EMPTY(component))
  1804. return (char *)apr_pmemdup(pool, base, blen + 1);
  1805. if ((blen == 1) && (base[0] == '/'))
  1806. blen = 0; // Ignore base, just return separator + component
  1807. // Construct the new, combined path.
  1808. path = (char *)apr_pcalloc(pool, blen + 1 + clen + 1);
  1809. memcpy(path, base, blen);
  1810. path[blen] = '/';
  1811. memcpy(path + blen + 1, component, clen + 1);
  1812. return path;
  1813. }
  1814. static const char *
  1815. path_url_add_component2(
  1816. const char * url,
  1817. const char * component,
  1818. apr_pool_t * pool)
  1819. {
  1820. // = path_uri_encode() but without always copying
  1821. component = uri_escape(component, uri_char_validity, pool);
  1822. return path_join(url, component, pool);
  1823. }
  1824. // Get APR's internal path encoding.
  1825. static error_t
  1826. get_path_encoding(
  1827. bool * path_is_utf8,
  1828. apr_pool_t * pool)
  1829. {
  1830. apr_status_t apr_err = 0;
  1831. int encoding_style = 0;
  1832. apr_err = apr_filepath_encoding(&encoding_style, pool);
  1833. if (apr_err)
  1834. return error_wrap_apr(apr_err,
  1835. "Can't determine the native path encoding");
  1836. // What to do about APR_FILEPATH_ENCODING_UNKNOWN?
  1837. // Well, for now we'll just punt to the utf_ functions;
  1838. // those will at least do the ASCII-subset check.
  1839. *path_is_utf8 = (encoding_style == APR_FILEPATH_ENCODING_UTF8);
  1840. return WEBDAV_NO_ERROR;
  1841. }
  1842. static error_t
  1843. path_cstring_to_utf8(
  1844. const char ** path_utf8,
  1845. const char * path_apr,
  1846. apr_pool_t * pool)
  1847. {
  1848. bool path_is_utf8 = FALSE;
  1849. WEBDAV_ERR(get_path_encoding(&path_is_utf8, pool));
  1850. if (path_is_utf8)
  1851. {
  1852. *path_utf8 = apr_pstrdup(pool, path_apr);
  1853. return WEBDAV_NO_ERROR;
  1854. }
  1855. else
  1856. return utf_cstring_to_utf8(path_utf8, path_apr, pool);
  1857. }
  1858. static apr_size_t
  1859. path_component_count(
  1860. const char * path)
  1861. {
  1862. if (!path) return 0;
  1863. apr_size_t count = 0;
  1864. while (*path)
  1865. {
  1866. const char * start;
  1867. while (*path == '/')
  1868. ++path;
  1869. start = path;
  1870. while (*path && (*path != '/'))
  1871. ++path;
  1872. if (path != start)
  1873. ++count;
  1874. }
  1875. return count;
  1876. }
  1877. // Return the length of substring necessary to encompass the entire
  1878. // previous path segment in PATH, which should be a LEN byte string.
  1879. // A trailing slash will not be included in the returned length except
  1880. // in the case in which PATH is absolute and there are no more
  1881. // previous segments.
  1882. static apr_size_t
  1883. previous_segment(
  1884. const char * path,
  1885. apr_size_t len)
  1886. {
  1887. if (len == 0)
  1888. return 0;
  1889. while ((len > 0) && (path[--len] != '/'))
  1890. ;
  1891. if ((len == 0) && (path[0] == '/'))
  1892. return 1;
  1893. else
  1894. return len;
  1895. }
  1896. static void
  1897. path_remove_component(
  1898. stringbuf_t * path)
  1899. {
  1900. path->len = previous_segment(path->data, path->len);
  1901. path->data[path->len] = '\0';
  1902. }
  1903. static void
  1904. path_remove_components(
  1905. stringbuf_t * path,
  1906. apr_size_t n)
  1907. {
  1908. while (n > 0)
  1909. {
  1910. path_remove_component(path);
  1911. n--;
  1912. }
  1913. }
  1914. static error_t
  1915. path_cstring_from_utf8(
  1916. const char ** path_apr,
  1917. const char * path_utf8,
  1918. apr_pool_t * pool)
  1919. {
  1920. bool path_is_utf8 = FALSE;
  1921. WEBDAV_ERR(get_path_encoding(&path_is_utf8, pool));
  1922. if (path_is_utf8)
  1923. {
  1924. *path_apr = apr_pstrdup(pool, path_utf8);
  1925. return WEBDAV_NO_ERROR;
  1926. }
  1927. else
  1928. return utf_cstring_from_utf8(path_apr, path_utf8, pool);
  1929. }
  1930. static bool
  1931. path_is_backpath_present(
  1932. const char * path)
  1933. {
  1934. size_t len;
  1935. // 0 and 1-length paths do not have a backpath
  1936. if ((path[0] == '\0') || (path[1] == '\0'))
  1937. return FALSE;
  1938. // Handle ".." or a leading "../"
  1939. if ((path[0] == '.') && (path[1] == '.') && ((path[2] == '\0') || (path[2] == '/')))
  1940. return TRUE;
  1941. // Paths of length 2 (at this point) have no backpath present.
  1942. if (path[2] == '\0')
  1943. return FALSE;
  1944. // If any segment is "..", then a backpath is present.
  1945. if (strstr(path, "/../") != NULL)
  1946. return TRUE;
  1947. // Does the path end in "/.." ?
  1948. len = strlen(path);
  1949. return (path[len - 3] == '/') && (path[len - 2] == '.') && (path[len - 1] == '.');
  1950. }
  1951. //------------------------------------------------------------------------------
  1952. // from svn_client.h
  1953. typedef error_t (*client_list_func_t)(
  1954. void * baton,
  1955. const char * path,
  1956. const dirent_t * dirent,
  1957. const char * abs_path,
  1958. apr_pool_t * pool);
  1959. typedef struct client_ctx_t
  1960. {
  1961. auth_baton_t * auth_baton;
  1962. cancel_func_t cancel_func;
  1963. void * cancel_baton;
  1964. progress_notify_func_t progress_func;
  1965. void * progress_baton;
  1966. const char * client_name;
  1967. } client_ctx_t;
  1968. //------------------------------------------------------------------------------
  1969. // from win32_xlate.c
  1970. static apr_status_t
  1971. subr_win32_xlate_to_stringbuf(// win32_xlate_t *handle,
  1972. const char * src_data,
  1973. apr_size_t src_length,
  1974. stringbuf_t ** dest,
  1975. apr_pool_t * pool)
  1976. {
  1977. WCHAR * wide_str = NULL;
  1978. int retval = 0, wide_size = 0;
  1979. if (src_length == 0)
  1980. {
  1981. *dest = stringbuf_create("", pool);
  1982. return APR_SUCCESS;
  1983. }
  1984. int from_page_id = CP_ACP;
  1985. retval = MultiByteToWideChar(from_page_id, // CP_UTF8, // handle->from_page_id,
  1986. 0, src_data, (int)src_length, NULL, 0);
  1987. if (retval == 0)
  1988. return apr_get_os_error();
  1989. wide_size = retval;
  1990. // Allocate temporary buffer for small strings on stack instead of heap.
  1991. if (wide_size <= MAX_PATH)
  1992. {
  1993. wide_str = static_cast<WCHAR *>(alloca(wide_size * sizeof(WCHAR)));
  1994. }
  1995. else
  1996. {
  1997. wide_str = static_cast<WCHAR *>(apr_pcalloc(pool, wide_size * sizeof(WCHAR)));
  1998. }
  1999. retval = MultiByteToWideChar(from_page_id, // handle->from_page_id,
  2000. 0, src_data, (int)src_length, wide_str, wide_size);
  2001. if (retval == 0)
  2002. return apr_get_os_error();
  2003. int to_page_id = CP_UTF8;
  2004. retval = WideCharToMultiByte(to_page_id, // handle->to_page_id,
  2005. 0, wide_str, wide_size, NULL, 0, NULL, NULL);
  2006. if (retval == 0)
  2007. return apr_get_os_error();
  2008. // Ensure that buffer is enough to hold result string and termination
  2009. // character.
  2010. *dest = stringbuf_create_ensure(retval + 1, pool);
  2011. (*dest)->len = retval;
  2012. retval = WideCharToMultiByte(to_page_id, // handle->to_page_id,
  2013. 0, wide_str, wide_size, (*dest)->data, (int)(*dest)->len, NULL, NULL);
  2014. if (retval == 0)
  2015. return apr_get_os_error();
  2016. (*dest)->len = retval;
  2017. return APR_SUCCESS;
  2018. }
  2019. static apr_status_t
  2020. utf8_to_unicode(
  2021. WCHAR ** retstr,
  2022. const char * srcstr,
  2023. apr_pool_t * pool)
  2024. {
  2025. /*apr_size_t retlen = 0;
  2026. apr_size_t srcremains = strlen(srcstr) + 1;
  2027. *retstr = static_cast<WCHAR *>(apr_pcalloc(pool, srcremains * 4));
  2028. apr_status_t rv;
  2029. if (rv = apr_conv_utf8_to_ucs2(srcstr, &srcremains, *retstr, &retlen)) {
  2030. return (rv == APR_INCOMPLETE) ? APR_EINVAL : rv;
  2031. }
  2032. if (srcremains) {
  2033. return APR_ENAMETOOLONG;
  2034. }*/
  2035. WCHAR * wide_str = NULL;
  2036. int retval = 0, wide_size = 0;
  2037. apr_size_t src_length = strlen(srcstr);
  2038. if (src_length == 0)
  2039. {
  2040. *retstr = L"";
  2041. return APR_SUCCESS;
  2042. }
  2043. retval = MultiByteToWideChar(CP_UTF8, // handle->from_page_id,
  2044. 0, srcstr, (int)src_length, NULL, 0);
  2045. if (retval == 0)
  2046. return apr_get_os_error();
  2047. wide_size = retval;
  2048. wide_str = static_cast<WCHAR *>(apr_pcalloc(pool, (wide_size + 1) * sizeof(WCHAR)));
  2049. retval = MultiByteToWideChar(CP_UTF8, // handle->from_page_id,
  2050. 0, srcstr, (int)src_length, wide_str, wide_size);
  2051. if (retval == 0)
  2052. return apr_get_os_error();
  2053. *retstr = wide_str;
  2054. (*retstr)[wide_size] = L'\0';
  2055. return APR_SUCCESS;
  2056. }
  2057. //------------------------------------------------------------------------------
  2058. // from utf.c
  2059. // Verify that the sequence DATA of length LEN is valid UTF-8.
  2060. // If it is not, return an error with code APR_EINVAL.
  2061. static error_t
  2062. check_utf8(
  2063. const char * data,
  2064. apr_size_t len,
  2065. apr_pool_t * pool)
  2066. {
  2067. // TODO: if (!utf_is_valid(data, len)))
  2068. // return invalid_utf8(data, len, pool);
  2069. return WEBDAV_NO_ERROR;
  2070. }
  2071. // Convert SRC_LENGTH bytes of SRC_DATA in NODE->handle, store the result
  2072. // in *DEST, which is allocated in POOL.
  2073. static error_t
  2074. convert_to_stringbuf(// xlate_handle_node_t *node,
  2075. const char * src_data,
  2076. apr_size_t src_length,
  2077. stringbuf_t ** dest,
  2078. apr_pool_t * pool)
  2079. {
  2080. apr_status_t apr_err = 0;
  2081. apr_err = subr_win32_xlate_to_stringbuf(// (win32_xlate_t *) node->handle,
  2082. src_data, src_length,
  2083. dest, pool);
  2084. // If we exited the loop with an error, return the error.
  2085. if (apr_err)
  2086. {
  2087. const char * errstr = NULL;
  2088. error_t err = 0;
  2089. // Can't use error_wrap_apr here because it calls functions in
  2090. // this file, leading to infinite recursion.
  2091. errstr = apr_psprintf(pool, "Can't convert string"); // from native encoding to '%s':"),
  2092. err = error_create(apr_err, NULL, "");
  2093. return error_create(apr_err, &err, errstr);
  2094. }
  2095. // Else, exited due to success. Trim the result buffer down to the
  2096. // right length.
  2097. (*dest)->data[(*dest)->len] = '\0';
  2098. return WEBDAV_NO_ERROR;
  2099. }
  2100. // Common implementation for utf_cstring_to_utf8,
  2101. // utf_cstring_to_utf8_ex, utf_cstring_from_utf8 and
  2102. // utf_cstring_from_utf8_ex. Convert SRC to DEST using NODE->handle as
  2103. // the translator and allocating from POOL.
  2104. static error_t
  2105. convert_cstring(
  2106. const char ** dest,
  2107. const char * src,
  2108. apr_pool_t * pool)
  2109. {
  2110. stringbuf_t * destbuf;
  2111. WEBDAV_ERR(convert_to_stringbuf(// node,
  2112. src, strlen(src), &destbuf, pool));
  2113. *dest = destbuf->data;
  2114. return WEBDAV_NO_ERROR;
  2115. }
  2116. // Verify that the NULL terminated sequence DATA is valid UTF-8.
  2117. // If it is not, return an error with code APR_EINVAL.
  2118. static error_t
  2119. check_cstring_utf8(
  2120. const char * data,
  2121. apr_pool_t * pool)
  2122. {
  2123. // TODO: if (!utf_cstring_is_valid(data))
  2124. // return invalid_utf8(data, strlen(data), pool);
  2125. return WEBDAV_NO_ERROR;
  2126. }
  2127. static error_t
  2128. utf_cstring_to_utf8(
  2129. const char ** dest,
  2130. const char * src,
  2131. apr_pool_t * pool)
  2132. {
  2133. // TODO: implement
  2134. error_t err = convert_cstring(dest, src, // node,
  2135. pool);
  2136. WEBDAV_ERR(err);
  2137. return check_cstring_utf8(*dest, pool);
  2138. }
  2139. static error_t
  2140. utf_cstring_from_utf8(
  2141. const char ** dest,
  2142. const char * src,
  2143. apr_pool_t * pool)
  2144. {
  2145. WEBDAV_ERR(check_utf8(src, strlen(src), pool));
  2146. error_t err = convert_cstring(dest, src, pool);
  2147. return err;
  2148. }
  2149. //------------------------------------------------------------------------------
  2150. // from xml.c
  2151. static const char *
  2152. xml_get_attr_value(
  2153. const char * name,
  2154. const char ** atts)
  2155. {
  2156. while (atts && (*atts))
  2157. {
  2158. if (strcmp(atts[0], name) == 0)
  2159. return atts[1];
  2160. else
  2161. atts += 2; // continue looping
  2162. }
  2163. // Else no such attribute name seen.
  2164. return NULL;
  2165. }
  2166. //------------------------------------------------------------------------------
  2167. // from apr_base64.c
  2168. static const char basis_64[] =
  2169. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  2170. // This is the same as apr_base64_encode() except on EBCDIC machines, where
  2171. // the conversion of the input to ascii is left out.
  2172. static int
  2173. apr_base64_encode_binary(
  2174. char * encoded,
  2175. const unsigned char * string,
  2176. int len)
  2177. {
  2178. int i;
  2179. char * p;
  2180. p = encoded;
  2181. for (i = 0; i < len - 2; i += 3)
  2182. {
  2183. *p++ = basis_64[(string[i] >> 2) & 0x3F];
  2184. *p++ = basis_64[((string[i] & 0x3) << 4) |
  2185. ((int)(string[i + 1] & 0xF0) >> 4)];
  2186. *p++ = basis_64[((string[i + 1] & 0xF) << 2) |
  2187. ((int)(string[i + 2] & 0xC0) >> 6)];
  2188. *p++ = basis_64[string[i + 2] & 0x3F];
  2189. }
  2190. if (i < len)
  2191. {
  2192. *p++ = basis_64[(string[i] >> 2) & 0x3F];
  2193. if (i == (len - 1))
  2194. {
  2195. *p++ = basis_64[((string[i] & 0x3) << 4)];
  2196. *p++ = '=';
  2197. }
  2198. else
  2199. {
  2200. *p++ = basis_64[((string[i] & 0x3) << 4) |
  2201. ((int)(string[i + 1] & 0xF0) >> 4)];
  2202. *p++ = basis_64[((string[i + 1] & 0xF) << 2)];
  2203. }
  2204. *p++ = '=';
  2205. }
  2206. *p++ = '\0';
  2207. return (int)(p - encoded);
  2208. }
  2209. static int
  2210. apr_base64_encode(
  2211. char * encoded,
  2212. const char * string,
  2213. int len)
  2214. {
  2215. return apr_base64_encode_binary(encoded, (const unsigned char *) string, len);
  2216. }
  2217. static int
  2218. apr_base64_encode_len(int len)
  2219. {
  2220. return ((len + 2) / 3 * 4) + 1;
  2221. }
  2222. // aaaack but it's fast and const should make it shared text page.
  2223. static const unsigned char pr2six[256] =
  2224. {
  2225. // ASCII table
  2226. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  2227. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  2228. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
  2229. 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
  2230. 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
  2231. 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
  2232. 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
  2233. 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
  2234. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  2235. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  2236. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  2237. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  2238. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  2239. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  2240. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  2241. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
  2242. };
  2243. static int
  2244. apr_base64_decode_len(
  2245. const char * bufcoded)
  2246. {
  2247. int nbytesdecoded;
  2248. register const unsigned char * bufin;
  2249. register apr_size_t nprbytes;
  2250. bufin = (const unsigned char *) bufcoded;
  2251. while (pr2six[*(bufin++)] <= 63);
  2252. nprbytes = (bufin - (const unsigned char *) bufcoded) - 1;
  2253. nbytesdecoded = (((int)nprbytes + 3) / 4) * 3;
  2254. return nbytesdecoded + 1;
  2255. }
  2256. // This is the same as apr_base64_decode() except on EBCDIC machines, where
  2257. // the conversion of the output to ebcdic is left out.
  2258. static int
  2259. apr_base64_decode_binary(
  2260. unsigned char * bufplain,
  2261. const char * bufcoded)
  2262. {
  2263. int nbytesdecoded;
  2264. register const unsigned char * bufin;
  2265. register unsigned char * bufout;
  2266. register apr_size_t nprbytes;
  2267. bufin = (const unsigned char *) bufcoded;
  2268. while (pr2six[*(bufin++)] <= 63);
  2269. nprbytes = (bufin - (const unsigned char *) bufcoded) - 1;
  2270. nbytesdecoded = (((int)nprbytes + 3) / 4) * 3;
  2271. bufout = (unsigned char *) bufplain;
  2272. bufin = (const unsigned char *) bufcoded;
  2273. while (nprbytes > 4)
  2274. {
  2275. *(bufout++) =
  2276. (unsigned char)((pr2six[*bufin] << 2) | (pr2six[bufin[1]] >> 4));
  2277. *(bufout++) =
  2278. (unsigned char)((pr2six[bufin[1]] << 4) | (pr2six[bufin[2]] >> 2));
  2279. *(bufout++) =
  2280. (unsigned char)((pr2six[bufin[2]] << 6) | pr2six[bufin[3]]);
  2281. bufin += 4;
  2282. nprbytes -= 4;
  2283. }
  2284. // Note: (nprbytes == 1) would be an error, so just ignore that case
  2285. if (nprbytes > 1)
  2286. {
  2287. *(bufout++) =
  2288. (unsigned char)((pr2six[*bufin] << 2) | (pr2six[bufin[1]] >> 4));
  2289. }
  2290. if (nprbytes > 2)
  2291. {
  2292. *(bufout++) =
  2293. (unsigned char)((pr2six[bufin[1]] << 4) | (pr2six[bufin[2]] >> 2));
  2294. }
  2295. if (nprbytes > 3)
  2296. {
  2297. *(bufout++) =
  2298. (unsigned char)((pr2six[bufin[2]] << 6) | pr2six[bufin[3]]);
  2299. }
  2300. nbytesdecoded -= (4 - (int)nprbytes) & 3;
  2301. return nbytesdecoded;
  2302. }
  2303. static int
  2304. apr_base64_decode(
  2305. char * bufplain,
  2306. const char * bufcoded)
  2307. {
  2308. int len = apr_base64_decode_binary((unsigned char *) bufplain, bufcoded);
  2309. bufplain[len] = '\0';
  2310. return len;
  2311. }
  2312. //---------------------------------------------------------------------------
  2313. // from user.c
  2314. // Get the current user's name from the OS
  2315. static const char *
  2316. get_os_username(
  2317. apr_pool_t * pool)
  2318. {
  2319. #if APR_HAS_USER
  2320. char * username;
  2321. apr_uid_t uid;
  2322. apr_gid_t gid;
  2323. if (apr_uid_current(&uid, &gid, pool) == APR_SUCCESS &&
  2324. apr_uid_name_get(&username, uid, pool) == APR_SUCCESS)
  2325. return username;
  2326. #endif
  2327. return NULL;
  2328. }
  2329. // Return a UTF8 version of STR, or NULL on error.
  2330. // Use POOL for any necessary allocation.
  2331. static const char *
  2332. utf8_or_nothing(
  2333. const char * str,
  2334. apr_pool_t * pool)
  2335. {
  2336. if (str)
  2337. {
  2338. const char * utf8_str;
  2339. error_t err = utf_cstring_to_utf8(&utf8_str, str, pool);
  2340. if (!err)
  2341. return utf8_str;
  2342. error_clear(&err);
  2343. }
  2344. return NULL;
  2345. }
  2346. static const char *
  2347. user_get_name(
  2348. apr_pool_t * pool)
  2349. {
  2350. const char * username = get_os_username(pool);
  2351. return utf8_or_nothing(username, pool);
  2352. }
  2353. //---------------------------------------------------------------------------
  2354. // from sorts.c
  2355. typedef struct sort_item_t
  2356. {
  2357. const void * key;
  2358. apr_ssize_t klen;
  2359. void * value;
  2360. } sort_item_t;
  2361. static int
  2362. sort_compare_items_lexically(
  2363. const sort_item_t * a,
  2364. const sort_item_t * b)
  2365. {
  2366. // Compare bytes of a's key and b's key up to the common length.
  2367. apr_size_t len = (a->klen < b->klen) ? a->klen : b->klen;
  2368. int val = memcmp(a->key, b->key, len);
  2369. if (val != 0)
  2370. return val;
  2371. // They match up until one of them ends; whichever is longer is greater.
  2372. return (a->klen < b->klen) ? -1 : (a->klen > b->klen) ? 1 : 0;
  2373. }
  2374. static apr_array_header_t *
  2375. sort_hash(apr_hash_t * ht,
  2376. int (*comparison_func)(const sort_item_t *,
  2377. const sort_item_t *),
  2378. apr_pool_t * pool)
  2379. {
  2380. apr_array_header_t * ary = NULL;
  2381. bool sorted = FALSE;
  2382. sort_item_t * prev_item = NULL;
  2383. // allocate an array with enough elements to hold all the keys.
  2384. ary = apr_array_make(pool, apr_hash_count(ht), sizeof(sort_item_t));
  2385. // loop over hash table and push all keys into the array
  2386. sorted = TRUE;
  2387. prev_item = NULL;
  2388. for (apr_hash_index_t * hi = apr_hash_first(pool, ht); hi;
  2389. hi = apr_hash_next(hi))
  2390. {
  2391. sort_item_t * item = static_cast<sort_item_t *>(apr_array_push(ary));
  2392. apr_hash_this(hi, &item->key, &item->klen, &item->value);
  2393. if (prev_item == NULL)
  2394. {
  2395. prev_item = item;
  2396. continue;
  2397. }
  2398. if (sorted)
  2399. {
  2400. sorted = (comparison_func(prev_item, item) < 0);
  2401. prev_item = item;
  2402. }
  2403. }
  2404. // quicksort the array if it isn't already sorted.
  2405. if (!sorted)
  2406. qsort(ary->elts, ary->nelts, ary->elt_size,
  2407. (int ( *)(const void *, const void *))comparison_func);
  2408. return ary;
  2409. }
  2410. //---------------------------------------------------------------------------
  2411. // from svn_config.h
  2412. #define WEBDAV_CONFIG_TRUE "TRUE"
  2413. #define WEBDAV_CONFIG_FALSE "FALSE"
  2414. #define WEBDAV_CONFIG_ASK "ASK"
  2415. // Default values for some options. Should be passed as default values
  2416. // to config_get and friends, instead of hard-coding the defaults in
  2417. // multiple places.
  2418. #define WEBDAV_CONFIG_DEFAULT_OPTION_STORE_PASSWORDS TRUE
  2419. #define WEBDAV_CONFIG_DEFAULT_OPTION_STORE_PLAINTEXT_PASSWORDS WEBDAV_CONFIG_ASK
  2420. #define WEBDAV_CONFIG_DEFAULT_OPTION_STORE_AUTH_CREDS TRUE
  2421. #define WEBDAV_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP TRUE
  2422. #define WEBDAV_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT \
  2423. WEBDAV_CONFIG_ASK
  2424. //---------------------------------------------------------------------------
  2425. // from svn_auth.h
  2426. // Certificate is not yet valid.
  2427. #define WEBDAV_AUTH_SSL_NOTYETVALID 0x00000001
  2428. // Certificate has expired.
  2429. #define WEBDAV_AUTH_SSL_EXPIRED 0x00000002
  2430. // Certificate's CN (hostname) does not match the remote hostname.
  2431. #define WEBDAV_AUTH_SSL_CNMISMATCH 0x00000004
  2432. // Certificate authority is unknown (i.e. not trusted)
  2433. #define WEBDAV_AUTH_SSL_UNKNOWNCA 0x00000008
  2434. // Other failure. This can happen if neon has introduced a new
  2435. // failure bit that we do not handle yet.
  2436. #define WEBDAV_AUTH_SSL_OTHER 0x40000000
  2437. #define AUTH_CRED_SSL_CLIENT_CERT_PW "ssl.client-passphrase"
  2438. #define AUTH_CRED_SSL_CLIENT_CERT "ssl.client-cert"
  2439. // The auth-hash prefix indicating that the parameter is global.
  2440. #define AUTH_PARAM_PREFIX "webdav:auth:"
  2441. // The following property is for SSL server cert providers. This
  2442. // provides a pointer to an apr_uint32_t containing the failures
  2443. // detected by the certificate validator.
  2444. #define AUTH_PARAM_SSL_SERVER_FAILURES AUTH_PARAM_PREFIX \
  2445. "ssl:failures"
  2446. // The following property is for SSL server cert providers. This
  2447. // provides the cert info (auth_ssl_server_cert_info_t).
  2448. #define AUTH_PARAM_SSL_SERVER_CERT_INFO AUTH_PARAM_PREFIX \
  2449. "ssl:cert-info"
  2450. #define AUTH_CRED_SSL_SERVER_TRUST "webdav.ssl.server"
  2451. #define AUTH_CRED_SIMPLE "webdav.simple"
  2452. #define WEBDAV_AUTH_CRED_USERNAME "webdav.username"
  2453. #define WEBDAV_AUTH_PARAM_DEFAULT_USERNAME AUTH_PARAM_PREFIX "username"
  2454. #define WEBDAV_AUTH_PARAM_DEFAULT_PASSWORD AUTH_PARAM_PREFIX "password"
  2455. #define WEBDAV_AUTH_PARAM_NON_INTERACTIVE AUTH_PARAM_PREFIX "non-interactive"
  2456. #define WEBDAV_AUTH_PARAM_DONT_STORE_PASSWORDS AUTH_PARAM_PREFIX \
  2457. "dont-store-passwords"
  2458. #define WEBDAV_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS AUTH_PARAM_PREFIX \
  2459. "store-plaintext-passwords"
  2460. #define WEBDAV_AUTH_PARAM_DONT_STORE_SSL_CLIENT_CERT_PP \
  2461. AUTH_PARAM_PREFIX "dont-store-ssl-client-cert-pp"
  2462. #define WEBDAV_AUTH_PARAM_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT \
  2463. AUTH_PARAM_PREFIX "store-ssl-client-cert-pp-plaintext"
  2464. #define WEBDAV_AUTH_PARAM_NO_AUTH_CACHE AUTH_PARAM_PREFIX "no-auth-cache"
  2465. #define WEBDAV_AUTH_SIMPLE_PASSWORD_TYPE "simple"
  2466. #define WEBDAV_AUTH_WINCRYPT_PASSWORD_TYPE "wincrypt"
  2467. // This effectively defines a single table. Every provider in this
  2468. // array returns the same kind of credentials.
  2469. typedef struct provider_set_t
  2470. {
  2471. // ordered array of auth_provider_object_t
  2472. apr_array_header_t * providers;
  2473. } provider_set_t;
  2474. // Abstracted iteration baton
  2475. struct auth_iterstate_t
  2476. {
  2477. provider_set_t * table; // the table being searched
  2478. int provider_idx; // the current provider (row)
  2479. bool got_first; // did we get the provider's first creds?
  2480. void * provider_iter_baton; // the provider's own iteration context
  2481. const char * realmstring; // The original realmstring passed in
  2482. const char * cache_key; // key to use in auth_baton's creds_cache
  2483. auth_baton_t * auth_baton; // the original auth_baton.
  2484. };
  2485. // The main auth baton.
  2486. typedef struct auth_baton_t
  2487. {
  2488. // a collection of tables. maps cred_kind -> provider_set
  2489. apr_hash_t * tables;
  2490. // the pool I'm allocated in.
  2491. apr_pool_t * pool;
  2492. // run-time parameters needed by providers.
  2493. apr_hash_t * parameters;
  2494. // run-time credentials cache.
  2495. apr_hash_t * creds_cache;
  2496. } auth_baton_t;
  2497. // The main authentication "provider" vtable.
  2498. typedef struct auth_provider_t
  2499. {
  2500. // The kind of credentials this provider knows how to retrieve.
  2501. const char * cred_kind;
  2502. error_t (*first_credentials)(void ** credentials,
  2503. void ** iter_baton,
  2504. void * provider_baton,
  2505. apr_hash_t * parameters,
  2506. const char * realmstring,
  2507. apr_pool_t * pool);
  2508. error_t (*next_credentials)(void ** credentials,
  2509. void * iter_baton,
  2510. void * provider_baton,
  2511. apr_hash_t * parameters,
  2512. const char * realmstring,
  2513. apr_pool_t * pool);
  2514. error_t (*save_credentials)(bool * saved,
  2515. void * credentials,
  2516. void * provider_baton,
  2517. apr_hash_t * parameters,
  2518. const char * realmstring,
  2519. apr_pool_t * pool);
  2520. } auth_provider_t;
  2521. // A provider object, ready to be put into an array and given to
  2522. // create_baton_open().
  2523. typedef struct auth_provider_object_t
  2524. {
  2525. const auth_provider_t * vtable;
  2526. void * provider_baton;
  2527. } auth_provider_object_t;
  2528. typedef error_t (*auth_plaintext_prompt_func_t)(
  2529. bool * may_save_plaintext,
  2530. const char * realmstring,
  2531. void * baton,
  2532. apr_pool_t * pool);
  2533. typedef error_t (*auth_password_get_t)(
  2534. bool * done,
  2535. const char ** password,
  2536. apr_hash_t * creds,
  2537. const char * realmstring,
  2538. const char * username,
  2539. apr_hash_t * parameters,
  2540. bool non_interactive,
  2541. apr_pool_t * pool);
  2542. typedef struct auth_cred_simple_t
  2543. {
  2544. // Username
  2545. const char * username;
  2546. // Password
  2547. const char * password;
  2548. bool may_save;
  2549. } auth_cred_simple_t;
  2550. typedef struct auth_cred_username_t
  2551. {
  2552. // Username
  2553. const char * username;
  2554. bool may_save;
  2555. } auth_cred_username_t;
  2556. typedef error_t (*auth_password_set_t)(
  2557. bool * done,
  2558. apr_hash_t * creds,
  2559. const char * realmstring,
  2560. const char * username,
  2561. const char * password,
  2562. apr_hash_t * parameters,
  2563. bool non_interactive,
  2564. apr_pool_t * pool);
  2565. // AUTH_CRED_SSL_CLIENT_CERT credentials.
  2566. typedef struct auth_cred_ssl_client_cert_t
  2567. {
  2568. // Absolute path to the certificate file
  2569. const char * cert_file;
  2570. bool may_save;
  2571. } auth_cred_ssl_client_cert_t;
  2572. typedef error_t (*auth_ssl_client_cert_prompt_func_t)(
  2573. auth_cred_ssl_client_cert_t ** cred,
  2574. void * baton,
  2575. const char * realm,
  2576. bool may_save,
  2577. apr_pool_t * pool);
  2578. typedef error_t (*auth_plaintext_passphrase_prompt_func_t)(
  2579. bool * may_save_plaintext,
  2580. const char * realmstring,
  2581. void * baton,
  2582. apr_pool_t * pool);
  2583. // AUTH_CRED_SSL_CLIENT_CERT_PW credentials.
  2584. typedef struct auth_cred_ssl_client_cert_pw_t
  2585. {
  2586. // Certificate password
  2587. const char * password;
  2588. bool may_save;
  2589. } auth_cred_ssl_client_cert_pw_t;
  2590. // AUTH_CRED_SSL_SERVER_TRUST credentials.
  2591. typedef struct auth_cred_ssl_server_trust_t
  2592. {
  2593. bool may_save;
  2594. // Bit mask of the accepted failures
  2595. apr_uint32_t accepted_failures;
  2596. } auth_cred_ssl_server_trust_t;
  2597. // SSL server certificate information used by
  2598. // AUTH_CRED_SSL_SERVER_TRUST providers.
  2599. typedef struct auth_ssl_server_cert_info_t
  2600. {
  2601. // Primary CN
  2602. const char * hostname;
  2603. // ASCII fingerprint
  2604. const char * fingerprint;
  2605. // ASCII date from which the certificate is valid
  2606. const char * valid_from;
  2607. // ASCII date until which the certificate is valid
  2608. const char * valid_until;
  2609. // DN of the certificate issuer
  2610. const char * issuer_dname;
  2611. // Base-64 encoded DER certificate representation
  2612. const char * ascii_cert;
  2613. } auth_ssl_server_cert_info_t;
  2614. typedef error_t (*auth_ssl_client_cert_pw_prompt_func_t)(
  2615. auth_cred_ssl_client_cert_pw_t ** cred,
  2616. void * baton,
  2617. const char * realm,
  2618. bool may_save,
  2619. apr_pool_t * pool);
  2620. typedef error_t (*auth_ssl_server_trust_prompt_func_t)(
  2621. auth_cred_ssl_server_trust_t ** cred,
  2622. void * baton,
  2623. const char * realm,
  2624. apr_uint32_t failures,
  2625. const auth_ssl_server_cert_info_t * cert_info,
  2626. bool may_save,
  2627. apr_pool_t * pool);
  2628. typedef error_t (*auth_simple_prompt_func_t)(
  2629. auth_cred_simple_t ** cred,
  2630. void * baton,
  2631. const char * realm,
  2632. const char * username,
  2633. bool may_save,
  2634. apr_pool_t * pool);
  2635. typedef error_t (*auth_username_prompt_func_t)(
  2636. auth_cred_username_t ** cred,
  2637. void * baton,
  2638. const char * realm,
  2639. bool may_save,
  2640. apr_pool_t * pool);
  2641. //---------------------------------------------------------------------------
  2642. // from config_auth.c
  2643. #define CONST_FS_KEY "fs"
  2644. #define CONST_FINGERPRINT_KEY "fingerprint"
  2645. // The keys that will be stored on disk. These serve the same role as
  2646. // similar constants in other providers.
  2647. #define AUTHN_ASCII_CERT_KEY "ascii_cert"
  2648. #define AUTHN_FAILURES_KEY "failures"
  2649. static const char CertificateStorageKey[] = "HttpsCertificates";
  2650. static error_t
  2651. config_read_auth_data(
  2652. apr_hash_t ** hash,
  2653. const char * cred_kind,
  2654. const char * realmstring,
  2655. TWebDAVFileSystem * fs,
  2656. apr_pool_t * pool)
  2657. {
  2658. const char * subkey = CertificateStorageKey;
  2659. THierarchicalStorage * Storage = NULL;
  2660. WEBDAV_ERR(fs->CreateStorage(Storage));
  2661. assert(Storage);
  2662. std::unique_ptr<THierarchicalStorage> StoragePtr;
  2663. StoragePtr.reset(Storage);
  2664. Storage->AccessMode = smRead;
  2665. if (!Storage->OpenSubKey(UnicodeString(subkey), false))
  2666. return WEBDAV_ERR_BAD_PARAM;
  2667. *hash = apr_hash_make(pool);
  2668. TStrings * Keys = new TStringList();
  2669. try
  2670. {
  2671. Storage->GetValueNames(Keys);
  2672. for (int Index = 0; Index < Keys->Count; ++Index)
  2673. {
  2674. UnicodeString Key = Keys->Strings[Index];
  2675. UnicodeString Value = Storage->ReadStringRaw(Key, L"");
  2676. apr_hash_set(*hash, AUTHN_ASCII_CERT_KEY, APR_HASH_KEY_STRING,
  2677. string_create(AnsiString(Key).c_str(), pool));
  2678. apr_hash_set(*hash, AUTHN_FAILURES_KEY, APR_HASH_KEY_STRING,
  2679. string_createf(pool, "%lu", (unsigned long)
  2680. StrToIntDef(Value, 0)));
  2681. }
  2682. }
  2683. __finally
  2684. {
  2685. delete Keys;
  2686. }
  2687. return WEBDAV_NO_ERROR;
  2688. }
  2689. static error_t
  2690. config_write_auth_data(
  2691. apr_hash_t * hash,
  2692. const char * cred_kind,
  2693. const char * realmstring,
  2694. TWebDAVFileSystem * fs,
  2695. apr_pool_t * pool)
  2696. {
  2697. const char * subkey = CertificateStorageKey;
  2698. assert(fs);
  2699. THierarchicalStorage * Storage = NULL;
  2700. WEBDAV_ERR(fs->CreateStorage(Storage));
  2701. assert(Storage);
  2702. std::unique_ptr<THierarchicalStorage> StoragePtr;
  2703. StoragePtr.reset(Storage);
  2704. Storage->AccessMode = smReadWrite;
  2705. if (!Storage->OpenSubKey(UnicodeString(subkey), true))
  2706. return WEBDAV_ERR_BAD_PARAM;
  2707. string_t * trusted_cert = static_cast<string_t *>(apr_hash_get(hash, AUTHN_ASCII_CERT_KEY,
  2708. APR_HASH_KEY_STRING));
  2709. string_t * failstr = static_cast<string_t *>(apr_hash_get(hash, AUTHN_FAILURES_KEY,
  2710. APR_HASH_KEY_STRING));
  2711. if (trusted_cert && failstr)
  2712. Storage->WriteString(UnicodeString(trusted_cert->data), UnicodeString(failstr->data));
  2713. return WEBDAV_NO_ERROR;
  2714. }
  2715. //---------------------------------------------------------------------------
  2716. // from simple_providers.c
  2717. // The keys that will be stored on disk. These serve the same role as
  2718. // similar constants in other providers.
  2719. #define AUTHN_USERNAME_KEY "username"
  2720. #define AUTHN_PASSWORD_KEY "password"
  2721. #define AUTHN_PASSTYPE_KEY "passtype"
  2722. // Baton type for the simple provider.
  2723. typedef struct simple_provider_baton_t
  2724. {
  2725. auth_plaintext_prompt_func_t plaintext_prompt_func;
  2726. void * prompt_baton;
  2727. // We cache the user's answer to the plaintext prompt, keyed
  2728. // by realm, in case we'll be called multiple times for the
  2729. // same realm.
  2730. apr_hash_t * plaintext_answers;
  2731. } simple_provider_baton_t;
  2732. // Implementation of auth_password_get_t that retrieves
  2733. // the plaintext password from CREDS.
  2734. static error_t
  2735. auth_simple_password_get(
  2736. bool * done,
  2737. const char ** password,
  2738. apr_hash_t * creds,
  2739. const char * realmstring,
  2740. const char * username,
  2741. apr_hash_t * parameters,
  2742. bool non_interactive,
  2743. apr_pool_t * pool)
  2744. {
  2745. *done = FALSE;
  2746. string_t * str = static_cast<string_t *>(apr_hash_get(creds, AUTHN_USERNAME_KEY, APR_HASH_KEY_STRING));
  2747. if (str && username && strcmp(str->data, username) == 0)
  2748. {
  2749. str = static_cast<string_t *>(apr_hash_get(creds, AUTHN_PASSWORD_KEY, APR_HASH_KEY_STRING));
  2750. if (str && str->data)
  2751. {
  2752. *password = str->data;
  2753. *done = TRUE;
  2754. }
  2755. }
  2756. return WEBDAV_NO_ERROR;
  2757. }
  2758. // Implementation of auth_password_set_t that stores
  2759. // the plaintext password in CREDS.
  2760. static error_t
  2761. auth_simple_password_set(
  2762. bool * done,
  2763. apr_hash_t * creds,
  2764. const char * realmstring,
  2765. const char * username,
  2766. const char * password,
  2767. apr_hash_t * parameters,
  2768. bool non_interactive,
  2769. apr_pool_t * pool)
  2770. {
  2771. apr_hash_set(creds, AUTHN_PASSWORD_KEY, APR_HASH_KEY_STRING,
  2772. string_create(password, pool));
  2773. *done = TRUE;
  2774. return WEBDAV_NO_ERROR;
  2775. }
  2776. // Set **USERNAME to the username retrieved from CREDS; ignore
  2777. // other parameters. *USERNAME will have the same lifetime as CREDS.
  2778. static bool
  2779. simple_username_get(
  2780. const char ** username,
  2781. apr_hash_t * creds,
  2782. const char * realmstring,
  2783. bool non_interactive)
  2784. {
  2785. string_t * str = static_cast<string_t *>(apr_hash_get(creds, AUTHN_USERNAME_KEY, APR_HASH_KEY_STRING));
  2786. if (str && str->data)
  2787. {
  2788. *username = str->data;
  2789. return TRUE;
  2790. }
  2791. return FALSE;
  2792. }
  2793. // Common implementation for simple_first_creds. Uses PARAMETERS, REALMSTRING
  2794. // and the simple auth provider's username and password cache to fill a set of
  2795. // CREDENTIALS. PASSWORD_GET is used to obtain the password value.
  2796. // PASSTYPE identifies the type of the cached password. CREDENTIALS are
  2797. // allocated from POOL.
  2798. static error_t
  2799. auth_simple_first_creds_helper(
  2800. void ** credentials,
  2801. void ** iter_baton,
  2802. void * provider_baton,
  2803. apr_hash_t * parameters,
  2804. const char * realmstring,
  2805. auth_password_get_t password_get,
  2806. const char * passtype,
  2807. apr_pool_t * pool)
  2808. {
  2809. const char * username = static_cast<const char *>(apr_hash_get(parameters,
  2810. WEBDAV_AUTH_PARAM_DEFAULT_USERNAME,
  2811. APR_HASH_KEY_STRING));
  2812. const char * password = static_cast<const char *>(apr_hash_get(parameters,
  2813. WEBDAV_AUTH_PARAM_DEFAULT_PASSWORD,
  2814. APR_HASH_KEY_STRING));
  2815. bool non_interactive = apr_hash_get(parameters,
  2816. WEBDAV_AUTH_PARAM_NON_INTERACTIVE,
  2817. APR_HASH_KEY_STRING) != NULL;
  2818. const char * default_username = NULL; // Default username from cache.
  2819. const char * default_password = NULL; // Default password from cache.
  2820. // This checks if we should save the CREDS, if saving the credentials is
  2821. // allowed by the run-time configuration.
  2822. bool need_to_save = FALSE;
  2823. apr_hash_t * creds_hash = NULL;
  2824. error_t err = 0;
  2825. // Try to load credentials from a file on disk, based on the
  2826. // realmstring. Don't throw an error, though: if something went
  2827. // wrong reading the file, no big deal. What really matters is that
  2828. // we failed to get the creds, so allow the auth system to try the
  2829. // next provider.
  2830. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
  2831. CONST_FS_KEY,
  2832. APR_HASH_KEY_STRING));
  2833. assert(fs);
  2834. err = config_read_auth_data(&creds_hash, AUTH_CRED_SIMPLE,
  2835. realmstring, fs, pool);
  2836. if (err)
  2837. {
  2838. error_clear(&err);
  2839. err = NULL;
  2840. }
  2841. else if (creds_hash)
  2842. {
  2843. // We have something in the auth cache for this realm.
  2844. bool have_passtype = FALSE;
  2845. // The password type in the auth data must match the
  2846. // mangler's type, otherwise the password must be
  2847. // interpreted by another provider.
  2848. string_t * str = static_cast<string_t *>(apr_hash_get(creds_hash, AUTHN_PASSTYPE_KEY, APR_HASH_KEY_STRING));
  2849. if (str && str->data)
  2850. if (passtype && (0 == strcmp(str->data, passtype)))
  2851. have_passtype = TRUE;
  2852. // See if we need to save this username if it is not present in
  2853. // auth cache.
  2854. if (username)
  2855. {
  2856. if (!simple_username_get(&default_username, creds_hash, realmstring,
  2857. non_interactive))
  2858. {
  2859. need_to_save = TRUE;
  2860. }
  2861. else
  2862. {
  2863. if (0 == strcmp(default_username, username))
  2864. need_to_save = FALSE;
  2865. else
  2866. need_to_save = TRUE;
  2867. }
  2868. }
  2869. // See if we need to save this password if it is not present in
  2870. // auth cache.
  2871. if (password)
  2872. {
  2873. if (have_passtype)
  2874. {
  2875. bool done;
  2876. WEBDAV_ERR(password_get(&done, &default_password, creds_hash, realmstring,
  2877. username, parameters, non_interactive, pool));
  2878. if (!done)
  2879. {
  2880. need_to_save = TRUE;
  2881. }
  2882. else
  2883. {
  2884. if (0 == strcmp(default_password, password))
  2885. need_to_save = FALSE;
  2886. else
  2887. need_to_save = TRUE;
  2888. }
  2889. }
  2890. }
  2891. // If we don't have a username and a password yet, we try the
  2892. // auth cache
  2893. if (!(username && password))
  2894. {
  2895. if (!username)
  2896. if (!simple_username_get(&username, creds_hash, realmstring,
  2897. non_interactive))
  2898. username = NULL;
  2899. if (username && !password)
  2900. {
  2901. if (!have_passtype)
  2902. password = NULL;
  2903. else
  2904. {
  2905. bool done;
  2906. WEBDAV_ERR(password_get(&done, &password, creds_hash, realmstring,
  2907. username, parameters, non_interactive,
  2908. pool));
  2909. if (!done)
  2910. password = NULL;
  2911. // If the auth data didn't contain a password type,
  2912. // force a write to upgrade the format of the auth
  2913. // data file.
  2914. if (password && !have_passtype)
  2915. need_to_save = TRUE;
  2916. }
  2917. }
  2918. }
  2919. }
  2920. else
  2921. {
  2922. // Nothing was present in the auth cache, so indicate that these
  2923. // credentials should be saved.
  2924. need_to_save = TRUE;
  2925. }
  2926. // Ask the OS for the username if we have a password but no username.
  2927. if (password && !username)
  2928. username = user_get_name(pool);
  2929. if (username && password)
  2930. {
  2931. auth_cred_simple_t * creds = static_cast<auth_cred_simple_t *>(apr_pcalloc(pool, sizeof(*creds)));
  2932. creds->username = username;
  2933. creds->password = password;
  2934. creds->may_save = need_to_save;
  2935. *credentials = creds;
  2936. }
  2937. else
  2938. *credentials = NULL;
  2939. *iter_baton = NULL;
  2940. return WEBDAV_NO_ERROR;
  2941. }
  2942. // Common implementation for simple_save_creds. Uses PARAMETERS and
  2943. // REALMSTRING to save a set of CREDENTIALS to the simple auth provider's
  2944. // username and password cache. PASSWORD_SET is used to store the password.
  2945. // PASSTYPE identifies the type of the cached password. Allocates from POOL.
  2946. static error_t
  2947. auth_simple_save_creds_helper(
  2948. bool * saved,
  2949. void * credentials,
  2950. void * provider_baton,
  2951. apr_hash_t * parameters,
  2952. const char * realmstring,
  2953. auth_password_set_t password_set,
  2954. const char * passtype,
  2955. apr_pool_t * pool)
  2956. {
  2957. auth_cred_simple_t * creds = static_cast<auth_cred_simple_t *>(credentials);
  2958. apr_hash_t * creds_hash = NULL;
  2959. error_t err = 0;
  2960. bool dont_store_passwords =
  2961. apr_hash_get(parameters,
  2962. WEBDAV_AUTH_PARAM_DONT_STORE_PASSWORDS,
  2963. APR_HASH_KEY_STRING) != NULL;
  2964. const char * store_plaintext_passwords = static_cast<const char *>(
  2965. apr_hash_get(parameters,
  2966. WEBDAV_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS,
  2967. APR_HASH_KEY_STRING));
  2968. bool non_interactive = apr_hash_get(parameters,
  2969. WEBDAV_AUTH_PARAM_NON_INTERACTIVE,
  2970. APR_HASH_KEY_STRING) != NULL;
  2971. simple_provider_baton_t * b = (simple_provider_baton_t *)provider_baton;
  2972. bool no_auth_cache = (!creds->may_save) ||
  2973. (apr_hash_get(parameters,
  2974. WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
  2975. APR_HASH_KEY_STRING) != NULL);
  2976. // Make sure we've been passed a passtype.
  2977. WEBDAV_ERR_ASSERT(passtype != NULL);
  2978. *saved = FALSE;
  2979. if (no_auth_cache)
  2980. return WEBDAV_NO_ERROR;
  2981. // Put the username into the credentials hash.
  2982. creds_hash = apr_hash_make(pool);
  2983. apr_hash_set(creds_hash, AUTHN_USERNAME_KEY, APR_HASH_KEY_STRING,
  2984. string_create(creds->username, pool));
  2985. // Don't store passwords in any form if the user has told
  2986. // us not to do so.
  2987. if (!dont_store_passwords)
  2988. {
  2989. bool may_save_password = FALSE;
  2990. // If the password is going to be stored encrypted, go right
  2991. // ahead and store it to disk. Else determine whether saving
  2992. // in plaintext is OK.
  2993. if (passtype &&
  2994. (strcmp(passtype, WEBDAV_AUTH_WINCRYPT_PASSWORD_TYPE) == 0))
  2995. {
  2996. may_save_password = TRUE;
  2997. }
  2998. else
  2999. {
  3000. if (store_plaintext_passwords && cstring_casecmp(store_plaintext_passwords,
  3001. WEBDAV_CONFIG_ASK) == 0)
  3002. {
  3003. if (non_interactive)
  3004. // In non-interactive mode, the default behaviour is
  3005. // to not store the password, because it is usually
  3006. // passed on the command line.
  3007. may_save_password = FALSE;
  3008. else if (b && b->plaintext_prompt_func)
  3009. {
  3010. // We're interactive, and the client provided a
  3011. // prompt callback. So we can ask the user.
  3012. // Check for a cached answer before prompting.
  3013. bool * cached_answer;
  3014. cached_answer = static_cast<bool *>(apr_hash_get(b->plaintext_answers,
  3015. realmstring,
  3016. APR_HASH_KEY_STRING));
  3017. if (cached_answer != NULL)
  3018. may_save_password = *cached_answer;
  3019. else
  3020. {
  3021. apr_pool_t * cached_answer_pool;
  3022. // Nothing cached for this realm, prompt the user.
  3023. WEBDAV_ERR((*b->plaintext_prompt_func)(&may_save_password,
  3024. realmstring,
  3025. b->prompt_baton,
  3026. pool));
  3027. cached_answer_pool = apr_hash_pool_get(b->plaintext_answers);
  3028. cached_answer = static_cast<bool *>(apr_pcalloc(cached_answer_pool,
  3029. sizeof(bool)));
  3030. *cached_answer = may_save_password;
  3031. apr_hash_set(b->plaintext_answers, realmstring,
  3032. APR_HASH_KEY_STRING, cached_answer);
  3033. }
  3034. }
  3035. else
  3036. {
  3037. may_save_password = TRUE;
  3038. }
  3039. }
  3040. else if (store_plaintext_passwords && cstring_casecmp(store_plaintext_passwords,
  3041. WEBDAV_CONFIG_FALSE) == 0)
  3042. {
  3043. may_save_password = FALSE;
  3044. }
  3045. else if (store_plaintext_passwords && cstring_casecmp(store_plaintext_passwords,
  3046. WEBDAV_CONFIG_TRUE) == 0)
  3047. {
  3048. may_save_password = TRUE;
  3049. }
  3050. else
  3051. {
  3052. /*return error_createf
  3053. (WEBDAV_ERR_BAD_CONFIG_VALUE, NULL,
  3054. "Config error: invalid value '%s' for option '%s'",
  3055. store_plaintext_passwords,
  3056. WEBDAV_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS);*/
  3057. may_save_password = FALSE;
  3058. }
  3059. }
  3060. if (may_save_password)
  3061. {
  3062. WEBDAV_ERR(password_set(saved, creds_hash, realmstring,
  3063. creds->username, creds->password,
  3064. parameters, non_interactive, pool));
  3065. if (*saved && passtype)
  3066. // Store the password type with the auth data, so that we
  3067. // know which provider owns the password.
  3068. apr_hash_set(creds_hash, AUTHN_PASSTYPE_KEY, APR_HASH_KEY_STRING,
  3069. string_create(passtype, pool));
  3070. }
  3071. }
  3072. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
  3073. CONST_FS_KEY,
  3074. APR_HASH_KEY_STRING));
  3075. assert(fs);
  3076. // Save credentials to disk.
  3077. err = config_write_auth_data(creds_hash, AUTH_CRED_SIMPLE,
  3078. realmstring, fs, pool);
  3079. error_clear(&err);
  3080. return WEBDAV_NO_ERROR;
  3081. }
  3082. // Get cached (unencrypted) credentials from the simple provider's cache.
  3083. static error_t
  3084. simple_first_creds(
  3085. void ** credentials,
  3086. void ** iter_baton,
  3087. void * provider_baton,
  3088. apr_hash_t * parameters,
  3089. const char * realmstring,
  3090. apr_pool_t * pool)
  3091. {
  3092. return auth_simple_first_creds_helper(credentials,
  3093. iter_baton,
  3094. provider_baton,
  3095. parameters,
  3096. realmstring,
  3097. auth_simple_password_get,
  3098. WEBDAV_AUTH_SIMPLE_PASSWORD_TYPE,
  3099. pool);
  3100. }
  3101. // Save (unencrypted) credentials to the simple provider's cache.
  3102. static error_t
  3103. simple_save_creds(
  3104. bool * saved,
  3105. void * credentials,
  3106. void * provider_baton,
  3107. apr_hash_t * parameters,
  3108. const char * realmstring,
  3109. apr_pool_t * pool)
  3110. {
  3111. return auth_simple_save_creds_helper(saved, credentials,
  3112. provider_baton,
  3113. parameters,
  3114. realmstring,
  3115. auth_simple_password_set,
  3116. WEBDAV_AUTH_SIMPLE_PASSWORD_TYPE,
  3117. pool);
  3118. }
  3119. static const auth_provider_t simple_provider =
  3120. {
  3121. AUTH_CRED_SIMPLE,
  3122. simple_first_creds,
  3123. NULL,
  3124. simple_save_creds
  3125. };
  3126. // Public API
  3127. static void
  3128. auth_get_simple_provider2(
  3129. auth_provider_object_t ** provider,
  3130. auth_plaintext_prompt_func_t plaintext_prompt_func,
  3131. void * prompt_baton,
  3132. apr_pool_t * pool)
  3133. {
  3134. auth_provider_object_t * po = static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
  3135. simple_provider_baton_t * pb = static_cast<simple_provider_baton_t *>(apr_pcalloc(pool, sizeof(*pb)));
  3136. pb->plaintext_prompt_func = plaintext_prompt_func;
  3137. pb->prompt_baton = prompt_baton;
  3138. pb->plaintext_answers = apr_hash_make(pool);
  3139. po->vtable = &simple_provider;
  3140. po->provider_baton = pb;
  3141. *provider = po;
  3142. }
  3143. // Baton type for username/password prompting.
  3144. typedef struct simple_prompt_provider_baton_t
  3145. {
  3146. auth_simple_prompt_func_t prompt_func;
  3147. void * prompt_baton;
  3148. // how many times to re-prompt after the first one fails
  3149. int retry_limit;
  3150. } simple_prompt_provider_baton_t;
  3151. // Iteration baton type for username/password prompting.
  3152. typedef struct simple_prompt_iter_baton_t
  3153. {
  3154. // how many times we've reprompted
  3155. int retries;
  3156. } simple_prompt_iter_baton_t;
  3157. // Helper Functions
  3158. static error_t
  3159. prompt_for_simple_creds(
  3160. auth_cred_simple_t ** cred_p,
  3161. simple_prompt_provider_baton_t * pb,
  3162. apr_hash_t * parameters,
  3163. const char * realmstring,
  3164. bool first_time,
  3165. bool may_save,
  3166. apr_pool_t * pool)
  3167. {
  3168. const char * default_username = NULL;
  3169. const char * default_password = NULL;
  3170. *cred_p = NULL;
  3171. // If we're allowed to check for default usernames and passwords, do so.
  3172. if (first_time)
  3173. {
  3174. default_username = static_cast<const char *>(apr_hash_get(parameters,
  3175. WEBDAV_AUTH_PARAM_DEFAULT_USERNAME,
  3176. APR_HASH_KEY_STRING));
  3177. // No default username? Try the auth cache.
  3178. if (!default_username)
  3179. {
  3180. apr_hash_t * creds_hash = NULL;
  3181. string_t * str;
  3182. error_t err;
  3183. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
  3184. CONST_FS_KEY,
  3185. APR_HASH_KEY_STRING));
  3186. assert(fs);
  3187. err = config_read_auth_data(&creds_hash, AUTH_CRED_SIMPLE,
  3188. realmstring, fs, pool);
  3189. error_clear(&err);
  3190. if (!err && creds_hash)
  3191. {
  3192. str = static_cast<string_t *>(apr_hash_get(creds_hash, AUTHN_USERNAME_KEY,
  3193. APR_HASH_KEY_STRING));
  3194. if (str && str->data)
  3195. default_username = str->data;
  3196. }
  3197. }
  3198. // Still no default username? Try the 'servers' file.
  3199. if (!default_username)
  3200. {
  3201. default_username = NULL;
  3202. }
  3203. // Still no default username? Try the UID.
  3204. if (!default_username)
  3205. default_username = user_get_name(pool);
  3206. default_password = static_cast<const char *>(apr_hash_get(parameters,
  3207. WEBDAV_AUTH_PARAM_DEFAULT_PASSWORD,
  3208. APR_HASH_KEY_STRING));
  3209. }
  3210. // If we have defaults, just build the cred here and return it.
  3211. // I do wonder why this is here instead of in a separate
  3212. // 'defaults' provider that would run before the prompt
  3213. // provider... Hmmm.
  3214. if (default_username && default_password)
  3215. {
  3216. *cred_p = static_cast<auth_cred_simple_t *>(apr_pcalloc(pool, sizeof(**cred_p)));
  3217. (*cred_p)->username = apr_pstrdup(pool, default_username);
  3218. (*cred_p)->password = apr_pstrdup(pool, default_password);
  3219. (*cred_p)->may_save = TRUE;
  3220. }
  3221. else
  3222. {
  3223. WEBDAV_ERR(pb->prompt_func(cred_p, pb->prompt_baton, realmstring,
  3224. default_username, may_save, pool));
  3225. }
  3226. return WEBDAV_NO_ERROR;
  3227. }
  3228. // Our first attempt will use any default username/password passed
  3229. // in, and prompt for the remaining stuff.
  3230. static error_t
  3231. simple_prompt_first_creds(
  3232. void ** credentials_p,
  3233. void ** iter_baton,
  3234. void * provider_baton,
  3235. apr_hash_t * parameters,
  3236. const char * realmstring,
  3237. apr_pool_t * pool)
  3238. {
  3239. simple_prompt_provider_baton_t * pb =
  3240. static_cast<simple_prompt_provider_baton_t *>(provider_baton);
  3241. simple_prompt_iter_baton_t * ibaton =
  3242. static_cast<simple_prompt_iter_baton_t *>(apr_pcalloc(pool, sizeof(*ibaton)));
  3243. const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
  3244. WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
  3245. APR_HASH_KEY_STRING));
  3246. WEBDAV_ERR(prompt_for_simple_creds((auth_cred_simple_t **) credentials_p,
  3247. pb, parameters, realmstring, TRUE,
  3248. !no_auth_cache, pool));
  3249. ibaton->retries = 0;
  3250. *iter_baton = ibaton;
  3251. return WEBDAV_NO_ERROR;
  3252. }
  3253. // Subsequent attempts to fetch will ignore the default values, and
  3254. // simply re-prompt for both, up to a maximum of ib->pb->retry_limit.
  3255. static error_t
  3256. simple_prompt_next_creds(
  3257. void ** credentials_p,
  3258. void * iter_baton,
  3259. void * provider_baton,
  3260. apr_hash_t * parameters,
  3261. const char * realmstring,
  3262. apr_pool_t * pool)
  3263. {
  3264. simple_prompt_iter_baton_t * ib =
  3265. static_cast<simple_prompt_iter_baton_t *>(iter_baton);
  3266. simple_prompt_provider_baton_t * pb =
  3267. static_cast<simple_prompt_provider_baton_t *>(provider_baton);
  3268. const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
  3269. WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
  3270. APR_HASH_KEY_STRING));
  3271. if ((pb->retry_limit >= 0) && (ib->retries >= pb->retry_limit))
  3272. {
  3273. // give up, go on to next provider.
  3274. *credentials_p = NULL;
  3275. return WEBDAV_NO_ERROR;
  3276. }
  3277. ib->retries++;
  3278. return prompt_for_simple_creds((auth_cred_simple_t **) credentials_p,
  3279. pb, parameters, realmstring, FALSE,
  3280. !no_auth_cache, pool);
  3281. }
  3282. static const auth_provider_t simple_prompt_provider =
  3283. {
  3284. AUTH_CRED_SIMPLE,
  3285. simple_prompt_first_creds,
  3286. simple_prompt_next_creds,
  3287. NULL,
  3288. };
  3289. // Public API
  3290. static void
  3291. auth_get_simple_prompt_provider(
  3292. auth_provider_object_t ** provider,
  3293. auth_simple_prompt_func_t prompt_func,
  3294. void * prompt_baton,
  3295. int retry_limit,
  3296. apr_pool_t * pool)
  3297. {
  3298. auth_provider_object_t * po =
  3299. static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
  3300. simple_prompt_provider_baton_t * pb =
  3301. static_cast<simple_prompt_provider_baton_t *>(apr_pcalloc(pool, sizeof(*pb)));
  3302. pb->prompt_func = prompt_func;
  3303. pb->prompt_baton = prompt_baton;
  3304. pb->retry_limit = retry_limit;
  3305. po->vtable = &simple_prompt_provider;
  3306. po->provider_baton = pb;
  3307. *provider = po;
  3308. }
  3309. //---------------------------------------------------------------------------
  3310. // from ssl_client_cert_pw_providers.c
  3311. // The keys that will be stored on disk. These serve the same role as
  3312. // similar constants in other providers.
  3313. // AUTHN_PASSTYPE_KEY just records the passphrase type next to the
  3314. // passphrase, so that anyone who is manually editing their authn
  3315. // files can know which provider owns the password.
  3316. #define AUTHN_PASSPHRASE_KEY "passphrase"
  3317. #define AUTHN_PASSTYPE_KEY "passtype"
  3318. // Baton type for the ssl client cert passphrase provider.
  3319. typedef struct ssl_client_cert_pw_file_provider_baton_t
  3320. {
  3321. auth_plaintext_passphrase_prompt_func_t plaintext_passphrase_prompt_func;
  3322. void * prompt_baton;
  3323. // We cache the user's answer to the plaintext prompt, keyed
  3324. // by realm, in case we'll be called multiple times for the
  3325. // same realm. So: keys are 'const char *' realm strings, and
  3326. // values are 'bool *'.
  3327. apr_hash_t * plaintext_answers;
  3328. } ssl_client_cert_pw_file_provider_baton_t;
  3329. // This implements the auth_password_get_t interface.
  3330. // Set **PASSPHRASE to the plaintext passphrase retrieved from CREDS;
  3331. // ignore other parameters.
  3332. static error_t
  3333. auth_ssl_client_cert_pw_get(
  3334. bool * done,
  3335. const char ** passphrase,
  3336. apr_hash_t * creds,
  3337. const char * realmstring,
  3338. const char * username,
  3339. apr_hash_t * parameters,
  3340. bool non_interactive,
  3341. apr_pool_t * pool)
  3342. {
  3343. string_t * str = static_cast<string_t *>(apr_hash_get(creds, AUTHN_PASSPHRASE_KEY, APR_HASH_KEY_STRING));
  3344. if (str && str->data)
  3345. {
  3346. *passphrase = str->data;
  3347. *done = TRUE;
  3348. return WEBDAV_NO_ERROR;
  3349. }
  3350. *done = FALSE;
  3351. return WEBDAV_NO_ERROR;
  3352. }
  3353. // This implements the auth_password_set_t interface.
  3354. // Store PASSPHRASE in CREDS; ignore other parameters.
  3355. static error_t
  3356. auth_ssl_client_cert_pw_set(
  3357. bool * done,
  3358. apr_hash_t * creds,
  3359. const char * realmstring,
  3360. const char * username,
  3361. const char * passphrase,
  3362. apr_hash_t * parameters,
  3363. bool non_interactive,
  3364. apr_pool_t * pool)
  3365. {
  3366. apr_hash_set(creds, AUTHN_PASSPHRASE_KEY, APR_HASH_KEY_STRING,
  3367. string_create(passphrase, pool));
  3368. *done = TRUE;
  3369. return WEBDAV_NO_ERROR;
  3370. }
  3371. static error_t
  3372. auth_ssl_client_cert_pw_file_first_creds_helper(
  3373. void ** credentials_p,
  3374. void ** iter_baton,
  3375. void * provider_baton,
  3376. apr_hash_t * parameters,
  3377. const char * realmstring,
  3378. auth_password_get_t passphrase_get,
  3379. const char * passtype,
  3380. apr_pool_t * pool)
  3381. {
  3382. bool non_interactive = apr_hash_get(parameters,
  3383. WEBDAV_AUTH_PARAM_NON_INTERACTIVE,
  3384. APR_HASH_KEY_STRING) != NULL;
  3385. const char * password = NULL;
  3386. if (!password)
  3387. {
  3388. error_t err;
  3389. apr_hash_t * creds_hash = NULL;
  3390. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
  3391. CONST_FS_KEY,
  3392. APR_HASH_KEY_STRING));
  3393. assert(fs);
  3394. // Try to load passphrase from the auth/ cache.
  3395. err = config_read_auth_data(&creds_hash,
  3396. AUTH_CRED_SSL_CLIENT_CERT_PW,
  3397. realmstring, fs, pool);
  3398. error_clear(&err);
  3399. if (!err && creds_hash)
  3400. {
  3401. bool done;
  3402. WEBDAV_ERR(passphrase_get(&done, &password, creds_hash, realmstring,
  3403. NULL, parameters, non_interactive, pool));
  3404. if (!done)
  3405. password = NULL;
  3406. }
  3407. }
  3408. if (password)
  3409. {
  3410. auth_cred_ssl_client_cert_pw_t * cred =
  3411. static_cast<auth_cred_ssl_client_cert_pw_t *>(apr_pcalloc(pool, sizeof(*cred)));
  3412. cred->password = password;
  3413. cred->may_save = FALSE;
  3414. *credentials_p = cred;
  3415. }
  3416. else *credentials_p = NULL;
  3417. *iter_baton = NULL;
  3418. return WEBDAV_NO_ERROR;
  3419. }
  3420. static error_t
  3421. auth_ssl_client_cert_pw_file_save_creds_helper(
  3422. bool * saved,
  3423. void * credentials,
  3424. void * provider_baton,
  3425. apr_hash_t * parameters,
  3426. const char * realmstring,
  3427. auth_password_set_t passphrase_set,
  3428. const char * passtype,
  3429. apr_pool_t * pool)
  3430. {
  3431. auth_cred_ssl_client_cert_pw_t * creds =
  3432. static_cast<auth_cred_ssl_client_cert_pw_t *>(credentials);
  3433. apr_hash_t * creds_hash = NULL;
  3434. error_t err = 0;
  3435. bool dont_store_passphrase =
  3436. apr_hash_get(parameters,
  3437. WEBDAV_AUTH_PARAM_DONT_STORE_SSL_CLIENT_CERT_PP,
  3438. APR_HASH_KEY_STRING) != NULL;
  3439. const char * store_ssl_client_cert_pp_plaintext =
  3440. static_cast<const char *>(apr_hash_get(parameters,
  3441. WEBDAV_AUTH_PARAM_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT,
  3442. APR_HASH_KEY_STRING));
  3443. bool non_interactive = apr_hash_get(parameters,
  3444. WEBDAV_AUTH_PARAM_NON_INTERACTIVE,
  3445. APR_HASH_KEY_STRING) != NULL;
  3446. ssl_client_cert_pw_file_provider_baton_t * b =
  3447. (ssl_client_cert_pw_file_provider_baton_t *)provider_baton;
  3448. bool no_auth_cache = (!creds->may_save) ||
  3449. (apr_hash_get(parameters,
  3450. WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
  3451. APR_HASH_KEY_STRING) != NULL);
  3452. *saved = FALSE;
  3453. if (no_auth_cache)
  3454. return WEBDAV_NO_ERROR;
  3455. creds_hash = apr_hash_make(pool);
  3456. // Don't store passphrase in any form if the user has told
  3457. // us not to do so.
  3458. if (!dont_store_passphrase)
  3459. {
  3460. bool may_save_passphrase = FALSE;
  3461. // If the passphrase is going to be stored encrypted, go right
  3462. // ahead and store it to disk. Else determine whether saving
  3463. // in plaintext is OK.
  3464. if (strcmp(passtype, WEBDAV_AUTH_WINCRYPT_PASSWORD_TYPE) == 0)
  3465. {
  3466. may_save_passphrase = TRUE;
  3467. }
  3468. else
  3469. {
  3470. if (cstring_casecmp(store_ssl_client_cert_pp_plaintext,
  3471. WEBDAV_CONFIG_ASK) == 0)
  3472. {
  3473. if (non_interactive)
  3474. {
  3475. // In non-interactive mode, the default behaviour is
  3476. // to not store the passphrase
  3477. may_save_passphrase = FALSE;
  3478. }
  3479. else if (b->plaintext_passphrase_prompt_func)
  3480. {
  3481. bool * cached_answer =
  3482. static_cast<bool *>(apr_hash_get(b->plaintext_answers, realmstring,
  3483. APR_HASH_KEY_STRING));
  3484. if (cached_answer != NULL)
  3485. {
  3486. may_save_passphrase = *cached_answer;
  3487. }
  3488. else
  3489. {
  3490. apr_pool_t * cached_answer_pool;
  3491. // Nothing cached for this realm, prompt the user.
  3492. WEBDAV_ERR((*b->plaintext_passphrase_prompt_func)(
  3493. &may_save_passphrase,
  3494. realmstring,
  3495. b->prompt_baton,
  3496. pool));
  3497. cached_answer_pool = apr_hash_pool_get(b->plaintext_answers);
  3498. cached_answer = static_cast<bool *>(apr_pcalloc(cached_answer_pool,
  3499. sizeof(*cached_answer)));
  3500. *cached_answer = may_save_passphrase;
  3501. apr_hash_set(b->plaintext_answers, realmstring,
  3502. APR_HASH_KEY_STRING, cached_answer);
  3503. }
  3504. }
  3505. else
  3506. {
  3507. may_save_passphrase = FALSE;
  3508. }
  3509. }
  3510. else if (cstring_casecmp(store_ssl_client_cert_pp_plaintext,
  3511. WEBDAV_CONFIG_FALSE) == 0)
  3512. {
  3513. may_save_passphrase = FALSE;
  3514. }
  3515. else if (cstring_casecmp(store_ssl_client_cert_pp_plaintext,
  3516. WEBDAV_CONFIG_TRUE) == 0)
  3517. {
  3518. may_save_passphrase = TRUE;
  3519. }
  3520. else
  3521. {
  3522. return error_createf(WEBDAV_ERR_DAV_INVALID_CONFIG_VALUE, NULL,
  3523. "Config error: invalid value '%s' for option '%s'",
  3524. store_ssl_client_cert_pp_plaintext,
  3525. WEBDAV_AUTH_PARAM_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT);
  3526. }
  3527. }
  3528. if (may_save_passphrase)
  3529. {
  3530. WEBDAV_ERR(passphrase_set(saved, creds_hash, realmstring,
  3531. NULL, creds->password, parameters,
  3532. non_interactive, pool));
  3533. if (*saved && passtype)
  3534. {
  3535. apr_hash_set(creds_hash, AUTHN_PASSTYPE_KEY,
  3536. APR_HASH_KEY_STRING,
  3537. string_create(passtype, pool));
  3538. }
  3539. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
  3540. CONST_FS_KEY,
  3541. APR_HASH_KEY_STRING));
  3542. assert(fs);
  3543. // Save credentials to disk.
  3544. err = config_write_auth_data(creds_hash,
  3545. AUTH_CRED_SSL_CLIENT_CERT_PW,
  3546. realmstring, fs, pool);
  3547. error_clear(&err);
  3548. *saved = !err;
  3549. }
  3550. }
  3551. return WEBDAV_NO_ERROR;
  3552. }
  3553. // This implements the auth_provider_t.first_credentials API.
  3554. // It gets cached (unencrypted) credentials from the ssl client cert
  3555. // password provider's cache.
  3556. static error_t
  3557. ssl_client_cert_pw_file_first_credentials(
  3558. void ** credentials_p,
  3559. void ** iter_baton,
  3560. void * provider_baton,
  3561. apr_hash_t * parameters,
  3562. const char * realmstring,
  3563. apr_pool_t * pool)
  3564. {
  3565. return auth_ssl_client_cert_pw_file_first_creds_helper(
  3566. credentials_p,
  3567. iter_baton,
  3568. provider_baton,
  3569. parameters,
  3570. realmstring,
  3571. auth_ssl_client_cert_pw_get,
  3572. WEBDAV_AUTH_SIMPLE_PASSWORD_TYPE,
  3573. pool);
  3574. }
  3575. // This implements the auth_provider_t.save_credentials API.
  3576. // It saves the credentials unencrypted.
  3577. static error_t
  3578. ssl_client_cert_pw_file_save_credentials(
  3579. bool * saved,
  3580. void * credentials,
  3581. void * provider_baton,
  3582. apr_hash_t * parameters,
  3583. const char * realmstring,
  3584. apr_pool_t * pool)
  3585. {
  3586. return auth_ssl_client_cert_pw_file_save_creds_helper(
  3587. saved, credentials,
  3588. provider_baton,
  3589. parameters,
  3590. realmstring,
  3591. auth_ssl_client_cert_pw_set,
  3592. WEBDAV_AUTH_SIMPLE_PASSWORD_TYPE,
  3593. pool);
  3594. }
  3595. static const auth_provider_t ssl_client_cert_pw_file_provider =
  3596. {
  3597. AUTH_CRED_SSL_CLIENT_CERT_PW,
  3598. ssl_client_cert_pw_file_first_credentials,
  3599. NULL,
  3600. ssl_client_cert_pw_file_save_credentials
  3601. };
  3602. // Public API to SSL file providers.
  3603. static void
  3604. auth_get_ssl_client_cert_pw_file_provider2(
  3605. auth_provider_object_t ** provider,
  3606. auth_plaintext_passphrase_prompt_func_t plaintext_passphrase_prompt_func,
  3607. void * prompt_baton,
  3608. apr_pool_t * pool)
  3609. {
  3610. auth_provider_object_t * po =
  3611. static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
  3612. ssl_client_cert_pw_file_provider_baton_t * pb =
  3613. static_cast<ssl_client_cert_pw_file_provider_baton_t *>(apr_pcalloc(pool,
  3614. sizeof(*pb)));
  3615. pb->plaintext_passphrase_prompt_func = plaintext_passphrase_prompt_func;
  3616. pb->prompt_baton = prompt_baton;
  3617. pb->plaintext_answers = apr_hash_make(pool);
  3618. po->vtable = &ssl_client_cert_pw_file_provider;
  3619. po->provider_baton = pb;
  3620. *provider = po;
  3621. }
  3622. /*-----------------------------------------------------------------------*/
  3623. // Prompt provider
  3624. /*-----------------------------------------------------------------------*/
  3625. // Baton type for client passphrase prompting.
  3626. // There is no iteration baton type.
  3627. typedef struct ssl_client_cert_pw_prompt_provider_baton_t
  3628. {
  3629. auth_ssl_client_cert_pw_prompt_func_t prompt_func;
  3630. void * prompt_baton;
  3631. // how many times to re-prompt after the first one fails
  3632. int retry_limit;
  3633. } ssl_client_cert_pw_prompt_provider_baton_t;
  3634. // Iteration baton.
  3635. typedef struct ssl_client_cert_pw_prompt_iter_baton_t
  3636. {
  3637. // The original provider baton
  3638. ssl_client_cert_pw_prompt_provider_baton_t * pb;
  3639. // The original realmstring
  3640. const char * realmstring;
  3641. // how many times we've reprompted
  3642. int retries;
  3643. } ssl_client_cert_pw_prompt_iter_baton_t;
  3644. static error_t
  3645. ssl_client_cert_pw_prompt_first_cred(
  3646. void ** credentials_p,
  3647. void ** iter_baton,
  3648. void * provider_baton,
  3649. apr_hash_t * parameters,
  3650. const char * realmstring,
  3651. apr_pool_t * pool)
  3652. {
  3653. ssl_client_cert_pw_prompt_provider_baton_t * pb =
  3654. static_cast<ssl_client_cert_pw_prompt_provider_baton_t *>(provider_baton);
  3655. ssl_client_cert_pw_prompt_iter_baton_t * ib =
  3656. static_cast<ssl_client_cert_pw_prompt_iter_baton_t *>(apr_pcalloc(pool, sizeof(*ib)));
  3657. const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
  3658. WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
  3659. APR_HASH_KEY_STRING));
  3660. WEBDAV_ERR(pb->prompt_func((auth_cred_ssl_client_cert_pw_t **)
  3661. credentials_p, pb->prompt_baton, realmstring,
  3662. !no_auth_cache, pool));
  3663. ib->pb = pb;
  3664. ib->realmstring = apr_pstrdup(pool, realmstring);
  3665. ib->retries = 0;
  3666. *iter_baton = ib;
  3667. return WEBDAV_NO_ERROR;
  3668. }
  3669. static error_t
  3670. ssl_client_cert_pw_prompt_next_cred(
  3671. void ** credentials_p,
  3672. void * iter_baton,
  3673. void * provider_baton,
  3674. apr_hash_t * parameters,
  3675. const char * realmstring,
  3676. apr_pool_t * pool)
  3677. {
  3678. ssl_client_cert_pw_prompt_iter_baton_t * ib =
  3679. static_cast<ssl_client_cert_pw_prompt_iter_baton_t *>(iter_baton);
  3680. const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
  3681. WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
  3682. APR_HASH_KEY_STRING));
  3683. if ((ib->pb->retry_limit >= 0) && (ib->retries >= ib->pb->retry_limit))
  3684. {
  3685. // give up, go on to next provider.
  3686. *credentials_p = NULL;
  3687. return WEBDAV_NO_ERROR;
  3688. }
  3689. ib->retries++;
  3690. return ib->pb->prompt_func((auth_cred_ssl_client_cert_pw_t **)
  3691. credentials_p, ib->pb->prompt_baton,
  3692. ib->realmstring, !no_auth_cache, pool);
  3693. }
  3694. static const auth_provider_t client_cert_pw_prompt_provider =
  3695. {
  3696. AUTH_CRED_SSL_CLIENT_CERT_PW,
  3697. ssl_client_cert_pw_prompt_first_cred,
  3698. ssl_client_cert_pw_prompt_next_cred,
  3699. NULL
  3700. };
  3701. static void
  3702. auth_get_ssl_client_cert_pw_prompt_provider(
  3703. auth_provider_object_t ** provider,
  3704. auth_ssl_client_cert_pw_prompt_func_t prompt_func,
  3705. void * prompt_baton,
  3706. int retry_limit,
  3707. apr_pool_t * pool)
  3708. {
  3709. auth_provider_object_t * po =
  3710. static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
  3711. ssl_client_cert_pw_prompt_provider_baton_t * pb =
  3712. static_cast<ssl_client_cert_pw_prompt_provider_baton_t *>(apr_pcalloc(pool, sizeof(*pb)));
  3713. pb->prompt_func = prompt_func;
  3714. pb->prompt_baton = prompt_baton;
  3715. pb->retry_limit = retry_limit;
  3716. po->vtable = &client_cert_pw_prompt_provider;
  3717. po->provider_baton = pb;
  3718. *provider = po;
  3719. }
  3720. //------------------------------------------------------------------------------
  3721. // from win32_crypto.c
  3722. // The description string that's combined with unencrypted data by the
  3723. // Windows CryptoAPI. Used during decryption to verify that the
  3724. // encrypted data were valid.
  3725. static const WCHAR description[] = L"auth.simple.wincrypt";
  3726. // Implementation of auth_password_set_t that encrypts
  3727. // the incoming password using the Windows CryptoAPI.
  3728. static error_t
  3729. windows_password_encrypter(
  3730. bool * done,
  3731. apr_hash_t * creds,
  3732. const char * realmstring,
  3733. const char * username,
  3734. const char * in,
  3735. apr_hash_t * parameters,
  3736. bool non_interactive,
  3737. apr_pool_t * pool)
  3738. {
  3739. DATA_BLOB blobin;
  3740. DATA_BLOB blobout;
  3741. BOOL crypted = FALSE;
  3742. blobin.cbData = (DWORD)strlen(in);
  3743. blobin.pbData = (BYTE *) in;
  3744. crypted = CryptProtectData(&blobin, description, NULL, NULL, NULL,
  3745. CRYPTPROTECT_UI_FORBIDDEN, &blobout);
  3746. if (crypted)
  3747. {
  3748. char * coded = static_cast<char *>(apr_pcalloc(pool, apr_base64_encode_len(blobout.cbData)));
  3749. apr_base64_encode(coded, (const char *)blobout.pbData, blobout.cbData);
  3750. WEBDAV_ERR(auth_simple_password_set(done, creds, realmstring, username,
  3751. coded, parameters,
  3752. non_interactive, pool));
  3753. LocalFree(blobout.pbData);
  3754. }
  3755. return WEBDAV_NO_ERROR;
  3756. }
  3757. // Implementation of auth_password_get_t that decrypts
  3758. // the incoming password using the Windows CryptoAPI and verifies its
  3759. // validity.
  3760. static error_t
  3761. windows_password_decrypter(
  3762. bool * done,
  3763. const char ** out,
  3764. apr_hash_t * creds,
  3765. const char * realmstring,
  3766. const char * username,
  3767. apr_hash_t * parameters,
  3768. bool non_interactive,
  3769. apr_pool_t * pool)
  3770. {
  3771. DATA_BLOB blobin;
  3772. DATA_BLOB blobout;
  3773. LPWSTR descr;
  3774. BOOL decrypted = FALSE;
  3775. const char * in = NULL;
  3776. WEBDAV_ERR(auth_simple_password_get(done, &in, creds, realmstring, username,
  3777. parameters, non_interactive, pool));
  3778. if (!*done)
  3779. return WEBDAV_NO_ERROR;
  3780. blobin.cbData = (DWORD)strlen(in);
  3781. blobin.pbData = static_cast<BYTE *>(apr_pcalloc(pool, apr_base64_decode_len(in)));
  3782. apr_base64_decode((char *)blobin.pbData, in);
  3783. decrypted = CryptUnprotectData(&blobin, &descr, NULL, NULL, NULL,
  3784. CRYPTPROTECT_UI_FORBIDDEN, &blobout);
  3785. if (decrypted)
  3786. {
  3787. if (0 == lstrcmpW(descr, description))
  3788. *out = apr_pstrndup(pool, (const char *)blobout.pbData, blobout.cbData);
  3789. else
  3790. decrypted = FALSE;
  3791. LocalFree(blobout.pbData);
  3792. LocalFree(descr);
  3793. }
  3794. *done = decrypted != 0;
  3795. return WEBDAV_NO_ERROR;
  3796. }
  3797. // Get cached encrypted credentials from the simple provider's cache.
  3798. static error_t
  3799. windows_simple_first_creds(
  3800. void ** credentials,
  3801. void ** iter_baton,
  3802. void * provider_baton,
  3803. apr_hash_t * parameters,
  3804. const char * realmstring,
  3805. apr_pool_t * pool)
  3806. {
  3807. return auth_simple_first_creds_helper(credentials,
  3808. iter_baton,
  3809. provider_baton,
  3810. parameters,
  3811. realmstring,
  3812. windows_password_decrypter,
  3813. WEBDAV_AUTH_WINCRYPT_PASSWORD_TYPE,
  3814. pool);
  3815. }
  3816. // Save encrypted credentials to the simple provider's cache.
  3817. static error_t
  3818. windows_simple_save_creds(
  3819. bool * saved,
  3820. void * credentials,
  3821. void * provider_baton,
  3822. apr_hash_t * parameters,
  3823. const char * realmstring,
  3824. apr_pool_t * pool)
  3825. {
  3826. return auth_simple_save_creds_helper(saved, credentials,
  3827. provider_baton,
  3828. parameters,
  3829. realmstring,
  3830. windows_password_encrypter,
  3831. WEBDAV_AUTH_WINCRYPT_PASSWORD_TYPE,
  3832. pool);
  3833. }
  3834. static const auth_provider_t windows_simple_provider =
  3835. {
  3836. AUTH_CRED_SIMPLE,
  3837. windows_simple_first_creds,
  3838. NULL,
  3839. windows_simple_save_creds
  3840. };
  3841. // Public API
  3842. static void
  3843. auth_get_windows_simple_provider(
  3844. auth_provider_object_t ** provider,
  3845. apr_pool_t * pool)
  3846. {
  3847. auth_provider_object_t * po =
  3848. static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
  3849. po->vtable = &windows_simple_provider;
  3850. *provider = po;
  3851. }
  3852. /*-----------------------------------------------------------------------*/
  3853. // Windows SSL server trust provider, validates ssl certificate using
  3854. // CryptoApi.
  3855. /*-----------------------------------------------------------------------*/
  3856. // Implementation of auth_password_set_t that encrypts
  3857. // the incoming password using the Windows CryptoAPI.
  3858. static error_t
  3859. windows_ssl_client_cert_pw_encrypter(
  3860. bool * done,
  3861. apr_hash_t * creds,
  3862. const char * realmstring,
  3863. const char * username,
  3864. const char * in,
  3865. apr_hash_t * parameters,
  3866. bool non_interactive,
  3867. apr_pool_t * pool)
  3868. {
  3869. DATA_BLOB blobin;
  3870. DATA_BLOB blobout;
  3871. BOOL crypted;
  3872. blobin.cbData = (DWORD)strlen(in);
  3873. blobin.pbData = (BYTE *) in;
  3874. crypted = CryptProtectData(&blobin, description, NULL, NULL, NULL,
  3875. CRYPTPROTECT_UI_FORBIDDEN, &blobout);
  3876. if (crypted)
  3877. {
  3878. char * coded = static_cast<char *>(apr_pcalloc(pool, apr_base64_encode_len(blobout.cbData)));
  3879. apr_base64_encode(coded, (const char *)blobout.pbData, blobout.cbData);
  3880. WEBDAV_ERR(auth_ssl_client_cert_pw_set(done, creds, realmstring, username,
  3881. coded, parameters,
  3882. non_interactive, pool));
  3883. LocalFree(blobout.pbData);
  3884. }
  3885. return WEBDAV_NO_ERROR;
  3886. }
  3887. // Implementation of auth_password_get_t that decrypts
  3888. // the incoming password using the Windows CryptoAPI and verifies its
  3889. // validity.
  3890. static error_t
  3891. windows_ssl_client_cert_pw_decrypter(
  3892. bool * done,
  3893. const char ** out,
  3894. apr_hash_t * creds,
  3895. const char * realmstring,
  3896. const char * username,
  3897. apr_hash_t * parameters,
  3898. bool non_interactive,
  3899. apr_pool_t * pool)
  3900. {
  3901. DATA_BLOB blobin;
  3902. DATA_BLOB blobout;
  3903. LPWSTR descr;
  3904. BOOL decrypted;
  3905. const char * in = NULL;
  3906. WEBDAV_ERR(auth_ssl_client_cert_pw_get(done, &in, creds, realmstring, username,
  3907. parameters, non_interactive, pool));
  3908. if (!*done)
  3909. return WEBDAV_NO_ERROR;
  3910. blobin.cbData = (DWORD)strlen(in);
  3911. blobin.pbData = static_cast<BYTE *>(apr_pcalloc(pool, apr_base64_decode_len(in)));
  3912. apr_base64_decode((char *)blobin.pbData, in);
  3913. decrypted = CryptUnprotectData(&blobin, &descr, NULL, NULL, NULL,
  3914. CRYPTPROTECT_UI_FORBIDDEN, &blobout);
  3915. if (decrypted)
  3916. {
  3917. if (0 == lstrcmpW(descr, description))
  3918. *out = apr_pstrndup(pool, (const char *)blobout.pbData, blobout.cbData);
  3919. else
  3920. decrypted = FALSE;
  3921. LocalFree(blobout.pbData);
  3922. LocalFree(descr);
  3923. }
  3924. *done = decrypted != 0;
  3925. return WEBDAV_NO_ERROR;
  3926. }
  3927. // Get cached encrypted credentials from the simple provider's cache.
  3928. static error_t
  3929. windows_ssl_client_cert_pw_first_creds(
  3930. void ** credentials,
  3931. void ** iter_baton,
  3932. void * provider_baton,
  3933. apr_hash_t * parameters,
  3934. const char * realmstring,
  3935. apr_pool_t * pool)
  3936. {
  3937. return auth_ssl_client_cert_pw_file_first_creds_helper(
  3938. credentials,
  3939. iter_baton,
  3940. provider_baton,
  3941. parameters,
  3942. realmstring,
  3943. windows_ssl_client_cert_pw_decrypter,
  3944. WEBDAV_AUTH_WINCRYPT_PASSWORD_TYPE,
  3945. pool);
  3946. }
  3947. // Save encrypted credentials to the simple provider's cache.
  3948. static error_t
  3949. windows_ssl_client_cert_pw_save_creds(
  3950. bool * saved,
  3951. void * credentials,
  3952. void * provider_baton,
  3953. apr_hash_t * parameters,
  3954. const char * realmstring,
  3955. apr_pool_t * pool)
  3956. {
  3957. return auth_ssl_client_cert_pw_file_save_creds_helper(
  3958. saved,
  3959. credentials,
  3960. provider_baton,
  3961. parameters,
  3962. realmstring,
  3963. windows_ssl_client_cert_pw_encrypter,
  3964. WEBDAV_AUTH_WINCRYPT_PASSWORD_TYPE,
  3965. pool);
  3966. }
  3967. static const auth_provider_t windows_ssl_client_cert_pw_provider =
  3968. {
  3969. AUTH_CRED_SSL_CLIENT_CERT_PW,
  3970. windows_ssl_client_cert_pw_first_creds,
  3971. NULL,
  3972. windows_ssl_client_cert_pw_save_creds
  3973. };
  3974. // Public API
  3975. static void
  3976. auth_get_windows_ssl_client_cert_pw_provider(
  3977. auth_provider_object_t ** provider,
  3978. apr_pool_t * pool)
  3979. {
  3980. auth_provider_object_t * po =
  3981. static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
  3982. po->vtable = &windows_ssl_client_cert_pw_provider;
  3983. *provider = po;
  3984. }
  3985. /*-----------------------------------------------------------------------*/
  3986. // Windows SSL server trust provider, validates ssl certificate using
  3987. // CryptoApi.
  3988. /*-----------------------------------------------------------------------*/
  3989. // Helper to create CryptoAPI CERT_CONTEXT from base64 encoded BASE64_CERT.
  3990. // Returns NULL on error.
  3991. static PCCERT_CONTEXT
  3992. certcontext_from_base64(
  3993. const char * base64_cert,
  3994. apr_pool_t * pool)
  3995. {
  3996. PCCERT_CONTEXT cert_context = NULL;
  3997. int cert_len = 0;
  3998. BYTE * binary_cert = NULL;
  3999. // Use apr-util as CryptStringToBinaryA is available only on XP+.
  4000. binary_cert = static_cast<BYTE *>(apr_pcalloc(pool,
  4001. apr_base64_decode_len(base64_cert)));
  4002. cert_len = apr_base64_decode((char *)binary_cert, base64_cert);
  4003. // Parse the certificate into a context.
  4004. cert_context = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  4005. binary_cert, cert_len);
  4006. return cert_context;
  4007. }
  4008. // Helper for windows_ssl_server_trust_first_credentials for validating
  4009. // certificate using CryptoApi. Sets *OK_P to TRUE if base64 encoded ASCII_CERT
  4010. // certificate considered as valid.
  4011. static error_t
  4012. windows_validate_certificate(
  4013. bool * ok_p,
  4014. const char * ascii_cert,
  4015. apr_pool_t * pool)
  4016. {
  4017. PCCERT_CONTEXT cert_context = NULL;
  4018. CERT_CHAIN_PARA chain_para;
  4019. PCCERT_CHAIN_CONTEXT chain_context = NULL;
  4020. *ok_p = FALSE;
  4021. // Parse the certificate into a context.
  4022. cert_context = certcontext_from_base64(ascii_cert, pool);
  4023. if (cert_context)
  4024. {
  4025. // Retrieve the certificate chain of the certificate
  4026. // (a certificate without a valid root does not have a chain).
  4027. memset(&chain_para, 0, sizeof(chain_para));
  4028. chain_para.cbSize = sizeof(chain_para);
  4029. HCERTCHAINENGINE chain_engine;
  4030. CERT_CHAIN_ENGINE_CONFIG chain_config;
  4031. chain_config.cbSize = sizeof(CERT_CHAIN_ENGINE_CONFIG);
  4032. chain_config.hRestrictedRoot = NULL;
  4033. chain_config.hRestrictedTrust = NULL;
  4034. chain_config.hRestrictedOther = NULL;
  4035. chain_config.cAdditionalStore = 0;
  4036. chain_config.rghAdditionalStore = NULL;
  4037. chain_config.dwFlags = CERT_CHAIN_CACHE_END_CERT;
  4038. chain_config.dwUrlRetrievalTimeout = 0;
  4039. chain_config.MaximumCachedCertificates =0;
  4040. chain_config.CycleDetectionModulus = 0;
  4041. CertCreateCertificateChainEngine(
  4042. &chain_config,
  4043. &chain_engine);
  4044. if (CertGetCertificateChain(chain_engine, cert_context, NULL, NULL, &chain_para,
  4045. CERT_CHAIN_CACHE_END_CERT |
  4046. CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
  4047. NULL, &chain_context))
  4048. {
  4049. CERT_CHAIN_POLICY_PARA policy_para;
  4050. CERT_CHAIN_POLICY_STATUS policy_status;
  4051. policy_para.cbSize = sizeof(policy_para);
  4052. policy_para.dwFlags = 0;
  4053. policy_para.pvExtraPolicyPara = NULL;
  4054. policy_status.cbSize = sizeof(policy_status);
  4055. if (CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL,
  4056. chain_context, &policy_para,
  4057. &policy_status))
  4058. {
  4059. if (policy_status.dwError == S_OK)
  4060. {
  4061. // Windows thinks the certificate is valid.
  4062. *ok_p = TRUE;
  4063. }
  4064. }
  4065. CertFreeCertificateChain(chain_context);
  4066. }
  4067. CertFreeCertificateContext(cert_context);
  4068. CertFreeCertificateChainEngine(chain_engine);
  4069. }
  4070. return WEBDAV_NO_ERROR;
  4071. }
  4072. // Retrieve ssl server CA failure overrides (if any) from CryptoApi.
  4073. static error_t
  4074. windows_ssl_server_trust_first_credentials(
  4075. void ** credentials,
  4076. void ** iter_baton,
  4077. void * provider_baton,
  4078. apr_hash_t * parameters,
  4079. const char * realmstring,
  4080. apr_pool_t * pool)
  4081. {
  4082. apr_uint32_t * failures = static_cast<apr_uint32_t *>(apr_hash_get(parameters,
  4083. AUTH_PARAM_SSL_SERVER_FAILURES,
  4084. APR_HASH_KEY_STRING));
  4085. const auth_ssl_server_cert_info_t * cert_info =
  4086. static_cast<const auth_ssl_server_cert_info_t *>(apr_hash_get(parameters,
  4087. AUTH_PARAM_SSL_SERVER_CERT_INFO,
  4088. APR_HASH_KEY_STRING));
  4089. *credentials = NULL;
  4090. *iter_baton = NULL;
  4091. // We can accept only unknown certificate authority.
  4092. if (*failures & WEBDAV_AUTH_SSL_UNKNOWNCA)
  4093. {
  4094. bool ok;
  4095. WEBDAV_ERR(windows_validate_certificate(&ok, cert_info->ascii_cert, pool));
  4096. // Windows thinks that certificate is ok.
  4097. if (ok)
  4098. {
  4099. // Clear failure flag.
  4100. *failures &= ~WEBDAV_AUTH_SSL_UNKNOWNCA;
  4101. }
  4102. }
  4103. // If all failures are cleared now, we return the creds
  4104. if (!*failures)
  4105. {
  4106. auth_cred_ssl_server_trust_t * creds =
  4107. static_cast<auth_cred_ssl_server_trust_t *>(apr_pcalloc(pool, sizeof(*creds)));
  4108. creds->may_save = FALSE; // No need to save it.
  4109. *credentials = creds;
  4110. }
  4111. return WEBDAV_NO_ERROR;
  4112. }
  4113. static const auth_provider_t windows_server_trust_provider =
  4114. {
  4115. AUTH_CRED_SSL_SERVER_TRUST,
  4116. windows_ssl_server_trust_first_credentials,
  4117. NULL,
  4118. NULL,
  4119. };
  4120. // Public API
  4121. static void
  4122. auth_get_windows_ssl_server_trust_provider(
  4123. auth_provider_object_t ** provider,
  4124. apr_pool_t * pool)
  4125. {
  4126. auth_provider_object_t * po =
  4127. static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
  4128. po->vtable = &windows_server_trust_provider;
  4129. *provider = po;
  4130. }
  4131. //------------------------------------------------------------------------------
  4132. // from username_providers.c
  4133. // Username-only Provider
  4134. static error_t
  4135. username_first_creds(
  4136. void ** credentials,
  4137. void ** iter_baton,
  4138. void * provider_baton,
  4139. apr_hash_t * parameters,
  4140. const char * realmstring,
  4141. apr_pool_t * pool)
  4142. {
  4143. const char * username = static_cast<const char *>(apr_hash_get(parameters,
  4144. WEBDAV_AUTH_PARAM_DEFAULT_USERNAME,
  4145. APR_HASH_KEY_STRING));
  4146. bool may_save = !!username;
  4147. error_t err = 0;
  4148. // If we don't have a usename yet, try the auth cache
  4149. if (!username)
  4150. {
  4151. apr_hash_t * creds_hash = NULL;
  4152. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
  4153. CONST_FS_KEY,
  4154. APR_HASH_KEY_STRING));
  4155. assert(fs);
  4156. // Try to load credentials from a file on disk, based on the
  4157. // realmstring. Don't throw an error, though: if something went
  4158. // wrong reading the file, no big deal. What really matters is that
  4159. // we failed to get the creds, so allow the auth system to try the
  4160. // next provider.
  4161. err = config_read_auth_data(&creds_hash, WEBDAV_AUTH_CRED_USERNAME,
  4162. realmstring, fs,
  4163. pool);
  4164. error_clear(&err);
  4165. if (!err && creds_hash)
  4166. {
  4167. string_t * str = static_cast<string_t *>(apr_hash_get(creds_hash, AUTHN_USERNAME_KEY,
  4168. APR_HASH_KEY_STRING));
  4169. if (str && str->data)
  4170. username = str->data;
  4171. }
  4172. }
  4173. // If that failed, ask the OS for the username
  4174. if (!username)
  4175. username = user_get_name(pool);
  4176. if (username)
  4177. {
  4178. auth_cred_simple_t * creds =
  4179. static_cast<auth_cred_simple_t *>(apr_pcalloc(pool, sizeof(*creds)));
  4180. creds->username = username;
  4181. creds->may_save = may_save;
  4182. *credentials = creds;
  4183. }
  4184. else
  4185. *credentials = NULL;
  4186. *iter_baton = NULL;
  4187. return WEBDAV_NO_ERROR;
  4188. }
  4189. static error_t
  4190. username_save_creds(
  4191. bool * saved,
  4192. void * credentials,
  4193. void * provider_baton,
  4194. apr_hash_t * parameters,
  4195. const char * realmstring,
  4196. apr_pool_t * pool)
  4197. {
  4198. auth_cred_simple_t * creds =
  4199. static_cast<auth_cred_simple_t *>(credentials);
  4200. apr_hash_t * creds_hash = NULL;
  4201. error_t err;
  4202. *saved = FALSE;
  4203. if (!creds->may_save)
  4204. return WEBDAV_NO_ERROR;
  4205. // Put the credentials in a hash and save it to disk
  4206. creds_hash = apr_hash_make(pool);
  4207. apr_hash_set(creds_hash, AUTHN_USERNAME_KEY, APR_HASH_KEY_STRING,
  4208. string_create(creds->username, pool));
  4209. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
  4210. CONST_FS_KEY,
  4211. APR_HASH_KEY_STRING));
  4212. assert(fs);
  4213. err = config_write_auth_data(creds_hash, WEBDAV_AUTH_CRED_USERNAME,
  4214. realmstring,
  4215. fs,
  4216. pool);
  4217. error_clear(&err);
  4218. *saved = !err;
  4219. return WEBDAV_NO_ERROR;
  4220. }
  4221. static const auth_provider_t username_provider =
  4222. {
  4223. WEBDAV_AUTH_CRED_USERNAME,
  4224. username_first_creds,
  4225. NULL,
  4226. username_save_creds
  4227. };
  4228. // Public API
  4229. static void
  4230. auth_get_username_provider(
  4231. auth_provider_object_t ** provider,
  4232. apr_pool_t * pool)
  4233. {
  4234. auth_provider_object_t * po =
  4235. static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
  4236. po->vtable = &username_provider;
  4237. *provider = po;
  4238. }
  4239. // Baton type for username-only prompting.
  4240. typedef struct username_prompt_provider_baton_t
  4241. {
  4242. auth_username_prompt_func_t prompt_func;
  4243. void * prompt_baton;
  4244. // how many times to re-prompt after the first one fails
  4245. int retry_limit;
  4246. } username_prompt_provider_baton_t;
  4247. // Iteration baton type for username-only prompting.
  4248. typedef struct username_prompt_iter_baton_t
  4249. {
  4250. // how many times we've reprompted
  4251. int retries;
  4252. } username_prompt_iter_baton_t;
  4253. // Helper Functions
  4254. static error_t
  4255. prompt_for_username_creds(
  4256. auth_cred_username_t ** cred_p,
  4257. username_prompt_provider_baton_t * pb,
  4258. apr_hash_t * parameters,
  4259. const char * realmstring,
  4260. bool first_time,
  4261. bool may_save,
  4262. apr_pool_t * pool)
  4263. {
  4264. const char * def_username = NULL;
  4265. *cred_p = NULL;
  4266. // If we're allowed to check for default usernames, do so.
  4267. if (first_time)
  4268. def_username = static_cast<const char *>(apr_hash_get(parameters,
  4269. WEBDAV_AUTH_PARAM_DEFAULT_USERNAME,
  4270. APR_HASH_KEY_STRING));
  4271. // If we have defaults, just build the cred here and return it.
  4272. // I do wonder why this is here instead of in a separate
  4273. // 'defaults' provider that would run before the prompt
  4274. // provider... Hmmm.
  4275. if (def_username)
  4276. {
  4277. *cred_p = static_cast<auth_cred_username_t *>(apr_pcalloc(pool, sizeof(**cred_p)));
  4278. (*cred_p)->username = apr_pstrdup(pool, def_username);
  4279. (*cred_p)->may_save = TRUE;
  4280. }
  4281. else
  4282. {
  4283. WEBDAV_ERR(pb->prompt_func(cred_p, pb->prompt_baton, realmstring,
  4284. may_save, pool));
  4285. }
  4286. return WEBDAV_NO_ERROR;
  4287. }
  4288. // Our first attempt will use any default username passed
  4289. // in, and prompt for the remaining stuff.
  4290. static error_t
  4291. username_prompt_first_creds(
  4292. void ** credentials_p,
  4293. void ** iter_baton,
  4294. void * provider_baton,
  4295. apr_hash_t * parameters,
  4296. const char * realmstring,
  4297. apr_pool_t * pool)
  4298. {
  4299. username_prompt_provider_baton_t * pb =
  4300. static_cast<username_prompt_provider_baton_t *>(provider_baton);
  4301. username_prompt_iter_baton_t * ibaton =
  4302. static_cast<username_prompt_iter_baton_t *>(apr_pcalloc(pool, sizeof(*ibaton)));
  4303. const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
  4304. WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
  4305. APR_HASH_KEY_STRING));
  4306. WEBDAV_ERR(prompt_for_username_creds((auth_cred_username_t **) credentials_p, pb,
  4307. parameters, realmstring, TRUE, !no_auth_cache, pool));
  4308. ibaton->retries = 0;
  4309. *iter_baton = ibaton;
  4310. return WEBDAV_NO_ERROR;
  4311. }
  4312. // Subsequent attempts to fetch will ignore the default username
  4313. // value, and simply re-prompt for the username, up to a maximum of
  4314. // ib->pb->retry_limit.
  4315. static error_t
  4316. username_prompt_next_creds(
  4317. void ** credentials_p,
  4318. void * iter_baton,
  4319. void * provider_baton,
  4320. apr_hash_t * parameters,
  4321. const char * realmstring,
  4322. apr_pool_t * pool)
  4323. {
  4324. username_prompt_iter_baton_t * ib =
  4325. static_cast<username_prompt_iter_baton_t *>(iter_baton);
  4326. username_prompt_provider_baton_t * pb =
  4327. static_cast<username_prompt_provider_baton_t *>(provider_baton);
  4328. const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
  4329. WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
  4330. APR_HASH_KEY_STRING));
  4331. if ((pb->retry_limit >= 0) && (ib->retries >= pb->retry_limit))
  4332. {
  4333. // give up, go on to next provider.
  4334. *credentials_p = NULL;
  4335. return WEBDAV_NO_ERROR;
  4336. }
  4337. ib->retries++;
  4338. return prompt_for_username_creds((auth_cred_username_t **) credentials_p, pb,
  4339. parameters, realmstring, FALSE, !no_auth_cache, pool);
  4340. }
  4341. static const auth_provider_t username_prompt_provider =
  4342. {
  4343. WEBDAV_AUTH_CRED_USERNAME,
  4344. username_prompt_first_creds,
  4345. username_prompt_next_creds,
  4346. NULL,
  4347. };
  4348. // Public API
  4349. static void
  4350. auth_get_username_prompt_provider(
  4351. auth_provider_object_t ** provider,
  4352. auth_username_prompt_func_t prompt_func,
  4353. void * prompt_baton,
  4354. int retry_limit,
  4355. apr_pool_t * pool)
  4356. {
  4357. auth_provider_object_t * po =
  4358. static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
  4359. username_prompt_provider_baton_t * pb =
  4360. static_cast<username_prompt_provider_baton_t *>(apr_pcalloc(pool, sizeof(*pb)));
  4361. pb->prompt_func = prompt_func;
  4362. pb->prompt_baton = prompt_baton;
  4363. pb->retry_limit = retry_limit;
  4364. po->vtable = &username_prompt_provider;
  4365. po->provider_baton = pb;
  4366. *provider = po;
  4367. }
  4368. //------------------------------------------------------------------------------
  4369. // from auth.c
  4370. static void
  4371. auth_baton_set_parameter(
  4372. auth_baton_t * auth_baton,
  4373. const char * name,
  4374. const void * value)
  4375. {
  4376. apr_hash_set(auth_baton->parameters, name, APR_HASH_KEY_STRING, value);
  4377. }
  4378. static const void *
  4379. auth_baton_get_parameter(
  4380. auth_baton_t * auth_baton,
  4381. const char * name)
  4382. {
  4383. return apr_hash_get(auth_baton->parameters, name, APR_HASH_KEY_STRING);
  4384. }
  4385. static error_t
  4386. auth_first_credentials(
  4387. void ** credentials,
  4388. auth_iterstate_t ** state,
  4389. const char * cred_kind,
  4390. const char * realmstring,
  4391. auth_baton_t * auth_baton,
  4392. apr_pool_t * pool)
  4393. {
  4394. int i = 0;
  4395. provider_set_t * table = NULL;
  4396. auth_provider_object_t * provider = NULL;
  4397. void * creds = NULL;
  4398. void * iter_baton = NULL;
  4399. bool got_first = FALSE;
  4400. auth_iterstate_t * iterstate = NULL;
  4401. const char * cache_key = NULL;
  4402. // Get the appropriate table of providers for CRED_KIND.
  4403. table = static_cast<provider_set_t *>(apr_hash_get(auth_baton->tables, cred_kind, APR_HASH_KEY_STRING));
  4404. if (!table)
  4405. return error_createf(WEBDAV_ERR_AUTHN_NO_PROVIDER, NULL,
  4406. "No provider registered for '%s' credentials",
  4407. cred_kind);
  4408. // First, see if we have cached creds in the auth_baton.
  4409. cache_key = apr_pstrcat(pool, cred_kind, ":", realmstring, (char *)NULL);
  4410. creds = static_cast<void *>(apr_hash_get(auth_baton->creds_cache,
  4411. cache_key, APR_HASH_KEY_STRING));
  4412. if (creds)
  4413. {
  4414. got_first = false;
  4415. }
  4416. else
  4417. // If not, find a provider that can give "first" credentials.
  4418. {
  4419. // Find a provider that can give "first" credentials.
  4420. for (i = 0; i < table->providers->nelts; i++)
  4421. {
  4422. provider = APR_ARRAY_IDX(table->providers, i,
  4423. auth_provider_object_t *);
  4424. WEBDAV_ERR(provider->vtable->first_credentials(
  4425. &creds, &iter_baton, provider->provider_baton,
  4426. auth_baton->parameters, realmstring, auth_baton->pool));
  4427. if (creds != NULL)
  4428. {
  4429. got_first = true;
  4430. break;
  4431. }
  4432. }
  4433. }
  4434. if (!creds)
  4435. *state = NULL;
  4436. else
  4437. {
  4438. // Build an abstract iteration state.
  4439. iterstate = static_cast<auth_iterstate_t *>(apr_pcalloc(pool, sizeof(*iterstate)));
  4440. iterstate->table = table;
  4441. iterstate->provider_idx = i;
  4442. iterstate->got_first = got_first;
  4443. iterstate->provider_iter_baton = iter_baton;
  4444. iterstate->realmstring = apr_pstrdup(pool, realmstring);
  4445. iterstate->cache_key = cache_key;
  4446. iterstate->auth_baton = auth_baton;
  4447. *state = iterstate;
  4448. // Put the creds in the cache
  4449. apr_hash_set(auth_baton->creds_cache,
  4450. apr_pstrdup(auth_baton->pool, cache_key),
  4451. APR_HASH_KEY_STRING,
  4452. creds);
  4453. }
  4454. *credentials = creds;
  4455. return WEBDAV_NO_ERROR;
  4456. }
  4457. static error_t
  4458. auth_next_credentials(
  4459. void ** credentials,
  4460. auth_iterstate_t * state,
  4461. apr_pool_t * pool)
  4462. {
  4463. auth_baton_t * auth_baton = state->auth_baton;
  4464. auth_provider_object_t * provider = NULL;
  4465. provider_set_t * table = state->table;
  4466. void * creds = NULL;
  4467. // Continue traversing the table from where we left off.
  4468. for (/* no init */;
  4469. state->provider_idx < table->providers->nelts;
  4470. state->provider_idx++)
  4471. {
  4472. provider = APR_ARRAY_IDX(table->providers,
  4473. state->provider_idx,
  4474. auth_provider_object_t *);
  4475. if (!state->got_first)
  4476. {
  4477. WEBDAV_ERR(provider->vtable->first_credentials(
  4478. &creds, &(state->provider_iter_baton),
  4479. provider->provider_baton, auth_baton->parameters,
  4480. state->realmstring, auth_baton->pool));
  4481. state->got_first = TRUE;
  4482. }
  4483. else
  4484. {
  4485. if (provider->vtable->next_credentials)
  4486. WEBDAV_ERR(provider->vtable->next_credentials(
  4487. &creds, state->provider_iter_baton,
  4488. provider->provider_baton, auth_baton->parameters,
  4489. state->realmstring, auth_baton->pool));
  4490. }
  4491. if (creds != NULL)
  4492. {
  4493. // Put the creds in the cache
  4494. apr_hash_set(auth_baton->creds_cache,
  4495. state->cache_key, APR_HASH_KEY_STRING,
  4496. creds);
  4497. break;
  4498. }
  4499. state->got_first = FALSE;
  4500. }
  4501. *credentials = creds;
  4502. return WEBDAV_NO_ERROR;
  4503. }
  4504. static error_t
  4505. auth_save_credentials(
  4506. auth_iterstate_t * state,
  4507. apr_pool_t * pool)
  4508. {
  4509. int i = 0;
  4510. auth_provider_object_t * provider = NULL;
  4511. bool save_succeeded = FALSE;
  4512. const char * no_auth_cache = NULL;
  4513. auth_baton_t * auth_baton = NULL;
  4514. void * creds = NULL;
  4515. if (!state || state->table->providers->nelts <= state->provider_idx)
  4516. return WEBDAV_NO_ERROR;
  4517. auth_baton = state->auth_baton;
  4518. creds = apr_hash_get(state->auth_baton->creds_cache,
  4519. state->cache_key, APR_HASH_KEY_STRING);
  4520. if (!creds)
  4521. return WEBDAV_NO_ERROR;
  4522. // Do not save the creds if AUTH_PARAM_NO_AUTH_CACHE is set
  4523. no_auth_cache = static_cast<const char *>(apr_hash_get(auth_baton->parameters,
  4524. AUTH_PARAM_NO_AUTH_CACHE,
  4525. APR_HASH_KEY_STRING));
  4526. if (no_auth_cache)
  4527. return WEBDAV_NO_ERROR;
  4528. // First, try to save the creds using the provider that produced them.
  4529. provider = APR_ARRAY_IDX(state->table->providers,
  4530. state->provider_idx,
  4531. auth_provider_object_t *);
  4532. if (provider->vtable->save_credentials)
  4533. WEBDAV_ERR(provider->vtable->save_credentials(&save_succeeded,
  4534. creds,
  4535. provider->provider_baton,
  4536. auth_baton->parameters,
  4537. state->realmstring,
  4538. pool));
  4539. if (save_succeeded)
  4540. return WEBDAV_NO_ERROR;
  4541. // Otherwise, loop from the top of the list, asking every provider
  4542. // to attempt a save. todo: someday optimize so we don't
  4543. // necessarily start from the top of the list.
  4544. for (i = 0; i < state->table->providers->nelts; i++)
  4545. {
  4546. provider = APR_ARRAY_IDX(state->table->providers, i,
  4547. auth_provider_object_t *);
  4548. if (provider->vtable->save_credentials)
  4549. WEBDAV_ERR(provider->vtable->save_credentials(
  4550. &save_succeeded, creds,
  4551. provider->provider_baton,
  4552. auth_baton->parameters,
  4553. state->realmstring,
  4554. pool));
  4555. if (save_succeeded)
  4556. break;
  4557. }
  4558. // notice that at the moment, if no provider can save, there's
  4559. // no way the caller will know.
  4560. return WEBDAV_NO_ERROR;
  4561. }
  4562. static error_t
  4563. auth_get_platform_specific_provider(
  4564. auth_provider_object_t ** provider,
  4565. const char * provider_name,
  4566. const char * provider_type,
  4567. apr_pool_t * pool)
  4568. {
  4569. *provider = NULL;
  4570. {
  4571. if (strcmp(provider_name, "windows") == 0 &&
  4572. strcmp(provider_type, "simple") == 0)
  4573. {
  4574. auth_get_windows_simple_provider(provider, pool);
  4575. }
  4576. else if (strcmp(provider_name, "windows") == 0 &&
  4577. strcmp(provider_type, "ssl_client_cert_pw") == 0)
  4578. {
  4579. auth_get_windows_ssl_client_cert_pw_provider(provider, pool);
  4580. }
  4581. else if (strcmp(provider_name, "windows") == 0 &&
  4582. strcmp(provider_type, "ssl_server_trust") == 0)
  4583. {
  4584. auth_get_windows_ssl_server_trust_provider(provider, pool);
  4585. }
  4586. }
  4587. return WEBDAV_NO_ERROR;
  4588. }
  4589. #define WEBDAV_MAYBE_ADD_PROVIDER(list, p) \
  4590. { if (p) APR_ARRAY_PUSH(list, auth_provider_object_t *) = p; }
  4591. static error_t
  4592. auth_get_platform_specific_client_providers(
  4593. apr_array_header_t ** providers,
  4594. apr_pool_t * pool)
  4595. {
  4596. auth_provider_object_t * provider;
  4597. const char * password_stores_config_option;
  4598. apr_array_header_t * password_stores;
  4599. int i;
  4600. password_stores_config_option = "windows-cryptoapi";
  4601. *providers = apr_array_make(pool, 12, sizeof(auth_provider_object_t *));
  4602. password_stores = cstring_split(password_stores_config_option, " ,", TRUE, pool);
  4603. for (i = 0; i < password_stores->nelts; i++)
  4604. {
  4605. const char * password_store = APR_ARRAY_IDX(password_stores, i,
  4606. const char *);
  4607. // Windows
  4608. if (apr_strnatcmp(password_store, "windows-cryptoapi") == 0)
  4609. {
  4610. WEBDAV_ERR(auth_get_platform_specific_provider(&provider,
  4611. "windows",
  4612. "simple",
  4613. pool));
  4614. WEBDAV_MAYBE_ADD_PROVIDER(*providers, provider);
  4615. WEBDAV_ERR(auth_get_platform_specific_provider(&provider,
  4616. "windows",
  4617. "ssl_client_cert_pw",
  4618. pool));
  4619. WEBDAV_MAYBE_ADD_PROVIDER(*providers, provider);
  4620. continue;
  4621. }
  4622. return error_createf(WEBDAV_ERR_BAD_CONFIG_VALUE, NULL,
  4623. "Invalid config: unknown password store "
  4624. "'%s'",
  4625. password_store);
  4626. }
  4627. return WEBDAV_NO_ERROR;
  4628. }
  4629. //------------------------------------------------------------------------------
  4630. // from dirent_uri.c
  4631. // TRUE if s is the canonical empty path, FALSE otherwise
  4632. #define PATH_IS_EMPTY(s) ((s)[0] == '\0')
  4633. // Path separator for local filesystem
  4634. #define WEBDAV_PATH_LOCAL_SEPARATOR '\\'
  4635. // Path type definition. Used only by internal functions.
  4636. typedef enum path_type_t
  4637. {
  4638. type_uri,
  4639. type_dirent,
  4640. type_relpath
  4641. } path_type_t;
  4642. // Locale insensitive tolower() for converting parts of dirents and urls
  4643. // while canonicalizing
  4644. static char
  4645. canonicalize_to_lower(char c)
  4646. {
  4647. if (!IsUpperCaseLetter(c))
  4648. return c;
  4649. else
  4650. return c - 'A' + 'a';
  4651. }
  4652. // Locale insensitive toupper() for converting parts of dirents and urls
  4653. // while canonicalizing
  4654. static char
  4655. canonicalize_to_upper(char c)
  4656. {
  4657. if (!IsLowerCaseLetter(c))
  4658. return c;
  4659. else
  4660. return c - 'a' + 'A';
  4661. }
  4662. // Return the canonicalized version of PATH, of type TYPE, allocated in POOL.
  4663. static const char *
  4664. canonicalize(
  4665. path_type_t type,
  4666. const char * path,
  4667. apr_pool_t * pool)
  4668. {
  4669. char * canon = NULL, *dst = NULL;
  4670. const char * src = NULL;
  4671. size_t seglen = 0;
  4672. size_t schemelen = 0;
  4673. size_t canon_segments = 0;
  4674. bool url = FALSE;
  4675. char * schema_data = NULL;
  4676. // "" is already canonical, so just return it; note that later code
  4677. // depends on path not being zero-length.
  4678. if (PATH_IS_EMPTY(path))
  4679. {
  4680. assert(type != type_uri);
  4681. return "";
  4682. }
  4683. dst = canon = static_cast<char *>(apr_pcalloc(pool, strlen(path) + 1));
  4684. // If this is supposed to be an URI, it should start with
  4685. // "scheme://". We'll copy the scheme, host name, etc. to DST and
  4686. // set URL = TRUE.
  4687. src = path;
  4688. if (type == type_uri)
  4689. {
  4690. assert(*src != '/');
  4691. while (*src && (*src != '/') && (*src != ':'))
  4692. src++;
  4693. if ((*src == ':') && (*(src+1) == '/') && (*(src+2) == '/'))
  4694. {
  4695. const char * seg;
  4696. url = TRUE;
  4697. // Found a scheme, convert to lowercase and copy to dst.
  4698. src = path;
  4699. while (*src != ':')
  4700. {
  4701. *(dst++) = canonicalize_to_lower((*src++));
  4702. schemelen++;
  4703. }
  4704. *(dst++) = ':';
  4705. *(dst++) = '/';
  4706. *(dst++) = '/';
  4707. src += 3;
  4708. schemelen += 3;
  4709. // This might be the hostname
  4710. seg = src;
  4711. while (*src && (*src != '/') && (*src != '@'))
  4712. src++;
  4713. if (*src == '@')
  4714. {
  4715. // Copy the username & password.
  4716. seglen = src - seg + 1;
  4717. memcpy(dst, seg, seglen);
  4718. dst += seglen;
  4719. src++;
  4720. }
  4721. else
  4722. src = seg;
  4723. // Found a hostname, convert to lowercase and copy to dst.
  4724. while (*src && (*src != '/') && (*src != ':'))
  4725. *(dst++) = canonicalize_to_lower((*src++));
  4726. if (*src == ':')
  4727. {
  4728. // We probably have a port number: Is it a default portnumber
  4729. // which doesn't belong in a canonical url?
  4730. if ((src[1] == '8') && (src[2] == '0') &&
  4731. ((src[3] == '/') || !src[3]) &&
  4732. !strncmp(canon, "http:", 5))
  4733. {
  4734. src += 3;
  4735. }
  4736. else if ((src[1] == '4') && (src[2] == '4') && (src[3] == '3') &&
  4737. ((src[4] == '/') || !src[4]) &&
  4738. !strncmp(canon, "https:", 6))
  4739. {
  4740. src += 4;
  4741. }
  4742. else if ((src[1] == '/') || !src[1])
  4743. {
  4744. src += 1;
  4745. }
  4746. while (*src && (*src != '/'))
  4747. *(dst++) = canonicalize_to_lower((*src++));
  4748. }
  4749. // Copy trailing slash, or null-terminator.
  4750. *(dst) = *(src);
  4751. // Move src and dst forward only if we are not
  4752. // at null-terminator yet.
  4753. if (*src)
  4754. {
  4755. src++;
  4756. dst++;
  4757. schema_data = dst;
  4758. }
  4759. canon_segments = 1;
  4760. }
  4761. }
  4762. // Copy to DST any separator or drive letter that must come before the
  4763. // first regular path segment.
  4764. if (!url && type != type_relpath)
  4765. {
  4766. src = path;
  4767. // If this is an absolute path, then just copy over the initial
  4768. // separator character.
  4769. if (*src == '/')
  4770. {
  4771. *(dst++) = *(src++);
  4772. // On Windows permit two leading separator characters which means an
  4773. // UNC path.
  4774. if ((type == type_dirent) && (*src == '/'))
  4775. *(dst++) = *(src++);
  4776. }
  4777. // On Windows the first segment can be a drive letter, which we normalize
  4778. // to upper case.
  4779. else if ((type == type_dirent) &&
  4780. IsLetter(*src) &&
  4781. (src[1] == ':'))
  4782. {
  4783. *(dst++) = canonicalize_to_upper(*(src++));
  4784. // Leave the ':' to be processed as (or as part of) a path segment
  4785. // by the following code block, so we need not care whether it has
  4786. // a slash after it.
  4787. }
  4788. }
  4789. while (*src)
  4790. {
  4791. // Parse each segment, finding the closing '/' (which might look
  4792. // like '%2F' for URIs).
  4793. const char * next = src;
  4794. size_t slash_len = 0;
  4795. while (*next &&
  4796. (next[0] != '/') &&
  4797. (!((type == type_uri) && (next[0] == '%') && (next[1] == '2') &&
  4798. (canonicalize_to_upper(next[2]) == 'F'))))
  4799. {
  4800. ++next;
  4801. }
  4802. // Record how long our "slash" is.
  4803. if (next[0] == '/')
  4804. slash_len = 1;
  4805. else if ((type == type_uri) && (next[0] == '%'))
  4806. slash_len = 3;
  4807. seglen = next - src;
  4808. if ((seglen == 0) ||
  4809. ((seglen == 1) && (src[0] == '.')) ||
  4810. ((type == type_uri) && (seglen == 3) && (src[0] == '%') && (src[1] == '2') &&
  4811. (canonicalize_to_upper(src[2]) == 'E')))
  4812. {
  4813. // Empty or noop segment, so do nothing. (For URIs, '%2E'
  4814. // is equivalent to '.').
  4815. }
  4816. // If this is the first path segment of a file:// URI and it contains a
  4817. // windows drive letter, convert the drive letter to upper case.
  4818. else if (url && (canon_segments == 1) && (seglen == 2) &&
  4819. (strncmp(canon, "file:", 5) == 0) &&
  4820. IsLowerCaseLetter(src[0]) && (src[1] == ':'))
  4821. {
  4822. *(dst++) = canonicalize_to_upper(src[0]);
  4823. *(dst++) = ':';
  4824. if (*next)
  4825. *(dst++) = *next;
  4826. canon_segments++;
  4827. }
  4828. else
  4829. {
  4830. // An actual segment, append it to the destination path
  4831. memcpy(dst, src, seglen);
  4832. dst += seglen;
  4833. if (slash_len)
  4834. {
  4835. *(dst++) = '/';
  4836. }
  4837. canon_segments++;
  4838. }
  4839. // Skip over trailing slash to the next segment.
  4840. src = next + slash_len;
  4841. }
  4842. *dst = '\0';
  4843. // Skip leading double slashes when there are less than 2
  4844. // canon segments. UNC paths *MUST* have two segments.
  4845. if ((type == type_dirent) && (canon[0] == '/') && (canon[1] == '/'))
  4846. {
  4847. if (canon_segments < 2)
  4848. return canon + 1;
  4849. else
  4850. {
  4851. // Now we're sure this is a valid UNC path, convert the server name
  4852. // (the first path segment) to lowercase as Windows treats it as case
  4853. // insensitive.
  4854. // Note: normally the share name is treated as case insensitive too,
  4855. // but it seems to be possible to configure Samba to treat those as
  4856. // case sensitive, so better leave that alone.
  4857. for (dst = canon + 2; *dst && (*dst != '/'); dst++)
  4858. *dst = canonicalize_to_lower(*dst);
  4859. }
  4860. }
  4861. // Check the normalization of characters in a uri
  4862. if (schema_data)
  4863. {
  4864. int need_extra = 0;
  4865. src = schema_data;
  4866. while (*src)
  4867. {
  4868. switch (*src)
  4869. {
  4870. case '/':
  4871. break;
  4872. case '%':
  4873. if (!ctype_isxdigit(*(src+1)) ||
  4874. !ctype_isxdigit(*(src+2)))
  4875. need_extra += 2;
  4876. else
  4877. src += 2;
  4878. break;
  4879. default:
  4880. if (!uri_char_validity[(unsigned char)*src])
  4881. need_extra += 2;
  4882. break;
  4883. }
  4884. src++;
  4885. }
  4886. if (need_extra > 0)
  4887. {
  4888. size_t pre_schema_size = (size_t)(schema_data - canon);
  4889. dst = static_cast<char *>(apr_pcalloc(pool, (size_t)(src - canon) + need_extra + 1));
  4890. memcpy(dst, canon, pre_schema_size);
  4891. canon = dst;
  4892. dst += pre_schema_size;
  4893. }
  4894. else
  4895. dst = schema_data;
  4896. src = schema_data;
  4897. while (*src)
  4898. {
  4899. switch (*src)
  4900. {
  4901. case '/':
  4902. *(dst++) = '/';
  4903. break;
  4904. case '%':
  4905. if (!ctype_isxdigit(*(src+1)) ||
  4906. !ctype_isxdigit(*(src+2)))
  4907. {
  4908. *(dst++) = '%';
  4909. *(dst++) = '2';
  4910. *(dst++) = '5';
  4911. }
  4912. else
  4913. {
  4914. char digitz[3];
  4915. int val;
  4916. digitz[0] = *(++src);
  4917. digitz[1] = *(++src);
  4918. digitz[2] = 0;
  4919. val = (int)strtol(digitz, NULL, 16);
  4920. if (uri_char_validity[(unsigned char)val])
  4921. *(dst++) = (char)val;
  4922. else
  4923. {
  4924. *(dst++) = '%';
  4925. *(dst++) = canonicalize_to_upper(digitz[0]);
  4926. *(dst++) = canonicalize_to_upper(digitz[1]);
  4927. }
  4928. }
  4929. break;
  4930. default:
  4931. if (!uri_char_validity[(unsigned char)*src])
  4932. {
  4933. apr_snprintf(dst, 4, "%%%02X", (unsigned char)*src);
  4934. dst += 3;
  4935. }
  4936. else
  4937. *(dst++) = *src;
  4938. break;
  4939. }
  4940. src++;
  4941. }
  4942. *dst = '\0';
  4943. }
  4944. return canon;
  4945. }
  4946. static const char *
  4947. uri_canonicalize(
  4948. const char * uri,
  4949. apr_pool_t * pool)
  4950. {
  4951. return canonicalize(type_uri, uri, pool);
  4952. }
  4953. static const char *
  4954. relpath_canonicalize(
  4955. const char * relpath,
  4956. apr_pool_t * pool)
  4957. {
  4958. return canonicalize(type_relpath, relpath, pool);
  4959. }
  4960. static const char *
  4961. fspath_canonicalize(
  4962. const char * fspath,
  4963. apr_pool_t * pool)
  4964. {
  4965. if ((fspath[0] == '/') && (fspath[1] == '\0'))
  4966. return "/";
  4967. return apr_pstrcat(pool, "/", relpath_canonicalize(fspath, pool),
  4968. (char *)NULL);
  4969. }
  4970. // Examine PATH as a potential URI, and return a substring of PATH
  4971. // that immediately follows the (scheme):// portion of the URI, or
  4972. // NULL if PATH doesn't appear to be a valid URI. The returned value
  4973. // is not allocated -- it shares memory with PATH.
  4974. static const char *
  4975. skip_uri_scheme(
  4976. const char * path)
  4977. {
  4978. size_t j = 0;
  4979. // A scheme is terminated by a : and cannot contain any /'s.
  4980. for (j = 0; path[j] && (path[j] != ':'); ++j)
  4981. if (path[j] == '/')
  4982. return NULL;
  4983. if ((j > 0) && (path[j] == ':') && (path[j+1] == '/') && (path[j+2] == '/'))
  4984. return path + j + 3;
  4985. return NULL;
  4986. }
  4987. static bool
  4988. path_is_url(
  4989. const char * path)
  4990. {
  4991. // This function is reaaaaaaaaaaaaaally stupid right now.
  4992. // We're just going to look for:
  4993. // (scheme)://(optional_stuff)
  4994. // Where (scheme) has no ':' or '/' characters.
  4995. // Someday it might be nice to have an actual URI parser here.
  4996. return skip_uri_scheme(path) != NULL;
  4997. }
  4998. static const char *
  4999. urlpath_canonicalize(
  5000. const char * uri,
  5001. apr_pool_t * pool)
  5002. {
  5003. if (path_is_url(uri))
  5004. {
  5005. uri = uri_canonicalize(uri, pool);
  5006. }
  5007. else
  5008. {
  5009. uri = fspath_canonicalize(uri, pool);
  5010. // Do a little dance to normalize hex encoding.
  5011. uri = path_uri_decode(uri, pool);
  5012. uri = path_uri_encode(uri, pool);
  5013. }
  5014. return uri;
  5015. }
  5016. // We decided against using apr_filepath_root here because of the negative
  5017. // performance impact (creating a pool and converting strings ).
  5018. static bool
  5019. dirent_is_root(
  5020. const char * dirent,
  5021. apr_size_t len)
  5022. {
  5023. // On Windows and Cygwin, 'H:' or 'H:/' (where 'H' is any letter)
  5024. // are also root directories
  5025. if ((len == 2 || ((len == 3) && (dirent[2] == '/'))) &&
  5026. (dirent[1] == ':') &&
  5027. IsLetter(dirent[0]))
  5028. return TRUE;
  5029. // On Windows and Cygwin //server/share is a root directory,
  5030. // and on Cygwin //drive is a drive alias
  5031. if ((len >= 2) && (dirent[0] == '/') && (dirent[1] == '/') &&
  5032. (dirent[len - 1] != '/'))
  5033. {
  5034. int segments = 0;
  5035. for (size_t i = len; i >= 2; i--)
  5036. {
  5037. if (dirent[i] == '/')
  5038. {
  5039. segments++;
  5040. if (segments > 1)
  5041. return FALSE;
  5042. }
  5043. }
  5044. return (segments == 1); // //drive is invalid on plain Windows
  5045. }
  5046. // directory is root if it's equal to '/'
  5047. if ((len == 1) && (dirent[0] == '/'))
  5048. return TRUE;
  5049. return FALSE;
  5050. }
  5051. static bool
  5052. relpath_is_canonical(
  5053. const char * relpath)
  5054. {
  5055. const char * ptr = relpath, *seg = relpath;
  5056. // RELPATH is canonical if it has:
  5057. // - no '.' segments
  5058. // - no start and closing '/'
  5059. // - no '//'
  5060. if (*relpath == '\0')
  5061. return TRUE;
  5062. if (*ptr == '/')
  5063. return FALSE;
  5064. // Now validate the rest of the path.
  5065. while (1)
  5066. {
  5067. apr_size_t seglen = ptr - seg;
  5068. if ((seglen == 1) && (*seg == '.'))
  5069. return FALSE; // /./
  5070. if ((*ptr == '/') && (*(ptr+1) == '/'))
  5071. return FALSE; // //
  5072. if (!*ptr && (*(ptr - 1) == '/'))
  5073. return FALSE; // foo/
  5074. if (!*ptr)
  5075. break;
  5076. if (*ptr == '/')
  5077. ptr++;
  5078. seg = ptr;
  5079. while (*ptr && (*ptr != '/'))
  5080. ptr++;
  5081. }
  5082. return TRUE;
  5083. }
  5084. static const char *
  5085. relpath_basename(
  5086. const char * relpath,
  5087. apr_pool_t * pool)
  5088. {
  5089. apr_size_t len = strlen(relpath);
  5090. apr_size_t start = 0;
  5091. assert(relpath_is_canonical(relpath));
  5092. start = len;
  5093. while ((start > 0) && (relpath[start - 1] != '/'))
  5094. --start;
  5095. if (pool)
  5096. return apr_pstrmemdup(pool, relpath + start, len - start);
  5097. else
  5098. return relpath + start;
  5099. }
  5100. static char *
  5101. relpath_join(
  5102. const char * base,
  5103. const char * component,
  5104. apr_pool_t * pool)
  5105. {
  5106. apr_size_t blen = strlen(base);
  5107. apr_size_t clen = strlen(component);
  5108. char * path = NULL;
  5109. assert(relpath_is_canonical(base));
  5110. assert(relpath_is_canonical(component));
  5111. // If either is empty return the other
  5112. if (blen == 0)
  5113. return static_cast<char *>(apr_pmemdup(pool, component, clen + 1));
  5114. if (clen == 0)
  5115. return static_cast<char *>(apr_pmemdup(pool, base, blen + 1));
  5116. path = static_cast<char *>(apr_pcalloc(pool, blen + 1 + clen + 1));
  5117. memcpy(path, base, blen);
  5118. path[blen] = '/';
  5119. memcpy(path + blen + 1, component, clen + 1);
  5120. return path;
  5121. }
  5122. static const char *
  5123. dirent_canonicalize(
  5124. const char * dirent,
  5125. apr_pool_t * pool)
  5126. {
  5127. const char * dst = canonicalize(type_dirent, dirent, pool);
  5128. // Handle a specific case on Windows where path == "X:/". Here we have to
  5129. // append the final '/', as path_canonicalize will chop this of.
  5130. if (IsLetter(dirent[0]) &&
  5131. (dirent[1] == ':') && (dirent[2] == '/') &&
  5132. (dst[3] == '\0'))
  5133. {
  5134. char * dst_slash = static_cast<char *>(apr_pcalloc(pool, 4));
  5135. dst_slash[0] = canonicalize_to_upper(dirent[0]);
  5136. dst_slash[1] = ':';
  5137. dst_slash[2] = '/';
  5138. dst_slash[3] = '\0';
  5139. return dst_slash;
  5140. }
  5141. return dst;
  5142. }
  5143. static bool
  5144. dirent_is_canonical(
  5145. const char * dirent,
  5146. apr_pool_t * pool)
  5147. {
  5148. const char * ptr = dirent;
  5149. if (*ptr == '/')
  5150. {
  5151. ptr++;
  5152. // Check for UNC paths
  5153. if (*ptr == '/')
  5154. {
  5155. // TODO: Scan hostname and sharename and fall back to part code
  5156. // Fall back to old implementation
  5157. return (strcmp(dirent, dirent_canonicalize(dirent, pool)) == 0);
  5158. }
  5159. }
  5160. else if (IsLetter(*ptr) &&
  5161. (ptr[1] == ':'))
  5162. {
  5163. // The only canonical drive names are "A:"..."Z:", no lower case
  5164. if (!IsUpperCaseLetter(*ptr))
  5165. return FALSE;
  5166. ptr += 2;
  5167. if (*ptr == '/')
  5168. ptr++;
  5169. }
  5170. return relpath_is_canonical(ptr);
  5171. }
  5172. static const char *
  5173. dirent_basename(
  5174. const char * dirent,
  5175. apr_pool_t * pool)
  5176. {
  5177. apr_size_t len = strlen(dirent);
  5178. apr_size_t start = 0;
  5179. assert(!pool || dirent_is_canonical(dirent, pool));
  5180. if (dirent_is_root(dirent, len))
  5181. {
  5182. return "";
  5183. }
  5184. else
  5185. {
  5186. start = len;
  5187. while ((start > 0) && (dirent[start - 1] != '/') &&
  5188. (dirent[start - 1] != ':'))
  5189. {
  5190. --start;
  5191. }
  5192. }
  5193. if (pool)
  5194. return apr_pstrmemdup(pool, dirent + start, len - start);
  5195. else
  5196. return dirent + start;
  5197. }
  5198. static const char *
  5199. uri_skip_ancestor(
  5200. const char * parent_uri,
  5201. const char * child_uri)
  5202. {
  5203. apr_size_t len = strlen(parent_uri);
  5204. if (0 != strncmp(parent_uri, child_uri, len))
  5205. return NULL; // parent_uri is no ancestor of child_uri
  5206. if (child_uri[len] == 0)
  5207. return ""; // parent_uri == child_uri
  5208. if (child_uri[len] == '/')
  5209. return child_uri + len + 1;
  5210. return NULL;
  5211. }
  5212. static const char *
  5213. uri_skip_ancestor(
  5214. const char * parent_uri,
  5215. const char * child_uri,
  5216. apr_pool_t * result_pool)
  5217. {
  5218. const char * result = uri_skip_ancestor(parent_uri, child_uri);
  5219. return result ? path_uri_decode(result, result_pool) : NULL;
  5220. }
  5221. static bool
  5222. dirent_is_rooted(
  5223. const char * dirent)
  5224. {
  5225. if (!dirent)
  5226. return FALSE;
  5227. // Root on all systems
  5228. if (dirent[0] == '/')
  5229. return TRUE;
  5230. // On Windows, dirent is also absolute when it starts with 'H:' or 'H:/'
  5231. // where 'H' is any letter.
  5232. if (IsLetter(dirent[0]) &&
  5233. (dirent[1] == ':'))
  5234. {
  5235. return TRUE;
  5236. }
  5237. return FALSE;
  5238. }
  5239. static const char *
  5240. is_child(
  5241. path_type_t type,
  5242. const char * path1,
  5243. const char * path2,
  5244. apr_pool_t * pool)
  5245. {
  5246. apr_size_t i = 0;
  5247. // Allow "" and "foo" or "H:foo" to be parent/child
  5248. if (WEBDAV_PATH_IS_EMPTY(path1)) // "" is the parent
  5249. {
  5250. if (WEBDAV_PATH_IS_EMPTY(path2)) // "" not a child
  5251. {
  5252. return NULL;
  5253. }
  5254. // check if this is an absolute path
  5255. if ((type == type_uri) ||
  5256. (type == type_dirent && dirent_is_rooted(path2)))
  5257. {
  5258. return NULL;
  5259. }
  5260. else
  5261. {
  5262. // everything else is child
  5263. return pool ? apr_pstrdup(pool, path2) : path2;
  5264. }
  5265. }
  5266. for (i = 0; path1[i] && path2[i]; i++)
  5267. if (path1[i] != path2[i])
  5268. {
  5269. return NULL;
  5270. }
  5271. /* FIXME: This comment does not really match
  5272. the checks made in the code it refers to:
  5273. There are two cases that are parent/child
  5274. ... path1[i] == '\0'
  5275. .../foo path2[i] == '/'
  5276. or
  5277. / path1[i] == '\0'
  5278. /foo path2[i] != '/'
  5279. Other root paths (like X:/) fall under the former case:
  5280. X:/ path1[i] == '\0'
  5281. X:/foo path2[i] != '/'
  5282. Check for '//' to avoid matching '/' and '//srv'.
  5283. */
  5284. if ((path1[i] == '\0') && path2[i])
  5285. {
  5286. if ((path1[i - 1] == '/') ||
  5287. ((type == type_dirent) && path1[i - 1] == ':'))
  5288. {
  5289. if (path2[i] == '/')
  5290. /* .../
  5291. * ..../
  5292. * i */
  5293. return NULL;
  5294. else
  5295. /* .../
  5296. * .../foo
  5297. * i */
  5298. return pool ? apr_pstrdup(pool, path2 + i) : path2 + i;
  5299. }
  5300. else if (path2[i] == '/')
  5301. {
  5302. if (path2[i + 1])
  5303. /* ...
  5304. * .../foo
  5305. * i */
  5306. return pool ? apr_pstrdup(pool, path2 + i + 1) : path2 + i + 1;
  5307. else
  5308. /* ...
  5309. * .../
  5310. * i */
  5311. return NULL;
  5312. }
  5313. }
  5314. // Otherwise, path2 isn't a child.
  5315. return NULL;
  5316. }
  5317. static const char *
  5318. uri_is_child(
  5319. const char * parent_uri,
  5320. const char * child_uri,
  5321. apr_pool_t * pool)
  5322. {
  5323. const char * relpath = NULL;
  5324. assert(pool); // hysterical raisins.
  5325. relpath = is_child(type_uri, parent_uri, child_uri, pool);
  5326. if (relpath)
  5327. relpath = path_uri_decode(relpath, pool);
  5328. return relpath;
  5329. }
  5330. static bool
  5331. dirent_is_absolute(
  5332. const char * dirent)
  5333. {
  5334. if (!dirent)
  5335. return FALSE;
  5336. // dirent is absolute if it starts with '/' on non-Windows platforms
  5337. // or with '//' on Windows platforms
  5338. if ((dirent[0] == '/') &&
  5339. (dirent[1] == '/')) // Single '/' depends on current drive
  5340. {
  5341. return TRUE;
  5342. }
  5343. // On Windows, dirent is also absolute when it starts with 'H:/'
  5344. // where 'H' is any letter.
  5345. if (IsUpperCaseLetter(dirent[0]) &&
  5346. (dirent[1] == ':') && (dirent[2] == '/'))
  5347. {
  5348. return TRUE;
  5349. }
  5350. return FALSE;
  5351. }
  5352. static error_t
  5353. dirent_get_absolute(
  5354. const char ** pabsolute,
  5355. const char * relative,
  5356. apr_pool_t * pool)
  5357. {
  5358. char * buffer = NULL;
  5359. apr_status_t apr_err = 0;
  5360. const char * path_apr = NULL;
  5361. WEBDAV_ERR_ASSERT(!path_is_url(relative));
  5362. // Merge the current working directory with the relative dirent.
  5363. WEBDAV_ERR(path_cstring_from_utf8(&path_apr, relative, pool));
  5364. apr_err = apr_filepath_merge(&buffer, NULL,
  5365. path_apr,
  5366. APR_FILEPATH_NOTRELATIVE,
  5367. pool);
  5368. if (apr_err)
  5369. {
  5370. // In some cases when the passed path or its ancestor(s) do not exist
  5371. // or no longer exist apr returns an error.
  5372. // In many of these cases we would like to return a path anyway, when the
  5373. // passed path was already a safe absolute path. So check for that now to
  5374. // avoid an error.
  5375. // dirent_is_absolute() doesn't perform the necessary checks to see
  5376. // if the path doesn't need post processing to be in the canonical absolute
  5377. // format.
  5378. if (dirent_is_absolute(relative) &&
  5379. dirent_is_canonical(relative, pool) &&
  5380. !path_is_backpath_present(relative))
  5381. {
  5382. *pabsolute = apr_pstrdup(pool, relative);
  5383. return WEBDAV_NO_ERROR;
  5384. }
  5385. return error_createf(WEBDAV_ERR_BAD_FILENAME,
  5386. NULL,
  5387. "Couldn't determine absolute path of '%s'", relative);
  5388. }
  5389. WEBDAV_ERR(path_cstring_to_utf8(pabsolute, buffer, pool));
  5390. *pabsolute = dirent_canonicalize(*pabsolute, pool);
  5391. return WEBDAV_NO_ERROR;
  5392. }
  5393. //------------------------------------------------------------------------------
  5394. // from atomic.c
  5395. #define atomic_t apr_uint32_t
  5396. // Magic values for atomic initialization
  5397. #define WEBDAV_ATOMIC_UNINITIALIZED 0
  5398. #define WEBDAV_ATOMIC_START_INIT 1
  5399. #define WEBDAV_ATOMIC_INIT_FAILED 2
  5400. #define WEBDAV_ATOMIC_INITIALIZED 3
  5401. static error_t
  5402. atomic_init_once(
  5403. volatile atomic_t * global_status,
  5404. error_t (*init_func)(void *,apr_pool_t *),
  5405. void * baton,
  5406. apr_pool_t * pool)
  5407. {
  5408. // We have to call init_func exactly once. Because APR
  5409. // doesn't have statically-initialized mutexes, we implement a poor
  5410. // man's spinlock using atomic_cas.
  5411. atomic_t status = apr_atomic_cas32(global_status,
  5412. WEBDAV_ATOMIC_START_INIT,
  5413. WEBDAV_ATOMIC_UNINITIALIZED);
  5414. if (status == WEBDAV_ATOMIC_UNINITIALIZED)
  5415. {
  5416. error_t err = init_func(baton, pool);
  5417. if (err)
  5418. {
  5419. #if APR_HAS_THREADS
  5420. // Tell other threads that the initialization failed.
  5421. apr_atomic_cas32(global_status,
  5422. WEBDAV_ATOMIC_INIT_FAILED,
  5423. WEBDAV_ATOMIC_START_INIT);
  5424. #endif
  5425. return error_create(WEBDAV_ERR_ATOMIC_INIT_FAILURE, &err,
  5426. "Couldn't perform atomic initialization");
  5427. }
  5428. apr_atomic_cas32(global_status,
  5429. WEBDAV_ATOMIC_INITIALIZED,
  5430. WEBDAV_ATOMIC_START_INIT);
  5431. }
  5432. #if APR_HAS_THREADS
  5433. // Wait for whichever thread is performing initialization to finish.
  5434. // XXX FIXME: Should we have a maximum wait here, like we have in
  5435. // the Windows file IO spinner?
  5436. else while (status != WEBDAV_ATOMIC_INITIALIZED)
  5437. {
  5438. if (status == WEBDAV_ATOMIC_INIT_FAILED)
  5439. return error_create(WEBDAV_ERR_ATOMIC_INIT_FAILURE, NULL,
  5440. "Couldn't perform atomic initialization");
  5441. apr_sleep(APR_USEC_PER_SEC / 1000);
  5442. status = apr_atomic_cas32(global_status,
  5443. WEBDAV_ATOMIC_UNINITIALIZED,
  5444. WEBDAV_ATOMIC_UNINITIALIZED);
  5445. }
  5446. #endif // APR_HAS_THREADS
  5447. return WEBDAV_NO_ERROR;
  5448. }
  5449. //------------------------------------------------------------------------------
  5450. // from io.c
  5451. #define RETRY_MAX_ATTEMPTS 2
  5452. #define RETRY_INITIAL_SLEEP 1000
  5453. #define RETRY_MAX_SLEEP 128000
  5454. // Suppress warning: Condition is always true
  5455. #pragma warn -8008
  5456. #define RETRY_LOOP(err, expr, retry_test, sleep_test) \
  5457. do \
  5458. { \
  5459. apr_status_t os_err = APR_TO_OS_ERROR(err); \
  5460. int sleep_count = RETRY_INITIAL_SLEEP; \
  5461. int retries; \
  5462. for (retries = 0; \
  5463. retries < RETRY_MAX_ATTEMPTS && (retry_test); \
  5464. os_err = APR_TO_OS_ERROR(err)) \
  5465. { \
  5466. if (sleep_test) \
  5467. { \
  5468. ++retries; \
  5469. apr_sleep(sleep_count); \
  5470. if (sleep_count < RETRY_MAX_SLEEP) \
  5471. sleep_count *= 2; \
  5472. } \
  5473. (err) = (expr); \
  5474. } \
  5475. } \
  5476. while (0)
  5477. #if defined(EDEADLK) && APR_HAS_THREADS
  5478. #define FILE_LOCK_RETRY_LOOP(err, expr) \
  5479. RETRY_LOOP(err, \
  5480. expr, \
  5481. (APR_STATUS_IS_EINTR(err) || os_err == EDEADLK), \
  5482. (!APR_STATUS_IS_EINTR(err)))
  5483. #else
  5484. #define FILE_LOCK_RETRY_LOOP(err, expr) \
  5485. RETRY_LOOP(err, \
  5486. expr, \
  5487. (APR_STATUS_IS_EINTR(err)), \
  5488. 0)
  5489. #endif
  5490. #ifndef WIN32_RETRY_LOOP
  5491. #if !defined(WEBDAV_NO_WIN32_RETRY_LOOP)
  5492. #define WIN32_RETRY_LOOP(err, expr) \
  5493. RETRY_LOOP(err, expr, (os_err == ERROR_ACCESS_DENIED || \
  5494. os_err == ERROR_SHARING_VIOLATION || \
  5495. os_err == ERROR_DIR_NOT_EMPTY), \
  5496. 1)
  5497. #else
  5498. #define WIN32_RETRY_LOOP(err, expr) ((void)0)
  5499. #endif
  5500. #endif
  5501. // Not specifying any of these means no removal at all.
  5502. typedef enum io_file_del_t
  5503. {
  5504. // No deletion ever
  5505. io_file_del_none = 0,
  5506. // Remove when the file is closed
  5507. io_file_del_on_close,
  5508. // Remove when the associated pool is cleared
  5509. io_file_del_on_pool_cleanup
  5510. } io_file_del_t;
  5511. // Wrapper for apr_file_open(), taking an APR-encoded filename.
  5512. static apr_status_t
  5513. file_open(
  5514. apr_file_t ** file,
  5515. const char * fname_apr,
  5516. apr_int32_t flags,
  5517. apr_fileperms_t perm,
  5518. bool retry_on_failure,
  5519. apr_pool_t * pool)
  5520. {
  5521. apr_status_t status = apr_file_open(file, fname_apr, flags, perm, pool);
  5522. if (retry_on_failure)
  5523. {
  5524. WIN32_RETRY_LOOP(status, apr_file_open(file, fname_apr, flags, perm, pool));
  5525. }
  5526. return status;
  5527. }
  5528. #pragma warn +8008
  5529. static error_t
  5530. io_file_open(
  5531. apr_file_t ** new_file,
  5532. const char * fname,
  5533. apr_int32_t flags,
  5534. apr_fileperms_t perms,
  5535. apr_pool_t * pool)
  5536. {
  5537. const char * fname_apr = NULL;
  5538. apr_status_t status = 0;
  5539. WEBDAV_ERR(cstring_from_utf8(&fname_apr, fname, pool));
  5540. status = file_open(new_file, fname_apr, flags | APR_BINARY, perms,
  5541. /* retry_on_failure */ FALSE,
  5542. pool);
  5543. if (status)
  5544. return error_wrap_apr(status, "Can't open file '%s'", fname);
  5545. else
  5546. return WEBDAV_NO_ERROR;
  5547. }
  5548. static error_t
  5549. io_file_open_writable(
  5550. apr_file_t ** new_file,
  5551. apr_os_file_t * thefile,
  5552. apr_int32_t flags,
  5553. apr_pool_t * pool)
  5554. {
  5555. apr_status_t status = 0;
  5556. status = apr_os_file_put(new_file, thefile,
  5557. flags | APR_BINARY,
  5558. pool);
  5559. if (status)
  5560. return error_wrap_apr(status, "Can't open file");
  5561. else
  5562. return WEBDAV_NO_ERROR;
  5563. }
  5564. // Wrapper for apr_file_name_get(), passing out a UTF8-encoded filename.
  5565. static error_t
  5566. io_file_name_get(
  5567. const char ** filename,
  5568. apr_file_t * file,
  5569. apr_pool_t * pool)
  5570. {
  5571. const char * fname_apr = NULL;
  5572. apr_status_t status = 0;
  5573. status = apr_file_name_get(&fname_apr, file);
  5574. if (status)
  5575. return error_wrap_apr(status, "Can't get file name");
  5576. if (fname_apr)
  5577. WEBDAV_ERR(path_cstring_to_utf8(filename, fname_apr, pool));
  5578. else
  5579. *filename = NULL;
  5580. return WEBDAV_NO_ERROR;
  5581. }
  5582. static APR_INLINE error_t
  5583. do_io_file_wrapper_cleanup(
  5584. apr_file_t * file,
  5585. apr_status_t status,
  5586. const char * msg,
  5587. const char * msg_no_name,
  5588. apr_pool_t * pool)
  5589. {
  5590. const char * name = NULL;
  5591. error_t err = 0;
  5592. if (!status)
  5593. return WEBDAV_NO_ERROR;
  5594. err = io_file_name_get(&name, file, pool);
  5595. if (err)
  5596. name = NULL;
  5597. error_clear(&err);
  5598. // Issue #3014: Return a specific error for broken pipes,
  5599. // with a single element in the error chain.
  5600. if (APR_STATUS_IS_EPIPE(status))
  5601. return error_create(WEBDAV_ERR_IO_PIPE_WRITE_ERROR, NULL, NULL);
  5602. if (name)
  5603. return error_wrap_apr(status, msg, name);
  5604. else
  5605. return error_wrap_apr(status, "%s", msg_no_name);
  5606. }
  5607. static error_t
  5608. io_file_close(
  5609. apr_file_t * file,
  5610. apr_pool_t * pool)
  5611. {
  5612. return do_io_file_wrapper_cleanup(file, apr_file_close(file),
  5613. "Can't close file '%s'",
  5614. "Can't close stream",
  5615. pool);
  5616. }
  5617. static error_t
  5618. io_file_getc(
  5619. char * ch,
  5620. apr_file_t * file,
  5621. apr_pool_t * pool)
  5622. {
  5623. return do_io_file_wrapper_cleanup(file, apr_file_getc(ch, file),
  5624. "Can't read file '%s'",
  5625. "Can't read stream",
  5626. pool);
  5627. }
  5628. static error_t
  5629. io_file_write_full(
  5630. apr_file_t * file,
  5631. const void * buf,
  5632. apr_size_t nbytes,
  5633. apr_size_t * bytes_written,
  5634. apr_pool_t * pool)
  5635. {
  5636. // We cannot simply call apr_file_write_full on Win32 as it may fail
  5637. // for larger values of NBYTES. In that case, we have to emulate the
  5638. // "_full" part here. Thus, always call apr_file_write directly on
  5639. // Win32 as this minimizes overhead for small data buffers.
  5640. #define MAXBUFSIZE 64*1024
  5641. apr_size_t bw = nbytes;
  5642. apr_size_t to_write = nbytes;
  5643. // try a simple "write everything at once" first
  5644. apr_status_t rv = apr_file_write(file, buf, &bw);
  5645. buf = (char *)buf + bw;
  5646. to_write -= bw;
  5647. // if the OS cannot handle that, use smaller chunks
  5648. if ((rv == APR_FROM_OS_ERROR(ERROR_NOT_ENOUGH_MEMORY)) &&
  5649. (nbytes > MAXBUFSIZE))
  5650. {
  5651. do
  5652. {
  5653. bw = to_write > MAXBUFSIZE ? MAXBUFSIZE : to_write;
  5654. rv = apr_file_write(file, buf, &bw);
  5655. buf = (char *)buf + bw;
  5656. to_write -= bw;
  5657. }
  5658. while (rv == APR_SUCCESS && to_write > 0);
  5659. }
  5660. // bytes_written may actually be NULL
  5661. if (bytes_written)
  5662. *bytes_written = nbytes - to_write;
  5663. #undef MAXBUFSIZE
  5664. return error_trace(do_io_file_wrapper_cleanup(file, rv,
  5665. "Can't write to file '%s'",
  5666. "Can't write to stream",
  5667. pool));
  5668. }
  5669. static error_t
  5670. io_file_seek(
  5671. apr_file_t * file,
  5672. apr_seek_where_t where,
  5673. apr_off_t * offset,
  5674. apr_pool_t * pool)
  5675. {
  5676. return do_io_file_wrapper_cleanup(file, apr_file_seek(file, where, offset),
  5677. "Can't set position pointer in file '%s'",
  5678. "Can't set position pointer in stream",
  5679. pool);
  5680. }
  5681. static error_t
  5682. io_file_putc(
  5683. char ch,
  5684. apr_file_t * file,
  5685. apr_pool_t * pool)
  5686. {
  5687. return do_io_file_wrapper_cleanup(file, apr_file_putc(ch, file),
  5688. "Can't write file '%s'",
  5689. "Can't write stream",
  5690. pool);
  5691. }
  5692. static error_t
  5693. io_file_read(
  5694. apr_file_t * file,
  5695. void * buf,
  5696. apr_size_t * nbytes,
  5697. apr_pool_t * pool)
  5698. {
  5699. return do_io_file_wrapper_cleanup(file, apr_file_read(file, buf, nbytes),
  5700. "Can't read file '%s'",
  5701. "Can't read stream",
  5702. pool);
  5703. }
  5704. // Local wrapper of path_cstring_from_utf8() that does no copying on
  5705. // operating systems where APR always uses utf-8 as native path format
  5706. static error_t
  5707. cstring_from_utf8(
  5708. const char ** path_apr,
  5709. const char * path_utf8,
  5710. apr_pool_t * pool)
  5711. {
  5712. *path_apr = path_utf8;
  5713. return WEBDAV_NO_ERROR;
  5714. }
  5715. static error_t
  5716. io_file_read_full2(
  5717. apr_file_t * file,
  5718. void * buf,
  5719. apr_size_t nbytes,
  5720. apr_size_t * bytes_read,
  5721. bool * hit_eof,
  5722. apr_pool_t * pool)
  5723. {
  5724. apr_status_t status = apr_file_read_full(file, buf, nbytes, bytes_read);
  5725. if (hit_eof)
  5726. {
  5727. if (APR_STATUS_IS_EOF(status))
  5728. {
  5729. *hit_eof = TRUE;
  5730. return WEBDAV_NO_ERROR;
  5731. }
  5732. else
  5733. *hit_eof = FALSE;
  5734. }
  5735. return do_io_file_wrapper_cleanup(file, status,
  5736. "Can't read file '%s'",
  5737. "Can't read stream",
  5738. pool);
  5739. }
  5740. //------------------------------------------------------------------------------
  5741. // from svn_io.h
  5742. // Read handler function for a generic stream. see stream_t.
  5743. typedef error_t (*read_fn_t)(
  5744. void * baton,
  5745. char * buffer,
  5746. apr_size_t * len);
  5747. // Skip data handler function for a generic stream. see stream_t
  5748. // and stream_skip().
  5749. typedef error_t (*stream_skip_fn_t)(
  5750. void * baton,
  5751. apr_size_t len);
  5752. // Write handler function for a generic stream. see stream_t.
  5753. typedef error_t (*write_fn_t)(
  5754. void * baton,
  5755. const char * data,
  5756. apr_size_t * len);
  5757. // Close handler function for a generic stream. see stream_t.
  5758. typedef error_t (*close_fn_t)(void * baton);
  5759. typedef struct stream_mark_t stream_mark_t;
  5760. typedef error_t (*stream_mark_fn_t)(
  5761. void * baton,
  5762. stream_mark_t ** mark,
  5763. apr_pool_t * pool);
  5764. typedef error_t (*stream_seek_fn_t)(
  5765. void * baton,
  5766. const stream_mark_t * mark);
  5767. typedef bool (*stream_is_buffered_fn_t)(void * baton);
  5768. //------------------------------------------------------------------------------
  5769. // from stream.c
  5770. typedef struct stream_t
  5771. {
  5772. void * baton;
  5773. read_fn_t read_fn;
  5774. stream_skip_fn_t skip_fn;
  5775. write_fn_t write_fn;
  5776. close_fn_t close_fn;
  5777. stream_mark_fn_t mark_fn;
  5778. stream_seek_fn_t seek_fn;
  5779. stream_is_buffered_fn_t is_buffered_fn;
  5780. } stream_t;
  5781. // Generic stream for APR files
  5782. struct baton_apr_t
  5783. {
  5784. apr_file_t * file;
  5785. apr_pool_t * pool;
  5786. };
  5787. // stream_mark_t for streams backed by APR files.
  5788. struct mark_apr_t
  5789. {
  5790. apr_off_t off;
  5791. };
  5792. static error_t
  5793. read_handler_apr(
  5794. void * baton,
  5795. char * buffer,
  5796. apr_size_t * len)
  5797. {
  5798. struct baton_apr_t * btn = static_cast<baton_apr_t *>(baton);
  5799. error_t err = 0;
  5800. bool eof = FALSE;
  5801. if (*len == 1)
  5802. {
  5803. err = io_file_getc(buffer, btn->file, btn->pool);
  5804. if (err)
  5805. {
  5806. *len = 0;
  5807. if (APR_STATUS_IS_EOF(err))
  5808. {
  5809. error_clear(&err);
  5810. err = WEBDAV_NO_ERROR;
  5811. }
  5812. }
  5813. }
  5814. else
  5815. err = io_file_read_full2(btn->file, buffer, *len, len,
  5816. &eof, btn->pool);
  5817. return err;
  5818. }
  5819. static error_t
  5820. skip_handler_apr(
  5821. void * baton,
  5822. apr_size_t len)
  5823. {
  5824. struct baton_apr_t * btn = static_cast<baton_apr_t *>(baton);
  5825. apr_off_t offset = len;
  5826. return io_file_seek(btn->file, APR_CUR, &offset, btn->pool);
  5827. }
  5828. static error_t
  5829. write_handler_apr(
  5830. void * baton,
  5831. const char * data,
  5832. apr_size_t * len)
  5833. {
  5834. struct baton_apr_t * btn = static_cast<baton_apr_t *>(baton);
  5835. error_t err = 0;
  5836. if (*len == 1)
  5837. {
  5838. err = io_file_putc(*data, btn->file, btn->pool);
  5839. if (err)
  5840. *len = 0;
  5841. }
  5842. else
  5843. err = io_file_write_full(btn->file, data, *len, len, btn->pool);
  5844. return err;
  5845. }
  5846. static error_t
  5847. close_handler_apr(
  5848. void * baton)
  5849. {
  5850. struct baton_apr_t * btn = static_cast<baton_apr_t *>(baton);
  5851. return io_file_close(btn->file, btn->pool);
  5852. }
  5853. static error_t
  5854. mark_handler_apr(
  5855. void * baton,
  5856. stream_mark_t ** mark,
  5857. apr_pool_t * pool)
  5858. {
  5859. struct baton_apr_t * btn = static_cast<baton_apr_t *>(baton);
  5860. struct mark_apr_t * mark_apr = 0;
  5861. mark_apr = static_cast<mark_apr_t *>(apr_pcalloc(pool, sizeof(*mark_apr)));
  5862. mark_apr->off = 0;
  5863. WEBDAV_ERR(io_file_seek(btn->file, APR_CUR, &mark_apr->off, btn->pool));
  5864. *mark = (stream_mark_t *)mark_apr;
  5865. return WEBDAV_NO_ERROR;
  5866. }
  5867. static error_t
  5868. seek_handler_apr(
  5869. void * baton,
  5870. const stream_mark_t * mark)
  5871. {
  5872. struct baton_apr_t * btn = static_cast<baton_apr_t *>(baton);
  5873. apr_off_t offset = (mark != NULL) ? ((const struct mark_apr_t *)mark)->off : 0;
  5874. WEBDAV_ERR(io_file_seek(btn->file, APR_SET, &offset, btn->pool));
  5875. return WEBDAV_NO_ERROR;
  5876. }
  5877. static bool
  5878. is_buffered_handler_apr(
  5879. void * baton)
  5880. {
  5881. struct baton_apr_t * btn = static_cast<baton_apr_t *>(baton);
  5882. return (apr_file_flags_get(btn->file) & APR_BUFFERED) != 0;
  5883. }
  5884. static stream_t *
  5885. stream_create(
  5886. void * baton,
  5887. apr_pool_t * pool)
  5888. {
  5889. stream_t * stream = static_cast<stream_t *>(apr_pcalloc(pool, sizeof(*stream)));
  5890. stream->baton = baton;
  5891. stream->read_fn = NULL;
  5892. stream->skip_fn = NULL;
  5893. stream->write_fn = NULL;
  5894. stream->close_fn = NULL;
  5895. stream->mark_fn = NULL;
  5896. stream->seek_fn = NULL;
  5897. stream->is_buffered_fn = NULL;
  5898. return stream;
  5899. }
  5900. static void
  5901. stream_set_read(
  5902. stream_t * stream,
  5903. read_fn_t read_fn)
  5904. {
  5905. stream->read_fn = read_fn;
  5906. }
  5907. static void
  5908. stream_set_skip(
  5909. stream_t * stream,
  5910. stream_skip_fn_t skip_fn)
  5911. {
  5912. stream->skip_fn = skip_fn;
  5913. }
  5914. static void
  5915. stream_set_write(
  5916. stream_t * stream,
  5917. write_fn_t write_fn)
  5918. {
  5919. stream->write_fn = write_fn;
  5920. }
  5921. static void
  5922. stream_set_close(
  5923. stream_t * stream,
  5924. close_fn_t close_fn)
  5925. {
  5926. stream->close_fn = close_fn;
  5927. }
  5928. static void
  5929. stream_set_mark(
  5930. stream_t * stream,
  5931. stream_mark_fn_t mark_fn)
  5932. {
  5933. stream->mark_fn = mark_fn;
  5934. }
  5935. static void
  5936. stream_set_seek(
  5937. stream_t * stream,
  5938. stream_seek_fn_t seek_fn)
  5939. {
  5940. stream->seek_fn = seek_fn;
  5941. }
  5942. static void
  5943. stream_set_is_buffered(
  5944. stream_t * stream,
  5945. stream_is_buffered_fn_t is_buffered_fn)
  5946. {
  5947. stream->is_buffered_fn = is_buffered_fn;
  5948. }
  5949. static error_t
  5950. read_handler_empty(
  5951. void * baton,
  5952. char * buffer,
  5953. apr_size_t * len)
  5954. {
  5955. *len = 0;
  5956. return WEBDAV_NO_ERROR;
  5957. }
  5958. static error_t
  5959. write_handler_empty(
  5960. void * baton,
  5961. const char * data,
  5962. apr_size_t * len)
  5963. {
  5964. return WEBDAV_NO_ERROR;
  5965. }
  5966. static error_t
  5967. mark_handler_empty(
  5968. void * baton,
  5969. stream_mark_t ** mark,
  5970. apr_pool_t * pool)
  5971. {
  5972. *mark = NULL; // Seek to start of stream marker
  5973. return WEBDAV_NO_ERROR;
  5974. }
  5975. static error_t
  5976. seek_handler_empty(
  5977. void * baton,
  5978. const stream_mark_t * mark)
  5979. {
  5980. return WEBDAV_NO_ERROR;
  5981. }
  5982. static bool
  5983. is_buffered_handler_empty(void * baton)
  5984. {
  5985. return FALSE;
  5986. }
  5987. static stream_t *
  5988. stream_empty(
  5989. apr_pool_t * pool)
  5990. {
  5991. stream_t * stream = stream_create(NULL, pool);
  5992. stream_set_read(stream, read_handler_empty);
  5993. stream_set_write(stream, write_handler_empty);
  5994. stream_set_mark(stream, mark_handler_empty);
  5995. stream_set_seek(stream, seek_handler_empty);
  5996. stream_set_is_buffered(stream, is_buffered_handler_empty);
  5997. return stream;
  5998. }
  5999. static stream_t *
  6000. stream_from_aprfile2(
  6001. apr_file_t * file,
  6002. bool disown,
  6003. apr_pool_t * pool)
  6004. {
  6005. stream_t * stream = NULL;
  6006. if (file == NULL)
  6007. return stream_empty(pool);
  6008. baton_apr_t * baton = static_cast<baton_apr_t *>(apr_pcalloc(pool, sizeof(*baton)));
  6009. baton->file = file;
  6010. baton->pool = pool;
  6011. stream = stream_create(baton, pool);
  6012. stream_set_read(stream, read_handler_apr);
  6013. stream_set_write(stream, write_handler_apr);
  6014. stream_set_skip(stream, skip_handler_apr);
  6015. stream_set_mark(stream, mark_handler_apr);
  6016. stream_set_seek(stream, seek_handler_apr);
  6017. stream_set_is_buffered(stream, is_buffered_handler_apr);
  6018. if (!disown)
  6019. stream_set_close(stream, close_handler_apr);
  6020. return stream;
  6021. }
  6022. static error_t
  6023. stream_open_writable(
  6024. stream_t ** stream,
  6025. apr_os_file_t * thefile,
  6026. apr_pool_t * result_pool,
  6027. apr_pool_t * scratch_pool)
  6028. {
  6029. apr_file_t * file = NULL;
  6030. WEBDAV_ERR(io_file_open_writable(&file,
  6031. thefile,
  6032. APR_WRITE
  6033. | APR_BUFFERED
  6034. | APR_BINARY
  6035. | APR_CREATE,
  6036. // | APR_EXCL,
  6037. result_pool));
  6038. *stream = stream_from_aprfile2(file, FALSE, result_pool);
  6039. return WEBDAV_NO_ERROR;
  6040. }
  6041. static error_t
  6042. stream_write(
  6043. stream_t * stream,
  6044. const char * data,
  6045. apr_size_t * len)
  6046. {
  6047. WEBDAV_ERR_ASSERT(stream->write_fn != NULL);
  6048. return stream->write_fn(stream->baton, data, len);
  6049. }
  6050. static error_t
  6051. stream_close(
  6052. stream_t * stream)
  6053. {
  6054. if (stream->close_fn == NULL)
  6055. return WEBDAV_NO_ERROR;
  6056. return stream->close_fn(stream->baton);
  6057. }
  6058. //------------------------------------------------------------------------------
  6059. // from util.c
  6060. static apr_status_t
  6061. dav_request_cleanup(
  6062. void * baton);
  6063. static apr_status_t
  6064. dav_request_sess_cleanup(
  6065. void * baton)
  6066. {
  6067. neon_request_t * req = static_cast<neon_request_t *>(baton);
  6068. // Make sure we don't run the 'child' cleanup anymore:
  6069. // the pool it refers to probably doesn't exist anymore when it
  6070. // finally does get run if it hasn't by now.
  6071. apr_pool_cleanup_kill(req->pool, req, dav_request_cleanup);
  6072. if (req->ne_req)
  6073. ne_request_destroy(req->ne_req);
  6074. return APR_SUCCESS;
  6075. }
  6076. static apr_status_t
  6077. dav_request_cleanup(
  6078. void * baton)
  6079. {
  6080. neon_request_t * req = static_cast<neon_request_t *>(baton);
  6081. apr_pool_cleanup_run(req->sess->pool, req, dav_request_sess_cleanup);
  6082. return APR_SUCCESS;
  6083. }
  6084. // Return a path-absolute relative URL, given a URL reference (which may
  6085. // be absolute or relative).
  6086. static const char *
  6087. path_from_url(
  6088. const char * url)
  6089. {
  6090. const char * p = NULL;
  6091. // Look for the scheme/authority separator. Stop if we see a path
  6092. // separator - that indicates that this definitely isn't an absolute URL.
  6093. for (p = url; *p; p++)
  6094. {
  6095. if ((*p == ':') || (*p == '/'))
  6096. break;
  6097. }
  6098. // Check whether we found the scheme/authority separator.
  6099. if ((*p++ != ':') || (*p++ != '/') || (*p++ != '/'))
  6100. {
  6101. // No separator, so it must already be relative.
  6102. return url;
  6103. }
  6104. // Find the end of the authority section, indicated by the start of
  6105. // a path, query, or fragment section.
  6106. for (; *p; p++)
  6107. {
  6108. if ((*p == '/') || (*p == '?') || (*p == '#'))
  6109. break;
  6110. }
  6111. // Return a pointer to the rest of the URL, or to "/" if there
  6112. // was no next section.
  6113. return *p == '\0' ? "/" : p;
  6114. }
  6115. // Simple multi-status parser
  6116. // For the purpose of 'simple' requests which - if it weren't
  6117. // for our custom error parser - could use the ne_basic.h interfaces.
  6118. // List of XML elements expected in 207 Multi-Status responses.
  6119. static const neon_xml_elm_t multistatus_elements[] =
  6120. {
  6121. { "DAV:", "multistatus", ELEM_multistatus, 0 },
  6122. { "DAV:", "response", ELEM_response, 0 },
  6123. {
  6124. "DAV:", "responsedescription", ELEM_responsedescription,
  6125. NEON_XML_CDATA
  6126. },
  6127. { "DAV:", "status", ELEM_status, NEON_XML_CDATA },
  6128. { "DAV:", "href", ELEM_href, NEON_XML_CDATA },
  6129. { "DAV:", "propstat", ELEM_propstat, NEON_XML_CDATA },
  6130. { "DAV:", "prop", ELEM_prop, NEON_XML_CDATA },
  6131. // We start out basic and are not interested in other elements
  6132. { "", "", ELEM_unknown, 0 },
  6133. { NULL }
  6134. };
  6135. static const int multistatus_nesting_table[][5] =
  6136. {
  6137. { ELEM_root, ELEM_multistatus, NEON_XML_INVALID },
  6138. {
  6139. ELEM_multistatus, ELEM_response, ELEM_responsedescription,
  6140. NEON_XML_DECLINE
  6141. },
  6142. { ELEM_responsedescription, NEON_XML_INVALID },
  6143. {
  6144. ELEM_response, ELEM_href, ELEM_status, ELEM_propstat,
  6145. NEON_XML_DECLINE
  6146. },
  6147. { ELEM_status, NEON_XML_INVALID },
  6148. { ELEM_href, NEON_XML_INVALID },
  6149. {
  6150. ELEM_propstat, ELEM_prop, ELEM_status, ELEM_responsedescription,
  6151. NEON_XML_INVALID
  6152. },
  6153. { ELEM_prop, NEON_XML_DECLINE },
  6154. { NEON_XML_DECLINE },
  6155. };
  6156. static int
  6157. multistatus_validate_element(
  6158. int parent,
  6159. int child)
  6160. {
  6161. int i = 0;
  6162. int j = 0;
  6163. while ((parent != multistatus_nesting_table[i][0]) &&
  6164. (multistatus_nesting_table[i][0] > 0 || i == 0))
  6165. i++;
  6166. if (parent == multistatus_nesting_table[i][0])
  6167. while ((multistatus_nesting_table[i][++j] != child) &&
  6168. (multistatus_nesting_table[i][j] > 0))
  6169. ;
  6170. return multistatus_nesting_table[i][j];
  6171. }
  6172. typedef struct multistatus_baton_t
  6173. {
  6174. stringbuf_t * want_cdata;
  6175. stringbuf_t * cdata;
  6176. bool in_propstat;
  6177. bool propstat_has_error;
  6178. stringbuf_t * propname;
  6179. stringbuf_t * propstat_description;
  6180. neon_request_t * req;
  6181. stringbuf_t * description;
  6182. bool contains_error;
  6183. bool contains_precondition_error;
  6184. } multistatus_baton_t;
  6185. // Implements neon_startelm_cb_t.
  6186. static error_t
  6187. start_207_element(
  6188. int * elem,
  6189. void * baton,
  6190. int parent,
  6191. const char * nspace,
  6192. const char * name,
  6193. const char ** atts)
  6194. {
  6195. multistatus_baton_t * b = static_cast<multistatus_baton_t *>(baton);
  6196. const neon_xml_elm_t * elm =
  6197. neon_lookup_xml_elem(multistatus_elements, nspace, name);
  6198. *elem = elm ? multistatus_validate_element(parent, elm->id) : NEON_XML_DECLINE;
  6199. if (parent == ELEM_prop)
  6200. {
  6201. stringbuf_setempty(b->propname);
  6202. if (strcmp(nspace, "DAV:") == 0)
  6203. stringbuf_set(b->propname, "DAV:");
  6204. stringbuf_appendcstr(b->propname, name);
  6205. }
  6206. if (*elem < 1) // ! > 0
  6207. return WEBDAV_NO_ERROR;
  6208. switch (*elem)
  6209. {
  6210. case ELEM_propstat:
  6211. b->in_propstat = TRUE;
  6212. b->propstat_has_error = FALSE;
  6213. break;
  6214. default:
  6215. break;
  6216. }
  6217. // We're guaranteed to have ELM now: NEON_XML_DECLINE < 1
  6218. if (elm->flags & NEON_XML_CDATA)
  6219. {
  6220. stringbuf_setempty(b->cdata);
  6221. b->want_cdata = b->cdata;
  6222. }
  6223. return WEBDAV_NO_ERROR;
  6224. }
  6225. // Implements neon_endelm_cb_t
  6226. static error_t
  6227. end_207_element(
  6228. void * baton,
  6229. int state,
  6230. const char * nspace,
  6231. const char * name)
  6232. {
  6233. multistatus_baton_t * b = static_cast<multistatus_baton_t *>(baton);
  6234. switch (state)
  6235. {
  6236. case ELEM_multistatus:
  6237. if (b->contains_error)
  6238. {
  6239. if (stringbuf_isempty(b->description))
  6240. return error_create(WEBDAV_ERR_DAV_REQUEST_FAILED, NULL,
  6241. "The request response contained at least one error");
  6242. else if (b->contains_precondition_error)
  6243. return error_create(WEBDAV_ERR_FS_PROP_BASEVALUE_MISMATCH, NULL,
  6244. b->description->data);
  6245. else
  6246. return error_create(WEBDAV_ERR_DAV_REQUEST_FAILED, NULL,
  6247. b->description->data);
  6248. }
  6249. break;
  6250. case ELEM_responsedescription:
  6251. if (b->in_propstat)
  6252. stringbuf_set(b->propstat_description, b->cdata->data);
  6253. else
  6254. {
  6255. if (!stringbuf_isempty(b->description))
  6256. stringbuf_appendcstr(b->description, "\n");
  6257. stringbuf_appendstr(b->description, b->cdata);
  6258. }
  6259. break;
  6260. case ELEM_status:
  6261. {
  6262. ne_status status;
  6263. if (ne_parse_statusline(b->cdata->data, &status) == 0)
  6264. {
  6265. // I wanted ||=, but I guess the end result is the same
  6266. if (!b->in_propstat)
  6267. b->contains_error |= (status.klass != 2);
  6268. else
  6269. b->propstat_has_error = (status.klass != 2);
  6270. // Handle "412 Precondition Failed" specially
  6271. if (status.code == 412)
  6272. b->contains_precondition_error = TRUE;
  6273. ne_free(status.reason_phrase);
  6274. }
  6275. else
  6276. return error_create(WEBDAV_ERR_DAV_REQUEST_FAILED, NULL,
  6277. "The response contains a non-conforming HTTP status line");
  6278. }
  6279. break;
  6280. case ELEM_propstat:
  6281. b->in_propstat = FALSE;
  6282. b->contains_error |= b->propstat_has_error;
  6283. stringbuf_appendcstr(b->description,
  6284. apr_psprintf(b->req->pool,
  6285. "Error setting property '%s': ",
  6286. b->propname->data));
  6287. stringbuf_appendstr(b->description,
  6288. b->propstat_description);
  6289. default:
  6290. // do nothing
  6291. break;
  6292. }
  6293. // When we have an element which wants cdata,
  6294. // we'll set it all up in start_207_element() again
  6295. b->want_cdata = NULL;
  6296. return WEBDAV_NO_ERROR;
  6297. }
  6298. // Create a status parser attached to the request REQ. Detected errors
  6299. // will be returned there.
  6300. static void
  6301. multistatus_parser_create(
  6302. neon_request_t * req)
  6303. {
  6304. multistatus_baton_t * b = static_cast<multistatus_baton_t *>(apr_pcalloc(req->pool, sizeof(*b)));
  6305. // Create a parser, attached to REQ. (Ignore the return value.)
  6306. neon_xml_parser_create(req, ne_accept_207,
  6307. start_207_element,
  6308. neon_xml_collect_cdata,
  6309. end_207_element, b);
  6310. b->cdata = stringbuf_create("", req->pool);
  6311. b->description = stringbuf_create("", req->pool);
  6312. b->req = req;
  6313. b->propname = stringbuf_create("", req->pool);
  6314. b->propstat_description = stringbuf_create("", req->pool);
  6315. }
  6316. static apr_status_t
  6317. compressed_body_reader_cleanup(
  6318. void * baton)
  6319. {
  6320. if (baton)
  6321. ne_decompress_destroy(static_cast<ne_decompress *>(baton));
  6322. return APR_SUCCESS;
  6323. }
  6324. // Attach READER as a response reader for the request REQ, with the
  6325. // acceptance function ACCPT. The response body data will be decompressed,
  6326. // if compressed, before being passed to READER. USERDATA will be passed as
  6327. // the first argument to the acceptance and reader callbacks.
  6328. static void
  6329. attach_ne_body_reader(
  6330. neon_request_t * req,
  6331. ne_accept_response accpt,
  6332. ne_block_reader reader,
  6333. void * userdata)
  6334. {
  6335. if (req->sess->compression)
  6336. {
  6337. ne_decompress * decompress =
  6338. ne_decompress_reader(req->ne_req, accpt, reader, userdata);
  6339. apr_pool_cleanup_register(req->pool,
  6340. decompress,
  6341. compressed_body_reader_cleanup,
  6342. apr_pool_cleanup_null);
  6343. }
  6344. else
  6345. ne_add_response_body_reader(req->ne_req, accpt, reader, userdata);
  6346. }
  6347. typedef struct cancellation_baton_t
  6348. {
  6349. ne_block_reader real_cb;
  6350. void * real_userdata;
  6351. neon_request_t * req;
  6352. } cancellation_baton_t;
  6353. static int
  6354. cancellation_callback(
  6355. void * userdata,
  6356. const char * block,
  6357. size_t len)
  6358. {
  6359. cancellation_baton_t * b = static_cast<cancellation_baton_t *>(userdata);
  6360. neon_session_t * ras = b->req->sess;
  6361. if (ras->callbacks->cancel_func)
  6362. {
  6363. NEON_REQ_ERR(b->req, (ras->callbacks->cancel_func)(ras->callback_baton));
  6364. }
  6365. if (b->req->err)
  6366. return 1;
  6367. else
  6368. return (b->real_cb)(b->real_userdata, block, len);
  6369. }
  6370. static cancellation_baton_t *
  6371. get_cancellation_baton(
  6372. neon_request_t * req,
  6373. ne_block_reader real_cb,
  6374. void * real_userdata,
  6375. apr_pool_t * pool)
  6376. {
  6377. cancellation_baton_t * b = static_cast<cancellation_baton_t *>(apr_pcalloc(pool, sizeof(*b)));
  6378. b->real_cb = real_cb;
  6379. b->real_userdata = real_userdata;
  6380. b->req = req;
  6381. return b;
  6382. }
  6383. typedef struct body_provider_baton_t
  6384. {
  6385. neon_request_t * req;
  6386. apr_file_t * body_file;
  6387. } body_provider_baton_t;
  6388. static ssize_t
  6389. ra_neon_body_provider(
  6390. void * userdata,
  6391. char * buffer,
  6392. size_t buflen)
  6393. {
  6394. body_provider_baton_t * b = static_cast<body_provider_baton_t *>(userdata);
  6395. neon_request_t * req = b->req;
  6396. apr_file_t * body_file = b->body_file;
  6397. if (req->sess->callbacks &&
  6398. req->sess->callbacks->cancel_func)
  6399. {
  6400. NEON_REQ_ERR(req, (req->sess->callbacks->cancel_func)(
  6401. req->sess->callback_baton));
  6402. }
  6403. if (req->err)
  6404. return -1;
  6405. webdav_pool_clear(req->iterpool);
  6406. if (buflen == 0)
  6407. {
  6408. // This is the beginning of a new body pull. Rewind the file.
  6409. apr_off_t offset = 0;
  6410. NEON_REQ_ERR(b->req, io_file_seek(body_file, APR_SET, &offset, req->iterpool));
  6411. return (req->err ? -1 : 0);
  6412. }
  6413. else
  6414. {
  6415. callback_baton_t * cb = static_cast<callback_baton_t *>(req->sess->callback_baton);
  6416. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(cb->ctx->auth_baton->parameters,
  6417. CONST_FS_KEY,
  6418. APR_HASH_KEY_STRING));
  6419. assert(fs);
  6420. fs->AdjustToCPSLimit(buflen);
  6421. apr_size_t nbytes = buflen;
  6422. error_t err = io_file_read(body_file, buffer, &nbytes,
  6423. req->iterpool);
  6424. if (err)
  6425. {
  6426. if (APR_STATUS_IS_EOF(err))
  6427. {
  6428. error_clear(&err);
  6429. return 0;
  6430. }
  6431. NEON_REQ_ERR(req, err);
  6432. return -1;
  6433. }
  6434. else
  6435. return (ssize_t)nbytes;
  6436. }
  6437. }
  6438. static error_t
  6439. neon_set_neon_body_provider(
  6440. neon_request_t * req,
  6441. apr_file_t * body_file)
  6442. {
  6443. apr_status_t status = 0;
  6444. apr_finfo_t finfo = {0};
  6445. body_provider_baton_t * b = static_cast<body_provider_baton_t *>(apr_pcalloc(req->pool, sizeof(*b)));
  6446. status = apr_file_info_get(&finfo, APR_FINFO_SIZE, body_file);
  6447. if (status)
  6448. return error_wrap_apr(status,
  6449. "Can't calculate the request body size");
  6450. b->body_file = body_file;
  6451. b->req = req;
  6452. ne_set_request_body_provider(req->ne_req, (ne_off_t)finfo.size,
  6453. ra_neon_body_provider, b);
  6454. return WEBDAV_NO_ERROR;
  6455. }
  6456. // See doc string for neon_parsed_request.
  6457. static error_t
  6458. parsed_request(
  6459. neon_request_t * req,
  6460. neon_session_t * ras,
  6461. const char * method,
  6462. const char * url,
  6463. const char * body,
  6464. apr_file_t * body_file,
  6465. void set_parser(ne_xml_parser * parser, void * baton),
  6466. neon_startelm_cb_t startelm_cb,
  6467. neon_cdata_cb_t cdata_cb,
  6468. neon_endelm_cb_t endelm_cb,
  6469. void * baton,
  6470. apr_hash_t * extra_headers,
  6471. int * status_code,
  6472. bool check_errors,
  6473. apr_pool_t * pool)
  6474. {
  6475. ne_xml_parser * success_parser = NULL;
  6476. if (body == NULL)
  6477. WEBDAV_ERR(neon_set_neon_body_provider(req, body_file));
  6478. // use a symbolic name somewhere for this MIME type?
  6479. ne_add_request_header(req->ne_req, "Content-Type", "text/xml");
  6480. // create a parser to read the normal response body
  6481. success_parser = neon_xml_parser_create(req, NULL,
  6482. startelm_cb, cdata_cb,
  6483. endelm_cb, baton);
  6484. // if our caller is interested in having access to this parser, call
  6485. // the SET_PARSER callback with BATON.
  6486. if (set_parser != NULL)
  6487. set_parser(success_parser, baton);
  6488. // Register the "main" accepter and body-reader with the request --
  6489. // the one to use when the HTTP status is 2XX.
  6490. attach_ne_body_reader(req, ne_accept_2xx, cancellation_callback,
  6491. get_cancellation_baton(req, ne_xml_parse_v,
  6492. success_parser, pool));
  6493. // run the request and get the resulting status code.
  6494. WEBDAV_ERR(neon_request_dispatch(
  6495. status_code, req, extra_headers, body,
  6496. (strcmp(method, "PROPFIND") == 0) ? 207 : 200,
  6497. 0,
  6498. check_errors,
  6499. pool));
  6500. WEBDAV_ERR(neon_check_parse_error(method, success_parser, url));
  6501. return WEBDAV_NO_ERROR;
  6502. }
  6503. static error_t
  6504. neon_parsed_request(
  6505. neon_session_t * sess,
  6506. const char * method,
  6507. const char * url,
  6508. const char * body,
  6509. apr_file_t * body_file,
  6510. void set_parser(ne_xml_parser * parser, void * baton),
  6511. neon_startelm_cb_t startelm_cb,
  6512. neon_cdata_cb_t cdata_cb,
  6513. neon_endelm_cb_t endelm_cb,
  6514. void * baton,
  6515. apr_hash_t * extra_headers,
  6516. int * status_code,
  6517. bool check_errors,
  6518. apr_pool_t * pool)
  6519. {
  6520. // create/prep the request
  6521. neon_request_t * req = NULL;
  6522. error_t err = 0;
  6523. WEBDAV_ERR(neon_request_create(&req, sess, method, url, pool));
  6524. err = parsed_request(req, sess, method, url, body, body_file,
  6525. set_parser, startelm_cb, cdata_cb, endelm_cb,
  6526. baton, extra_headers, status_code,
  6527. check_errors,
  6528. pool);
  6529. neon_request_destroy(req);
  6530. return err;
  6531. }
  6532. static error_t
  6533. neon_simple_request(
  6534. int * code,
  6535. neon_session_t * ras,
  6536. const char * method,
  6537. const char * url,
  6538. apr_hash_t * extra_headers,
  6539. const char * body,
  6540. int okay_1, int okay_2, apr_pool_t * pool)
  6541. {
  6542. neon_request_t * req = NULL;
  6543. error_t err = 0;
  6544. WEBDAV_ERR(neon_request_create(&req, ras, method, url, pool));
  6545. multistatus_parser_create(req);
  6546. // neon_request_dispatch() adds the custom error response
  6547. // reader. Neon will take care of the Content-Length calculation
  6548. err = neon_request_dispatch(code, req, extra_headers,
  6549. body ? body : "",
  6550. okay_1, okay_2, false, pool);
  6551. neon_request_destroy(req);
  6552. return err;
  6553. }
  6554. static void
  6555. neon_add_depth_header(
  6556. apr_hash_t * extra_headers,
  6557. int depth)
  6558. {
  6559. assert(extra_headers != NULL);
  6560. assert(depth == NEON_DEPTH_ZERO ||
  6561. depth == NEON_DEPTH_ONE ||
  6562. depth == NEON_DEPTH_INFINITE);
  6563. apr_hash_set(extra_headers, "Depth", APR_HASH_KEY_STRING,
  6564. (depth == NEON_DEPTH_INFINITE) ?
  6565. "infinity" : (depth == NEON_DEPTH_ZERO) ? "0" : "1");
  6566. return;
  6567. }
  6568. static const neon_xml_elm_t *
  6569. neon_lookup_xml_elem(
  6570. const neon_xml_elm_t * table,
  6571. const char * nspace,
  6572. const char * name)
  6573. {
  6574. // placeholder for `unknown' element if it's present
  6575. const neon_xml_elm_t * elem_unknown = NULL;
  6576. const neon_xml_elm_t * elem = NULL;
  6577. for (elem = table; elem->nspace; ++elem)
  6578. {
  6579. if ((strcmp(elem->nspace, nspace) == 0) &&
  6580. (strcmp(elem->name, name) == 0))
  6581. return elem;
  6582. // Use a single loop to save CPU cycles.
  6583. // Maybe this element is defined as `unknown'?
  6584. if (elem->id == ELEM_unknown)
  6585. elem_unknown = elem;
  6586. }
  6587. // ELEM_unknown position in the table or NULL
  6588. return elem_unknown;
  6589. }
  6590. static error_t
  6591. neon_xml_collect_cdata(
  6592. void * baton,
  6593. int state,
  6594. const char * cdata,
  6595. size_t len)
  6596. {
  6597. stringbuf_t ** b = static_cast<stringbuf_t **>(baton);
  6598. if (*b)
  6599. stringbuf_appendbytes(*b, cdata, len);
  6600. return WEBDAV_NO_ERROR;
  6601. }
  6602. // Custom function of type ne_accept_response.
  6603. static int
  6604. ra_neon_error_accepter(
  6605. void * userdata,
  6606. ne_request * req,
  6607. const ne_status * st)
  6608. {
  6609. // Before, this function was being run for *all* responses including
  6610. // the 401 auth challenge. In neon 0.24.x that was harmless. But
  6611. // in neon 0.25.0, trying to parse a 401 response as XML using
  6612. // ne_xml_parse_v aborts the response; so the auth hooks never got a
  6613. // chance.
  6614. ne_content_type ctype = {0};
  6615. // Only accept non-2xx responses with text/xml content-type
  6616. if (st->klass != 2 && ne_get_content_type(req, &ctype) == 0)
  6617. {
  6618. int is_xml = (strcmp(ctype.type, "text") == 0) &&
  6619. (strcmp(ctype.subtype, "xml") == 0);
  6620. ne_free(ctype.value);
  6621. return is_xml;
  6622. }
  6623. else
  6624. return 0;
  6625. }
  6626. static const neon_xml_elm_t error_elements[] =
  6627. {
  6628. { "DAV:", "error", ELEM_error, 0 },
  6629. {
  6630. "http://apache.org/dav/xmlns", "human-readable",
  6631. ELEM_human_readable, NEON_XML_CDATA
  6632. },
  6633. // our validator doesn't yet recognize the rich, specific
  6634. // <D:some-condition-failed/> objects as defined by DeltaV.
  6635. { NULL }
  6636. };
  6637. static error_t
  6638. xml_parser_cleanup(void * baton)
  6639. {
  6640. ne_xml_destroy(static_cast<ne_xml_parser *>(baton));
  6641. return WEBDAV_NO_ERROR;
  6642. }
  6643. static ne_xml_parser *
  6644. xml_parser_create(
  6645. neon_request_t * req)
  6646. {
  6647. ne_xml_parser * p = ne_xml_create();
  6648. // HACK: Set the parser's error to the empty string. Someday we
  6649. // hope neon will let us have an easy way to tell the difference
  6650. // between XML parsing errors, and errors that occur while handling
  6651. // the XML tags that we get. Until then, trust that whenever neon
  6652. // has an error somewhere below the API, it sets its own error to
  6653. // something non-empty (the API promises non-NULL, at least).
  6654. ne_xml_set_error(p, "");
  6655. apr_pool_cleanup_register(req->pool, p,
  6656. xml_parser_cleanup,
  6657. apr_pool_cleanup_null);
  6658. return p;
  6659. }
  6660. static int
  6661. validate_error_elements(
  6662. neon_xml_elmid parent,
  6663. neon_xml_elmid child)
  6664. {
  6665. switch (parent)
  6666. {
  6667. case ELEM_root:
  6668. if (child == ELEM_error)
  6669. return child;
  6670. else
  6671. return NEON_XML_INVALID;
  6672. case ELEM_error:
  6673. if ((child == ELEM_error) ||
  6674. (child == ELEM_human_readable))
  6675. return child;
  6676. else
  6677. return NEON_XML_DECLINE; // ignore if something else
  6678. // was in there
  6679. default:
  6680. return NEON_XML_DECLINE;
  6681. }
  6682. // NOTREACHED
  6683. }
  6684. static error_t
  6685. generate_error(
  6686. neon_request_t * req,
  6687. apr_pool_t * pool)
  6688. {
  6689. int errcode = WEBDAV_ERR_DAV_REQUEST_FAILED;
  6690. const char * context =
  6691. apr_psprintf(req->pool, "%s of '%s'", req->method, req->url);
  6692. const char * msg = NULL;
  6693. const char * hostport = NULL;
  6694. // Convert the return codes.
  6695. switch (req->rv)
  6696. {
  6697. case NE_OK:
  6698. switch (req->code)
  6699. {
  6700. case 404:
  6701. return error_create(WEBDAV_ERR_FS_NOT_FOUND, NULL,
  6702. apr_psprintf(pool, "'%s' path not found", req->url));
  6703. case 403:
  6704. return error_create(WEBDAV_ERR_DAV_FORBIDDEN, NULL,
  6705. apr_psprintf(pool, "Access to '%s' forbidden",
  6706. req->url));
  6707. case 301:
  6708. case 302:
  6709. case 307:
  6710. return error_create(WEBDAV_ERR_DAV_RELOCATED, NULL,
  6711. apr_psprintf(pool, (req->code == 301) ?
  6712. "WebDAV resource moved permanently to '%s';"
  6713. " please relocate"
  6714. : "WebDAV resource moved temporarily to '%s';"
  6715. " please relocate",
  6716. neon_request_get_location(req, pool)));
  6717. default:
  6718. return error_create(errcode, NULL,
  6719. apr_psprintf(pool,
  6720. "Server sent unexpected return value (%d %s) "
  6721. "in response to %s request for '%s'", req->code,
  6722. req->code_desc, req->method, req->url));
  6723. }
  6724. case NE_AUTH:
  6725. case NE_PROXYAUTH:
  6726. errcode = WEBDAV_ERR_NOT_AUTHORIZED;
  6727. // neon >= 0.27 gives a descriptive error message after auth
  6728. // failure; expose this since it's a useful diagnostic e.g. for
  6729. // an unsupported challenge scheme, or a local GSSAPI error due
  6730. // to an expired ticket.
  6731. WEBDAV_ERR(utf_cstring_to_utf8(&msg, ne_get_error(req->ne_sess), pool));
  6732. msg = apr_psprintf(pool, "authorization failed: %s", msg);
  6733. break;
  6734. case NE_CONNECT:
  6735. msg = "could not connect to server";
  6736. break;
  6737. case NE_TIMEOUT:
  6738. msg = "timed out waiting for server";
  6739. break;
  6740. default:
  6741. // Get the error string from neon and convert to UTF-8.
  6742. WEBDAV_ERR(utf_cstring_to_utf8(&msg, ne_get_error(req->ne_sess), pool));
  6743. break;
  6744. }
  6745. // The hostname may contain non-ASCII characters, so convert it to UTF-8.
  6746. WEBDAV_ERR(utf_cstring_to_utf8(&hostport,
  6747. ne_get_server_hostport(req->ne_sess), pool));
  6748. // This is a translation nightmare. Make sure to compose full strings
  6749. // and mark those for translation.
  6750. return error_createf(errcode, NULL, "%s: %s (%s://%s)",
  6751. context, msg, ne_get_scheme(req->ne_sess),
  6752. hostport);
  6753. }
  6754. typedef struct error_parser_baton
  6755. {
  6756. stringbuf_t * want_cdata;
  6757. stringbuf_t * cdata;
  6758. error_t * dst_err;
  6759. error_t tmp_err;
  6760. bool * marshalled_error;
  6761. } error_parser_baton_t;
  6762. static int
  6763. start_err_element(
  6764. void * baton,
  6765. int parent,
  6766. const char * nspace,
  6767. const char * name,
  6768. const char ** atts)
  6769. {
  6770. const neon_xml_elm_t * elm = neon_lookup_xml_elem(error_elements, nspace, name);
  6771. int acc = elm ? validate_error_elements(parent, elm->id) : NEON_XML_DECLINE;
  6772. error_parser_baton_t * b = static_cast<error_parser_baton_t *>(baton);
  6773. error_t * err = &(b->tmp_err);
  6774. if (acc < 1) // ! > 0
  6775. return acc;
  6776. switch (elm->id)
  6777. {
  6778. case ELEM_error:
  6779. {
  6780. // allocate the error_t. Hopefully the value will be
  6781. // overwritten by the <human-readable> tag, or even someday by
  6782. // a <D:failed-precondition/> tag.
  6783. *err = error_create(APR_EGENERAL, NULL,
  6784. "General svn error from server");
  6785. break;
  6786. }
  6787. case ELEM_human_readable:
  6788. {
  6789. // get the errorcode attribute if present
  6790. const char * errcode_str =
  6791. xml_get_attr_value("errcode", // make constant in
  6792. // some mod_dav header?
  6793. atts);
  6794. if (errcode_str && *err)
  6795. {
  6796. apr_int64_t val;
  6797. error_t err2;
  6798. err2 = cstring_atoi64(&val, errcode_str);
  6799. if (err2)
  6800. {
  6801. error_clear(&err2);
  6802. break;
  6803. }
  6804. }
  6805. break;
  6806. }
  6807. default:
  6808. break;
  6809. }
  6810. switch (elm->id)
  6811. {
  6812. case ELEM_human_readable:
  6813. b->want_cdata = b->cdata;
  6814. stringbuf_setempty(b->want_cdata);
  6815. break;
  6816. default:
  6817. b->want_cdata = NULL;
  6818. break;
  6819. }
  6820. return elm->id;
  6821. }
  6822. static int
  6823. end_err_element(
  6824. void * baton,
  6825. int state,
  6826. const char * nspace,
  6827. const char * name)
  6828. {
  6829. error_parser_baton_t * b = static_cast<error_parser_baton_t *>(baton);
  6830. error_t * err = &(b->tmp_err);
  6831. switch (state)
  6832. {
  6833. case ELEM_human_readable:
  6834. {
  6835. if (b->cdata->data && err)
  6836. {
  6837. // On the server dav_error_response_tag() will add a leading
  6838. // and trailing newline if DEBUG_CR is defined in mod_dav.h,
  6839. // so remove any such characters here.
  6840. apr_size_t len;
  6841. const char * cd = b->cdata->data;
  6842. if (*cd == '\n')
  6843. ++cd;
  6844. len = strlen(cd);
  6845. if (len > 0 && cd[len - 1] == '\n')
  6846. --len;
  6847. }
  6848. break;
  6849. }
  6850. case ELEM_error:
  6851. {
  6852. if (b->dst_err)
  6853. error_clear(&b->tmp_err);
  6854. else if (b->tmp_err)
  6855. {
  6856. b->dst_err = &b->tmp_err;
  6857. if (b->marshalled_error)
  6858. *(b->marshalled_error) = TRUE;
  6859. }
  6860. b->tmp_err = NULL;
  6861. break;
  6862. }
  6863. default:
  6864. break;
  6865. }
  6866. return 0;
  6867. }
  6868. static int
  6869. collect_error_cdata(
  6870. void * baton,
  6871. int state,
  6872. const char * cdata,
  6873. size_t len)
  6874. {
  6875. stringbuf_t ** b = static_cast<stringbuf_t **>(baton);
  6876. if (*b)
  6877. stringbuf_appendbytes(*b, cdata, len);
  6878. return 0;
  6879. }
  6880. static apr_status_t
  6881. error_parser_baton_cleanup(
  6882. void * baton)
  6883. {
  6884. error_parser_baton_t * b = static_cast<error_parser_baton_t *>(baton);
  6885. if (b->tmp_err)
  6886. error_clear(&b->tmp_err);
  6887. return APR_SUCCESS;
  6888. }
  6889. static ne_xml_parser *
  6890. error_parser_create(
  6891. neon_request_t * req)
  6892. {
  6893. error_parser_baton_t * b = static_cast<error_parser_baton_t *>(apr_pcalloc(req->pool, sizeof(*b)));
  6894. ne_xml_parser * error_parser = NULL;
  6895. b->dst_err = &(req->err);
  6896. b->marshalled_error = &(req->marshalled_error);
  6897. b->tmp_err = NULL;
  6898. b->want_cdata = NULL;
  6899. b->cdata = stringbuf_create("", req->pool);
  6900. // attach a standard <D:error> body parser to the request
  6901. error_parser = xml_parser_create(req);
  6902. ne_xml_push_handler(error_parser,
  6903. start_err_element,
  6904. collect_error_cdata,
  6905. end_err_element, b);
  6906. apr_pool_cleanup_register(req->pool, b,
  6907. error_parser_baton_cleanup,
  6908. apr_pool_cleanup_null);
  6909. // Register the "error" accepter and body-reader with the request --
  6910. // the one to use when HTTP status is *not* 2XX
  6911. attach_ne_body_reader(req, ra_neon_error_accepter,
  6912. ne_xml_parse_v, error_parser);
  6913. return error_parser;
  6914. }
  6915. static error_t
  6916. neon_maybe_store_auth_info(
  6917. neon_session_t * ras,
  6918. apr_pool_t * pool)
  6919. {
  6920. // No auth_baton? Never mind.
  6921. if (!ras->callbacks->auth_baton)
  6922. return WEBDAV_NO_ERROR;
  6923. // If we ever got credentials, ask the iter_baton to save them.
  6924. return auth_save_credentials(ras->auth_iterstate, pool);
  6925. }
  6926. // A baton that is used along with a set of Neon ne_startelm_cb,
  6927. // ne_cdata_cb, and ne_endelm_cb callbacks to handle conversion
  6928. // from our style errors to Neon style errors.
  6929. // The underlying callbacks are called, and if errors
  6930. // are returned they are stored in this baton and a Neon level
  6931. // error code is returned to the parser.
  6932. typedef struct parser_wrapper_baton_t
  6933. {
  6934. neon_request_t * req;
  6935. ne_xml_parser * parser;
  6936. void * baton;
  6937. neon_startelm_cb_t startelm_cb;
  6938. neon_cdata_cb_t cdata_cb;
  6939. neon_endelm_cb_t endelm_cb;
  6940. } parser_wrapper_baton_t;
  6941. static int
  6942. wrapper_startelm_cb(
  6943. void * baton,
  6944. int parent,
  6945. const char * nspace,
  6946. const char * name,
  6947. const char ** atts)
  6948. {
  6949. parser_wrapper_baton_t * pwb = static_cast<parser_wrapper_baton_t *>(baton);
  6950. int elem = NEON_XML_DECLINE;
  6951. if (pwb->startelm_cb)
  6952. {
  6953. NEON_REQ_ERR(pwb->req, pwb->startelm_cb(&elem, pwb->baton, parent, nspace,
  6954. name, atts));
  6955. }
  6956. if (elem == NEON_XML_INVALID)
  6957. {
  6958. NEON_REQ_ERR(pwb->req, error_create(WEBDAV_ERR_XML_MALFORMED, NULL, NULL));
  6959. }
  6960. if (pwb->req->err)
  6961. return NE_XML_ABORT;
  6962. return elem;
  6963. }
  6964. static int
  6965. wrapper_cdata_cb(
  6966. void * baton,
  6967. int state,
  6968. const char * cdata,
  6969. size_t len)
  6970. {
  6971. parser_wrapper_baton_t * pwb = static_cast<parser_wrapper_baton_t *>(baton);
  6972. if (pwb->cdata_cb)
  6973. {
  6974. NEON_REQ_ERR(pwb->req, pwb->cdata_cb(pwb->baton, state, cdata, len));
  6975. }
  6976. if (pwb->req->err)
  6977. return NE_XML_ABORT;
  6978. return 0;
  6979. }
  6980. static int
  6981. wrapper_endelm_cb(
  6982. void * baton,
  6983. int state,
  6984. const char * nspace,
  6985. const char * name)
  6986. {
  6987. parser_wrapper_baton_t * pwb = static_cast<parser_wrapper_baton_t *>(baton);
  6988. if (pwb->endelm_cb)
  6989. {
  6990. NEON_REQ_ERR(pwb->req, pwb->endelm_cb(pwb->baton, state, nspace, name));
  6991. }
  6992. if (pwb->req->err)
  6993. return NE_XML_ABORT;
  6994. return 0;
  6995. }
  6996. static error_t
  6997. neon_check_parse_error(
  6998. const char * method,
  6999. ne_xml_parser * xml_parser,
  7000. const char * url)
  7001. {
  7002. const char * msg = ne_xml_get_error(xml_parser);
  7003. if (msg != NULL && *msg != '\0')
  7004. return error_createf(WEBDAV_ERR_DAV_REQUEST_FAILED, NULL,
  7005. "The %s request returned invalid XML "
  7006. "in the response: %s (%s)",
  7007. method, msg, url);
  7008. return WEBDAV_NO_ERROR;
  7009. }
  7010. static int
  7011. wrapper_reader_cb(
  7012. void * baton,
  7013. const char * data,
  7014. size_t len)
  7015. {
  7016. parser_wrapper_baton_t * pwb = static_cast<parser_wrapper_baton_t *>(baton);
  7017. neon_session_t * sess = pwb->req->sess;
  7018. int parser_status = 0;
  7019. if (pwb->req->err)
  7020. return 1;
  7021. if (sess->callbacks->cancel_func)
  7022. {
  7023. NEON_REQ_ERR(pwb->req, (sess->callbacks->cancel_func)(sess->callback_baton));
  7024. }
  7025. if (pwb->req->err)
  7026. return 1;
  7027. if (len)
  7028. parser_status = ne_xml_parse(pwb->parser, data, len);
  7029. if (parser_status)
  7030. {
  7031. // Pass XML parser error.
  7032. NEON_REQ_ERR(pwb->req, neon_check_parse_error(pwb->req->method,
  7033. pwb->parser,
  7034. pwb->req->url));
  7035. }
  7036. return parser_status;
  7037. }
  7038. // Create a Neon xml parser with callbacks STARTELM_CB, ENDELM_CB and
  7039. // CDATA_CB. The created parser wraps the Neon callbacks and marshals any
  7040. // errors returned by the callbacks through the Neon layer. Any errors
  7041. // raised will be returned by neon_request_dispatch() unless
  7042. // an earlier error occurred.
  7043. // Register a pool cleanup on the pool of REQ to clean up any allocated
  7044. // Neon resources.
  7045. // Return the new parser. Also attach it to REQ if ACCPT is non-null.
  7046. // ACCPT indicates whether the parser wants to read the response body
  7047. // or not. Pass NULL for ACCPT when you don't want the returned parser
  7048. // to be attached to REQ.
  7049. static ne_xml_parser *
  7050. neon_xml_parser_create(
  7051. neon_request_t * req,
  7052. ne_accept_response accpt,
  7053. neon_startelm_cb_t startelm_cb,
  7054. neon_cdata_cb_t cdata_cb,
  7055. neon_endelm_cb_t endelm_cb,
  7056. void * baton)
  7057. {
  7058. ne_xml_parser * p = xml_parser_create(req);
  7059. parser_wrapper_baton_t * pwb = static_cast<parser_wrapper_baton_t *>(apr_pcalloc(req->pool, sizeof(*pwb)));
  7060. pwb->req = req;
  7061. pwb->parser = p;
  7062. pwb->baton = baton;
  7063. pwb->startelm_cb = startelm_cb;
  7064. pwb->cdata_cb = cdata_cb;
  7065. pwb->endelm_cb = endelm_cb;
  7066. ne_xml_push_handler(p,
  7067. wrapper_startelm_cb,
  7068. wrapper_cdata_cb,
  7069. wrapper_endelm_cb, pwb);
  7070. if (accpt)
  7071. attach_ne_body_reader(req, accpt, wrapper_reader_cb, pwb);
  7072. return p;
  7073. }
  7074. static error_t
  7075. neon_request_dispatch(
  7076. int * code_p,
  7077. neon_request_t * req,
  7078. apr_hash_t * extra_headers,
  7079. const char * body,
  7080. int okay_1,
  7081. int okay_2,
  7082. bool check_errors,
  7083. apr_pool_t * pool)
  7084. {
  7085. // add any extra headers passed in by caller.
  7086. if (extra_headers != NULL)
  7087. {
  7088. for (apr_hash_index_t * hi = apr_hash_first(pool, extra_headers); hi;
  7089. hi = apr_hash_next(hi))
  7090. {
  7091. const void * key;
  7092. void * val;
  7093. apr_hash_this(hi, &key, NULL, &val);
  7094. ne_add_request_header(req->ne_req,
  7095. static_cast<const char *>(key), static_cast<const char *>(val));
  7096. }
  7097. }
  7098. if (body)
  7099. ne_set_request_body_buffer(req->ne_req, body, strlen(body));
  7100. // attach a standard <D:error> body parser to the request
  7101. ne_xml_parser * error_parser = error_parser_create(req);
  7102. if (check_errors)
  7103. multistatus_parser_create(req);
  7104. // run the request, see what comes back.
  7105. req->rv = ne_request_dispatch(req->ne_req);
  7106. // Save values from the request
  7107. const ne_status * statstruct = ne_get_status(req->ne_req);
  7108. req->code_desc = apr_pstrdup(pool, statstruct->reason_phrase);
  7109. req->code = statstruct->code;
  7110. // If we see a successful request that used authentication, we should store
  7111. // the credentials for future use.
  7112. if ((req->sess->auth_used) && (statstruct->code < 400))
  7113. {
  7114. req->sess->auth_used = FALSE;
  7115. WEBDAV_ERR(neon_maybe_store_auth_info(req->sess, pool));
  7116. }
  7117. if (code_p)
  7118. *code_p = req->code;
  7119. if (!req->marshalled_error && req->err)
  7120. WEBDAV_ERR(req->err);
  7121. // If the status code was one of the two that we expected, then go
  7122. // ahead and return now. IGNORE any marshalled error.
  7123. if ((req->rv == NE_OK) && (req->code == okay_1 || req->code == okay_2))
  7124. return WEBDAV_NO_ERROR;
  7125. // Any other errors? Report them
  7126. if (req->err)
  7127. WEBDAV_ERR(req->err);
  7128. WEBDAV_ERR(neon_check_parse_error(req->method, error_parser, req->url));
  7129. // We either have a neon error, or some other error
  7130. // that we didn't expect.
  7131. return generate_error(req, pool);
  7132. }
  7133. static const char *
  7134. neon_request_get_location(
  7135. neon_request_t * request,
  7136. apr_pool_t * pool)
  7137. {
  7138. const char * val = ne_get_response_header(request->ne_req, "Location");
  7139. return val ? urlpath_canonicalize(val, pool) : NULL;
  7140. }
  7141. static error_t
  7142. neon_request_create(
  7143. neon_request_t ** request,
  7144. neon_session_t * sess,
  7145. const char * method, const char * url,
  7146. apr_pool_t * pool)
  7147. {
  7148. apr_pool_t * reqpool = webdav_pool_create(pool);
  7149. neon_request_t * req = NULL;
  7150. const char * path = NULL;
  7151. // We never want to send Neon an absolute URL, since that can cause
  7152. // problems with some servers (for example, those that may be accessed
  7153. // using different server names from different locations, or those that
  7154. // want to rewrite the incoming URL). If the URL passed in is absolute,
  7155. // convert it to a path-absolute relative URL.
  7156. path = path_from_url(url);
  7157. req = static_cast<neon_request_t *>(apr_pcalloc(reqpool, sizeof(*req)));
  7158. req->ne_sess = sess->ne_sess;
  7159. req->ne_req = ne_request_create(req->ne_sess, method, path);
  7160. req->sess = sess;
  7161. req->pool = reqpool;
  7162. req->iterpool = webdav_pool_create(req->pool);
  7163. req->method = apr_pstrdup(req->pool, method);
  7164. req->url = apr_pstrdup(req->pool, url);
  7165. req->rv = -1;
  7166. // Neon resources may be NULL on out-of-memory
  7167. assert(req->ne_req != NULL);
  7168. apr_pool_cleanup_register(sess->pool, req,
  7169. dav_request_sess_cleanup,
  7170. apr_pool_cleanup_null);
  7171. apr_pool_cleanup_register(reqpool, req,
  7172. dav_request_cleanup,
  7173. apr_pool_cleanup_null);
  7174. *request = req;
  7175. return WEBDAV_NO_ERROR;
  7176. }
  7177. static error_t
  7178. get_path_relative_to_session(
  7179. session_t * session,
  7180. const char ** rel_path,
  7181. const char * url,
  7182. apr_pool_t * pool)
  7183. {
  7184. const char * sess_url = NULL;
  7185. WEBDAV_ERR(session->vtable->get_session_url(session, &sess_url, pool));
  7186. if (strcmp(sess_url, url) == 0)
  7187. {
  7188. *rel_path = "";
  7189. }
  7190. else
  7191. {
  7192. *rel_path = uri_is_child(sess_url, url, pool);
  7193. if (!*rel_path)
  7194. {
  7195. return error_createf(WEBDAV_ERR_ILLEGAL_URL, NULL,
  7196. "'%s' isn't a child of session URL '%s'", url, sess_url);
  7197. }
  7198. }
  7199. return WEBDAV_NO_ERROR;
  7200. }
  7201. static error_t
  7202. client_path_relative_to_root(
  7203. const char ** rel_path,
  7204. const char * abspath_or_url,
  7205. const char * webdav_root,
  7206. bool include_leading_slash,
  7207. session_t * ra_session,
  7208. apr_pool_t * result_pool,
  7209. apr_pool_t * scratch_pool)
  7210. {
  7211. const char * webdav_relpath = NULL;
  7212. if (!path_is_url(abspath_or_url))
  7213. {
  7214. error_createf(WEBDAV_ERR_DAV_NOT_IMPLEMENTED, NULL,
  7215. "not implemented: 'client_path_relative_to_root'");
  7216. }
  7217. // Merge handling passes a root that is not WebDAV resource root
  7218. else if (webdav_root != NULL)
  7219. {
  7220. /*if (!uri_is_ancestor(webdav_root, abspath_or_url))
  7221. return error_createf(WEBDAV_ERR_CLIENT_UNRELATED_RESOURCES, NULL,
  7222. "URL '%s' is not a child of "
  7223. "root URL '%s'",
  7224. abspath_or_url, webdav_root);*/
  7225. webdav_relpath = uri_skip_ancestor(webdav_root, abspath_or_url,
  7226. result_pool);
  7227. }
  7228. else
  7229. {
  7230. error_t err = 0;
  7231. WEBDAV_ERR_ASSERT(ra_session != NULL);
  7232. // Ask the RA layer to create a relative path for us
  7233. err = get_path_relative_to_root(ra_session, &webdav_relpath,
  7234. abspath_or_url, scratch_pool);
  7235. if (err)
  7236. {
  7237. if (err == WEBDAV_ERR_ILLEGAL_URL)
  7238. {
  7239. return error_createf(WEBDAV_ERR_CLIENT_UNRELATED_RESOURCES, &err,
  7240. "URL '%s' is not inside WebDAV resource root", abspath_or_url);
  7241. }
  7242. return error_trace(err);
  7243. }
  7244. }
  7245. if (include_leading_slash)
  7246. *rel_path = apr_pstrcat(result_pool, "/", webdav_relpath, NULL);
  7247. else
  7248. *rel_path = webdav_relpath;
  7249. return WEBDAV_NO_ERROR;
  7250. }
  7251. static const char *
  7252. neon_uri_unparse(
  7253. const ne_uri * uri,
  7254. apr_pool_t * pool)
  7255. {
  7256. char * unparsed_uri = NULL;
  7257. const char * result = NULL;
  7258. // Unparse uri.
  7259. unparsed_uri = ne_uri_unparse(uri);
  7260. result = uri_canonicalize(unparsed_uri, pool);
  7261. // Free neon's allocated copy.
  7262. ne_free(unparsed_uri);
  7263. // Return string allocated in result pool.
  7264. return result;
  7265. }
  7266. typedef struct body_reader_wrapper_baton_t
  7267. {
  7268. neon_request_t * req;
  7269. neon_block_reader real_reader;
  7270. void * real_baton;
  7271. } body_reader_wrapper_baton_t;
  7272. static int
  7273. body_reader_wrapper(
  7274. void * userdata,
  7275. const char * data,
  7276. size_t len)
  7277. {
  7278. body_reader_wrapper_baton_t * b = static_cast<body_reader_wrapper_baton_t *>(userdata);
  7279. if (b->req->err)
  7280. // We already had an error? Bail out.
  7281. return 1;
  7282. NEON_REQ_ERR(b->req, b->real_reader(b->real_baton, data, len));
  7283. if (b->req->err)
  7284. return 1;
  7285. return 0;
  7286. }
  7287. static void
  7288. neon_add_response_body_reader(
  7289. neon_request_t * req,
  7290. ne_accept_response accpt,
  7291. neon_block_reader reader,
  7292. void * userdata)
  7293. {
  7294. body_reader_wrapper_baton_t * b = static_cast<body_reader_wrapper_baton_t *>(apr_pcalloc(req->pool, sizeof(*b)));
  7295. b->req = req;
  7296. b->real_baton = userdata;
  7297. b->real_reader = reader;
  7298. attach_ne_body_reader(req, accpt, body_reader_wrapper, b);
  7299. }
  7300. //------------------------------------------------------------------------------
  7301. // from fetch.c
  7302. typedef struct file_read_ctx_t
  7303. {
  7304. apr_pool_t * pool;
  7305. // these two are the handler that the editor gave us
  7306. void * handler_baton;
  7307. // if we're receiving an svndiff, this is a parser which places the
  7308. // resulting windows into the above handler/baton.
  7309. stream_t * stream;
  7310. } file_read_ctx_t;
  7311. typedef struct file_write_ctx_t
  7312. {
  7313. stream_t * stream; // stream to write file contents to
  7314. } file_write_ctx_t;
  7315. typedef struct custom_get_ctx_t
  7316. {
  7317. neon_request_t * req; // Used to propagate errors out of the reader
  7318. int checked_type; // have we processed ctype yet?
  7319. void * subctx;
  7320. void * callback_baton;
  7321. } custom_get_ctx_t;
  7322. // Helper for neon_get_file. This implements
  7323. // the neon_block_reader() callback interface.
  7324. static error_t
  7325. get_file_reader(
  7326. void * userdata,
  7327. const char * buf,
  7328. size_t len)
  7329. {
  7330. custom_get_ctx_t * cgc = static_cast<custom_get_ctx_t *>(userdata);
  7331. if (cgc->req->sess->callbacks &&
  7332. cgc->req->sess->callbacks->cancel_func)
  7333. {
  7334. NEON_REQ_ERR(cgc->req, (cgc->req->sess->callbacks->cancel_func)(
  7335. cgc->req->sess->callback_baton));
  7336. }
  7337. assert(cgc->callback_baton);
  7338. callback_baton_t * cb = static_cast<callback_baton_t *>(cgc->callback_baton);
  7339. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(cb->ctx->auth_baton->parameters,
  7340. CONST_FS_KEY,
  7341. APR_HASH_KEY_STRING));
  7342. assert(fs);
  7343. fs->AdjustToCPSLimit(len);
  7344. // The stream we want to push data at.
  7345. file_write_ctx_t * fwc = static_cast<file_write_ctx_t *>(cgc->subctx);
  7346. stream_t * stream = fwc->stream;
  7347. // Write however many bytes were passed in by neon.
  7348. WEBDAV_ERR(stream_write(stream, buf, &len));
  7349. return WEBDAV_NO_ERROR;
  7350. }
  7351. static error_t
  7352. custom_get_request(
  7353. neon_session_t * ras,
  7354. const char * url,
  7355. const char * editor_relpath,
  7356. neon_block_reader reader,
  7357. void * subctx,
  7358. void * cb_baton,
  7359. apr_pool_t * pool)
  7360. {
  7361. custom_get_ctx_t cgc = { 0 };
  7362. neon_request_t * request = NULL;
  7363. error_t err = 0;
  7364. WEBDAV_ERR(neon_request_create(&request, ras, "GET", url, pool));
  7365. neon_add_response_body_reader(request, ne_accept_2xx, reader, &cgc);
  7366. // complete initialization of the body reading context
  7367. cgc.req = request;
  7368. cgc.subctx = subctx;
  7369. cgc.callback_baton = cb_baton;
  7370. // run the request
  7371. err = neon_request_dispatch(NULL, request, NULL, NULL,
  7372. 200 /* OK */,
  7373. 226 /* IM Used */,
  7374. false,
  7375. pool);
  7376. neon_request_destroy(request);
  7377. // The request runner raises internal errors before Neon errors,
  7378. // pass a returned error to our callers
  7379. return err;
  7380. }
  7381. //------------------------------------------------------------------------------
  7382. static error_t
  7383. get_file(
  7384. session_t * session,
  7385. const char * path,
  7386. stream_t * stream,
  7387. apr_hash_t ** props,
  7388. apr_pool_t * pool)
  7389. {
  7390. WEBDAV_ERR_ASSERT(*path != '/');
  7391. return session->vtable->get_file(session, path,
  7392. stream,
  7393. props, pool);
  7394. }
  7395. static error_t
  7396. get_dir2(
  7397. session_t * session,
  7398. apr_hash_t ** dirents,
  7399. const char * path,
  7400. apr_uint32_t dirent_fields,
  7401. apr_pool_t * pool)
  7402. {
  7403. WEBDAV_ERR_ASSERT(*path != '/');
  7404. return session->vtable->get_dir(session, dirents,
  7405. path,
  7406. dirent_fields, pool);
  7407. }
  7408. static error_t
  7409. get_webdav_resource_root2(
  7410. session_t * session,
  7411. const char ** url,
  7412. apr_pool_t * pool)
  7413. {
  7414. WEBDAV_ERR(session->vtable->get_webdav_resource_root(session, url, pool));
  7415. *url = *url ? apr_pstrdup(pool, *url) : NULL;
  7416. return WEBDAV_NO_ERROR;
  7417. }
  7418. static error_t
  7419. stat(
  7420. session_t * session,
  7421. const char * path,
  7422. dirent_t ** dirent,
  7423. apr_pool_t * pool)
  7424. {
  7425. WEBDAV_ERR_ASSERT(*path != '/');
  7426. return session->vtable->stat(session, path,
  7427. dirent, pool);
  7428. }
  7429. static error_t
  7430. get_path_relative_to_root(
  7431. session_t * session,
  7432. const char ** rel_path,
  7433. const char * url,
  7434. apr_pool_t * pool)
  7435. {
  7436. const char * root_url = NULL;
  7437. WEBDAV_ERR(session->vtable->get_webdav_resource_root(session, &root_url, pool));
  7438. if (strcmp(root_url, url) == 0)
  7439. {
  7440. *rel_path = "";
  7441. }
  7442. else
  7443. {
  7444. *rel_path = uri_is_child(root_url, url, pool);
  7445. if (!*rel_path)
  7446. {
  7447. return error_createf(WEBDAV_ERR_ILLEGAL_URL, NULL,
  7448. "'%s' isn't a child of root URL '%s'", url, root_url);
  7449. }
  7450. }
  7451. return WEBDAV_NO_ERROR;
  7452. }
  7453. static error_t
  7454. check_path(
  7455. session_t * session,
  7456. const char * path,
  7457. node_kind_t * kind,
  7458. apr_pool_t * pool)
  7459. {
  7460. WEBDAV_ERR_ASSERT(*path != '/');
  7461. return session->vtable->check_path(session, path,
  7462. kind, pool);
  7463. }
  7464. static error_t
  7465. reparent(
  7466. session_t * session,
  7467. const char * url,
  7468. apr_pool_t * pool)
  7469. {
  7470. return session->vtable->reparent(session, url, pool);
  7471. }
  7472. static error_t
  7473. session_open(
  7474. session_t ** session_p,
  7475. const char ** corrected_url_p,
  7476. const char * session_URL,
  7477. const callbacks2_t * callbacks,
  7478. void * callback_baton,
  7479. apr_pool_t * pool)
  7480. {
  7481. assert(callback_baton);
  7482. // check options, url, prepare parameters, callbacks, auth etc
  7483. apr_pool_t * sesspool = webdav_pool_create(pool);
  7484. // Initialize the return variable.
  7485. *session_p = NULL;
  7486. ne_uri * webdav_URI = NULL;
  7487. error_t err = parse_ne_uri(&webdav_URI, session_URL, sesspool);
  7488. if ((err != WEBDAV_NO_ERROR) || (webdav_URI->host == NULL))
  7489. {
  7490. return error_createf(WEBDAV_ERR_ILLEGAL_URL, NULL,
  7491. "Illegal URL '%s'", session_URL);
  7492. }
  7493. // Auth caching parameters.
  7494. bool store_passwords = WEBDAV_CONFIG_DEFAULT_OPTION_STORE_PASSWORDS;
  7495. bool store_auth_creds = WEBDAV_CONFIG_DEFAULT_OPTION_STORE_AUTH_CREDS;
  7496. const char * store_plaintext_passwords = WEBDAV_CONFIG_DEFAULT_OPTION_STORE_PLAINTEXT_PASSWORDS;
  7497. bool store_pp = WEBDAV_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP;
  7498. const char * store_pp_plaintext = WEBDAV_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT;
  7499. if (callbacks->auth_baton)
  7500. {
  7501. if (auth_baton_get_parameter(callbacks->auth_baton,
  7502. WEBDAV_AUTH_PARAM_DONT_STORE_PASSWORDS) != NULL)
  7503. {
  7504. store_passwords = FALSE;
  7505. }
  7506. if (auth_baton_get_parameter(callbacks->auth_baton,
  7507. WEBDAV_AUTH_PARAM_NO_AUTH_CACHE) != NULL)
  7508. {
  7509. store_auth_creds = FALSE;
  7510. }
  7511. }
  7512. if (callbacks->auth_baton)
  7513. {
  7514. // Save auth caching parameters in the auth parameter hash.
  7515. if (!store_passwords)
  7516. auth_baton_set_parameter(callbacks->auth_baton,
  7517. WEBDAV_AUTH_PARAM_DONT_STORE_PASSWORDS, "");
  7518. auth_baton_set_parameter(callbacks->auth_baton,
  7519. WEBDAV_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS,
  7520. store_plaintext_passwords);
  7521. if (!store_pp)
  7522. auth_baton_set_parameter(callbacks->auth_baton,
  7523. WEBDAV_AUTH_PARAM_DONT_STORE_SSL_CLIENT_CERT_PP,
  7524. "");
  7525. auth_baton_set_parameter(callbacks->auth_baton,
  7526. WEBDAV_AUTH_PARAM_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT,
  7527. store_pp_plaintext);
  7528. if (!store_auth_creds)
  7529. auth_baton_set_parameter(callbacks->auth_baton,
  7530. WEBDAV_AUTH_PARAM_NO_AUTH_CACHE, "");
  7531. }
  7532. const vtable_t * vtable = NULL;
  7533. WEBDAV_ERR(neon_init(&vtable, sesspool));
  7534. // Create the session object.
  7535. session_t * session = static_cast<session_t *>(apr_pcalloc(sesspool, sizeof(*session)));
  7536. session->vtable = vtable;
  7537. session->pool = sesspool;
  7538. const char * corrected_url = NULL;
  7539. // Ask the library to open the session.
  7540. WEBDAV_ERR_W(vtable->open_session(
  7541. session,
  7542. &corrected_url,
  7543. session_URL,
  7544. callbacks, callback_baton, sesspool),
  7545. apr_psprintf(pool, "Unable to connect to a WebDAV resource at URL '%s'",
  7546. session_URL));
  7547. if (corrected_url_p && corrected_url)
  7548. {
  7549. if (!path_is_url(corrected_url))
  7550. {
  7551. ne_uri * corrected_URI = NULL;
  7552. WEBDAV_ERR(parse_ne_uri(&corrected_URI, session_URL, sesspool));
  7553. if (corrected_URI->path) ne_free(corrected_URI->path);
  7554. corrected_URI->path = ne_strdup(corrected_url);
  7555. corrected_url = neon_uri_unparse(corrected_URI, pool);
  7556. }
  7557. *corrected_url_p = uri_canonicalize(corrected_url, pool);
  7558. webdav_pool_destroy(sesspool);
  7559. return WEBDAV_NO_ERROR;
  7560. }
  7561. *session_p = session;
  7562. return WEBDAV_NO_ERROR;
  7563. }
  7564. //---------------------------------------------------------------------------
  7565. // This implements the client_list_func_t API
  7566. static error_t
  7567. list_func(
  7568. void * baton,
  7569. const char * path,
  7570. const dirent_t * dirent,
  7571. const char * abs_path,
  7572. apr_pool_t * pool)
  7573. {
  7574. list_func_baton_t * pb = static_cast<list_func_baton_t *>(baton);
  7575. assert(pb);
  7576. assert(pb->entries);
  7577. const char * entryname = NULL;
  7578. neon_session_t * ras = static_cast<neon_session_t *>(pb->session->priv);
  7579. assert(ras);
  7580. if (ras->callbacks->cancel_func)
  7581. WEBDAV_ERR(ras->callbacks->cancel_func(ras->callback_baton));
  7582. if (strcmp(path, "") == 0)
  7583. {
  7584. if (dirent->kind == node_file)
  7585. entryname = dirent_basename(abs_path, pool);
  7586. else if (pb->verbose)
  7587. entryname = ".";
  7588. else
  7589. // Don't bother to list if no useful information will be shown.
  7590. return WEBDAV_NO_ERROR;
  7591. }
  7592. else
  7593. entryname = path;
  7594. if (pb->verbose)
  7595. {
  7596. apr_time_t now = apr_time_now();
  7597. apr_time_exp_t exp_time;
  7598. apr_status_t apr_err;
  7599. apr_size_t size;
  7600. char timestr[20];
  7601. const char * utf8_timestr;
  7602. // time_to_human_cstring gives us something *way* too long
  7603. // to use for this, so we have to roll our own. We include
  7604. // the year if the entry's time is not within half a year.
  7605. apr_time_exp_lt(&exp_time, dirent->time);
  7606. if (apr_time_sec(now - dirent->time) < (365 * 86400 / 2) &&
  7607. apr_time_sec(dirent->time - now) < (365 * 86400 / 2))
  7608. {
  7609. apr_err = apr_strftime(timestr, &size, sizeof(timestr),
  7610. "%b %d %H:%M", &exp_time);
  7611. }
  7612. else
  7613. {
  7614. apr_err = apr_strftime(timestr, &size, sizeof(timestr),
  7615. "%b %d %Y", &exp_time);
  7616. }
  7617. // if that failed, just zero out the string and print nothing
  7618. if (apr_err)
  7619. timestr[0] = '\0';
  7620. // we need it in UTF-8.
  7621. WEBDAV_ERR(utf_cstring_to_utf8(&utf8_timestr, timestr, pool));
  7622. TListDataEntry entry = {NULL, NULL, NULL, 0, false, false, {0}, NULL};
  7623. if (APR_SUCCESS != utf8_to_unicode(const_cast<wchar_t **>(&entry.Name), entryname, pb->pool))
  7624. {
  7625. return error_create(WEBDAV_ERR_DAV_MALFORMED_DATA, NULL, NULL);
  7626. }
  7627. entry.Permissions = L"";
  7628. entry.OwnerGroup = L"";
  7629. int dir = dirent->kind == node_dir;
  7630. entry.Size = dir == 0 ? dirent->size : 0;
  7631. entry.Dir = dir != 0;
  7632. entry.Link = false;
  7633. entry.Time.Year = exp_time.tm_year + 1900;
  7634. entry.Time.Month = exp_time.tm_mon + 1;
  7635. entry.Time.Day = exp_time.tm_mday;
  7636. entry.Time.Hour = exp_time.tm_hour;
  7637. entry.Time.Minute = exp_time.tm_min;
  7638. entry.Time.Second = exp_time.tm_sec;
  7639. entry.Time.HasTime = true;
  7640. entry.Time.HasSeconds = true;
  7641. entry.Time.HasDate = true;
  7642. entry.LinkTarget = L"";
  7643. pb->entries->push_back(entry);
  7644. }
  7645. return WEBDAV_NO_ERROR;
  7646. }
  7647. //---------------------------------------------------------------------------
  7648. // from url.c
  7649. static error_t
  7650. client_url_from_path2(
  7651. const char ** url,
  7652. const char * path_or_url,
  7653. stringbuf_t * session_url,
  7654. apr_pool_t * result_pool,
  7655. apr_pool_t * scratch_pool)
  7656. {
  7657. if (!path_is_url(path_or_url))
  7658. {
  7659. ne_uri * uri = NULL;
  7660. WEBDAV_ERR(parse_ne_uri(&uri, session_url->data, result_pool));
  7661. if (uri->path) ne_free(uri->path);
  7662. uri->path = ne_strdup(path_or_url);
  7663. const char * corrected_url = neon_uri_unparse(uri, result_pool);
  7664. *url = uri_canonicalize(corrected_url, result_pool);
  7665. }
  7666. else
  7667. *url = uri_canonicalize(path_or_url, result_pool);
  7668. return WEBDAV_NO_ERROR;
  7669. }
  7670. //---------------------------------------------------------------------------
  7671. // from ctx.c
  7672. static error_t
  7673. client_create_context(
  7674. client_ctx_t ** ctx,
  7675. apr_pool_t * pool)
  7676. {
  7677. *ctx = static_cast<client_ctx_t *>(apr_pcalloc(pool, sizeof(client_ctx_t)));
  7678. return WEBDAV_NO_ERROR;
  7679. }
  7680. //------------------------------------------------------------------------------
  7681. // from auth.c
  7682. static void
  7683. auth_baton_create(
  7684. auth_baton_t ** auth_baton,
  7685. apr_pool_t * pool)
  7686. {
  7687. auth_baton_t * ab = NULL;
  7688. // Build the auth_baton.
  7689. ab = static_cast<auth_baton_t *>(apr_pcalloc(pool, sizeof(*ab)));
  7690. ab->tables = apr_hash_make(pool);
  7691. ab->parameters = apr_hash_make(pool);
  7692. ab->creds_cache = apr_hash_make(pool);
  7693. ab->pool = pool;
  7694. *auth_baton = ab;
  7695. }
  7696. static void
  7697. create_baton_open(
  7698. auth_baton_t * auth_baton,
  7699. const apr_array_header_t * providers,
  7700. apr_pool_t * pool)
  7701. {
  7702. auth_provider_object_t * provider = NULL;
  7703. // Register each provider in order. Providers of different
  7704. // credentials will be automatically sorted into different tables by
  7705. // register_provider().
  7706. if (providers)
  7707. {
  7708. for (int i = 0; i < providers->nelts; i++)
  7709. {
  7710. provider_set_t * table = NULL;
  7711. provider = APR_ARRAY_IDX(providers, i, auth_provider_object_t *);
  7712. // Add it to the appropriate table in the auth_baton
  7713. table = static_cast<provider_set_t *>(apr_hash_get(auth_baton->tables,
  7714. provider->vtable->cred_kind, APR_HASH_KEY_STRING));
  7715. if (!table)
  7716. {
  7717. table = static_cast<provider_set_t *>(apr_pcalloc(pool, sizeof(*table)));
  7718. table->providers = apr_array_make(pool, 1, sizeof(auth_provider_object_t *));
  7719. apr_hash_set(auth_baton->tables,
  7720. provider->vtable->cred_kind, APR_HASH_KEY_STRING,
  7721. table);
  7722. }
  7723. APR_ARRAY_PUSH(table->providers, auth_provider_object_t *) = provider;
  7724. }
  7725. }
  7726. }
  7727. //---------------------------------------------------------------------------
  7728. // from ssl_client_cert_providers.c
  7729. // A function returning an SSL client certificate passphrase provider.
  7730. typedef void (*auth_ssl_client_cert_pw_provider_func_t)(
  7731. auth_provider_object_t ** provider,
  7732. apr_pool_t * pool);
  7733. // retrieve and load the ssl client certificate file from servers config
  7734. static error_t
  7735. ssl_client_cert_file_first_credentials(
  7736. void ** credentials_p,
  7737. void ** iter_baton,
  7738. void * provider_baton,
  7739. apr_hash_t * parameters,
  7740. const char * realmstring,
  7741. apr_pool_t * pool)
  7742. {
  7743. const char * cert_file;
  7744. cert_file = NULL;
  7745. if (cert_file != NULL)
  7746. {
  7747. auth_cred_ssl_client_cert_t * cred =
  7748. static_cast<auth_cred_ssl_client_cert_t *>(apr_pcalloc(pool, sizeof(*cred)));
  7749. cred->cert_file = cert_file;
  7750. cred->may_save = FALSE;
  7751. *credentials_p = cred;
  7752. }
  7753. else
  7754. {
  7755. *credentials_p = NULL;
  7756. }
  7757. *iter_baton = NULL;
  7758. return WEBDAV_NO_ERROR;
  7759. }
  7760. static const auth_provider_t ssl_client_cert_file_provider =
  7761. {
  7762. AUTH_CRED_SSL_CLIENT_CERT,
  7763. ssl_client_cert_file_first_credentials,
  7764. NULL,
  7765. NULL
  7766. };
  7767. // Public API to SSL file providers.
  7768. static void
  7769. auth_get_ssl_client_cert_file_provider(
  7770. auth_provider_object_t ** provider,
  7771. apr_pool_t * pool)
  7772. {
  7773. auth_provider_object_t * po =
  7774. static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
  7775. po->vtable = &ssl_client_cert_file_provider;
  7776. *provider = po;
  7777. }
  7778. /*-----------------------------------------------------------------------*/
  7779. // Prompt provider
  7780. /*-----------------------------------------------------------------------*/
  7781. // Baton type for prompting to send client ssl creds.
  7782. // There is no iteration baton type.
  7783. typedef struct ssl_client_cert_prompt_provider_baton_t
  7784. {
  7785. auth_ssl_client_cert_prompt_func_t prompt_func;
  7786. void * prompt_baton;
  7787. // how many times to re-prompt after the first one fails
  7788. int retry_limit;
  7789. } ssl_client_cert_prompt_provider_baton_t;
  7790. // Iteration baton.
  7791. typedef struct ssl_client_cert_prompt_iter_baton_t
  7792. {
  7793. // The original provider baton
  7794. ssl_client_cert_prompt_provider_baton_t * pb;
  7795. // The original realmstring
  7796. const char * realmstring;
  7797. // how many times we've reprompted
  7798. int retries;
  7799. } ssl_client_cert_prompt_iter_baton_t;
  7800. static error_t
  7801. ssl_client_cert_prompt_first_cred(
  7802. void ** credentials_p,
  7803. void ** iter_baton,
  7804. void * provider_baton,
  7805. apr_hash_t * parameters,
  7806. const char * realmstring,
  7807. apr_pool_t * pool)
  7808. {
  7809. ssl_client_cert_prompt_provider_baton_t * pb =
  7810. static_cast<ssl_client_cert_prompt_provider_baton_t *>(provider_baton);
  7811. ssl_client_cert_prompt_iter_baton_t * ib =
  7812. static_cast<ssl_client_cert_prompt_iter_baton_t *>(apr_pcalloc(pool, sizeof(*ib)));
  7813. const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
  7814. WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
  7815. APR_HASH_KEY_STRING));
  7816. WEBDAV_ERR(pb->prompt_func((auth_cred_ssl_client_cert_t **) credentials_p,
  7817. pb->prompt_baton, realmstring, !no_auth_cache,
  7818. pool));
  7819. ib->pb = pb;
  7820. ib->realmstring = apr_pstrdup(pool, realmstring);
  7821. ib->retries = 0;
  7822. *iter_baton = ib;
  7823. return WEBDAV_NO_ERROR;
  7824. }
  7825. static error_t
  7826. ssl_client_cert_prompt_next_cred(
  7827. void ** credentials_p,
  7828. void * iter_baton,
  7829. void * provider_baton,
  7830. apr_hash_t * parameters,
  7831. const char * realmstring,
  7832. apr_pool_t * pool)
  7833. {
  7834. ssl_client_cert_prompt_iter_baton_t * ib =
  7835. static_cast<ssl_client_cert_prompt_iter_baton_t *>(iter_baton);
  7836. const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
  7837. WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
  7838. APR_HASH_KEY_STRING));
  7839. if ((ib->pb->retry_limit >= 0) && (ib->retries >= ib->pb->retry_limit))
  7840. {
  7841. // give up, go on to next provider.
  7842. *credentials_p = NULL;
  7843. return WEBDAV_NO_ERROR;
  7844. }
  7845. ib->retries++;
  7846. return ib->pb->prompt_func((auth_cred_ssl_client_cert_t **)
  7847. credentials_p, ib->pb->prompt_baton,
  7848. ib->realmstring, !no_auth_cache, pool);
  7849. }
  7850. static const auth_provider_t ssl_client_cert_prompt_provider =
  7851. {
  7852. AUTH_CRED_SSL_CLIENT_CERT,
  7853. ssl_client_cert_prompt_first_cred,
  7854. ssl_client_cert_prompt_next_cred,
  7855. NULL
  7856. };
  7857. // Public API to SSL prompting providers.
  7858. static void
  7859. auth_get_ssl_client_cert_prompt_provider(
  7860. auth_provider_object_t ** provider,
  7861. auth_ssl_client_cert_prompt_func_t prompt_func,
  7862. void * prompt_baton,
  7863. int retry_limit,
  7864. apr_pool_t * pool)
  7865. {
  7866. auth_provider_object_t * po =
  7867. static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
  7868. ssl_client_cert_prompt_provider_baton_t * pb =
  7869. static_cast<ssl_client_cert_prompt_provider_baton_t *>(apr_pcalloc(pool, sizeof(*pb)));
  7870. pb->prompt_func = prompt_func;
  7871. pb->prompt_baton = prompt_baton;
  7872. pb->retry_limit = retry_limit;
  7873. po->vtable = &ssl_client_cert_prompt_provider;
  7874. po->provider_baton = pb;
  7875. *provider = po;
  7876. }
  7877. //---------------------------------------------------------------------------
  7878. // from ssl_server_trust_providers.c
  7879. // retrieve ssl server CA failure overrides (if any) from servers config
  7880. static error_t
  7881. ssl_server_trust_file_first_credentials(
  7882. void ** credentials,
  7883. void ** iter_baton,
  7884. void * provider_baton,
  7885. apr_hash_t * parameters,
  7886. const char * realmstring,
  7887. apr_pool_t * pool)
  7888. {
  7889. apr_uint32_t * failures = static_cast<apr_uint32_t *>(apr_hash_get(parameters,
  7890. AUTH_PARAM_SSL_SERVER_FAILURES,
  7891. APR_HASH_KEY_STRING));
  7892. const auth_ssl_server_cert_info_t * cert_info =
  7893. static_cast<const auth_ssl_server_cert_info_t *>(apr_hash_get(parameters,
  7894. AUTH_PARAM_SSL_SERVER_CERT_INFO,
  7895. APR_HASH_KEY_STRING));
  7896. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
  7897. CONST_FS_KEY,
  7898. APR_HASH_KEY_STRING));
  7899. assert(fs);
  7900. apr_hash_t * creds_hash = NULL;
  7901. error_t error = WEBDAV_NO_ERROR;
  7902. *credentials = NULL;
  7903. *iter_baton = NULL;
  7904. // Check if this is a permanently accepted certificate
  7905. error = config_read_auth_data(&creds_hash, AUTH_CRED_SSL_SERVER_TRUST,
  7906. realmstring, fs, pool);
  7907. error_clear(&error);
  7908. if (!error && creds_hash)
  7909. {
  7910. string_t * trusted_cert, *this_cert, *failstr;
  7911. apr_uint32_t last_failures = 0;
  7912. trusted_cert = static_cast<string_t *>(apr_hash_get(creds_hash, AUTHN_ASCII_CERT_KEY,
  7913. APR_HASH_KEY_STRING));
  7914. this_cert = string_create(cert_info->fingerprint, pool);
  7915. failstr = static_cast<string_t *>(apr_hash_get(creds_hash, AUTHN_FAILURES_KEY,
  7916. APR_HASH_KEY_STRING));
  7917. if (failstr)
  7918. {
  7919. char * endptr;
  7920. unsigned long tmp_ulong = strtoul(failstr->data, &endptr, 10);
  7921. if (*endptr == '\0')
  7922. last_failures = (apr_uint32_t) tmp_ulong;
  7923. }
  7924. // If the cert is trusted and there are no new failures, we
  7925. // accept it by clearing all failures.
  7926. if (trusted_cert &&
  7927. string_compare(this_cert, trusted_cert) &&
  7928. (*failures & ~last_failures) == 0)
  7929. {
  7930. *failures = 0;
  7931. }
  7932. }
  7933. // If all failures are cleared now, we return the creds
  7934. if (!*failures)
  7935. {
  7936. auth_cred_ssl_server_trust_t * creds =
  7937. static_cast<auth_cred_ssl_server_trust_t *>(apr_pcalloc(pool, sizeof(*creds)));
  7938. creds->may_save = FALSE; // No need to save it again...
  7939. *credentials = creds;
  7940. }
  7941. return WEBDAV_NO_ERROR;
  7942. }
  7943. static error_t
  7944. ssl_server_trust_file_save_credentials(
  7945. bool * saved,
  7946. void * credentials,
  7947. void * provider_baton,
  7948. apr_hash_t * parameters,
  7949. const char * realmstring,
  7950. apr_pool_t * pool)
  7951. {
  7952. auth_cred_ssl_server_trust_t * creds =
  7953. static_cast<auth_cred_ssl_server_trust_t *>(credentials);
  7954. const auth_ssl_server_cert_info_t * cert_info;
  7955. apr_hash_t * creds_hash = NULL;
  7956. if (!creds->may_save)
  7957. return WEBDAV_NO_ERROR;
  7958. cert_info = static_cast<const auth_ssl_server_cert_info_t *>(apr_hash_get(parameters,
  7959. AUTH_PARAM_SSL_SERVER_CERT_INFO,
  7960. APR_HASH_KEY_STRING));
  7961. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(parameters,
  7962. CONST_FS_KEY,
  7963. APR_HASH_KEY_STRING));
  7964. assert(fs);
  7965. creds_hash = apr_hash_make(pool);
  7966. apr_hash_set(creds_hash, AUTHN_ASCII_CERT_KEY, APR_HASH_KEY_STRING,
  7967. string_create(cert_info->fingerprint, pool));
  7968. apr_hash_set(creds_hash, AUTHN_FAILURES_KEY, APR_HASH_KEY_STRING,
  7969. string_createf(pool, "%lu", (unsigned long)
  7970. creds->accepted_failures));
  7971. WEBDAV_ERR(config_write_auth_data(creds_hash,
  7972. AUTH_CRED_SSL_SERVER_TRUST,
  7973. realmstring,
  7974. fs,
  7975. pool));
  7976. *saved = TRUE;
  7977. return WEBDAV_NO_ERROR;
  7978. }
  7979. static const auth_provider_t ssl_server_trust_file_provider =
  7980. {
  7981. AUTH_CRED_SSL_SERVER_TRUST,
  7982. &ssl_server_trust_file_first_credentials,
  7983. NULL,
  7984. &ssl_server_trust_file_save_credentials,
  7985. };
  7986. // Public API to SSL file providers.
  7987. static void
  7988. auth_get_ssl_server_trust_file_provider(
  7989. auth_provider_object_t ** provider,
  7990. apr_pool_t * pool)
  7991. {
  7992. auth_provider_object_t * po =
  7993. static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
  7994. po->vtable = &ssl_server_trust_file_provider;
  7995. *provider = po;
  7996. }
  7997. /*-----------------------------------------------------------------------*/
  7998. // Prompt provider
  7999. /*-----------------------------------------------------------------------*/
  8000. // Baton type for prompting to verify server ssl creds.
  8001. // There is no iteration baton type.
  8002. typedef struct ssl_server_trust_prompt_provider_baton_t
  8003. {
  8004. auth_ssl_server_trust_prompt_func_t prompt_func;
  8005. void * prompt_baton;
  8006. } ssl_server_trust_prompt_provider_baton_t;
  8007. static error_t
  8008. ssl_server_trust_prompt_first_cred(
  8009. void ** credentials_p,
  8010. void ** iter_baton,
  8011. void * provider_baton,
  8012. apr_hash_t * parameters,
  8013. const char * realmstring,
  8014. apr_pool_t * pool)
  8015. {
  8016. ssl_server_trust_prompt_provider_baton_t * pb =
  8017. static_cast<ssl_server_trust_prompt_provider_baton_t *>(provider_baton);
  8018. apr_uint32_t * failures = static_cast<apr_uint32_t *>(apr_hash_get(parameters,
  8019. AUTH_PARAM_SSL_SERVER_FAILURES,
  8020. APR_HASH_KEY_STRING));
  8021. const char * no_auth_cache = static_cast<const char *>(apr_hash_get(parameters,
  8022. WEBDAV_AUTH_PARAM_NO_AUTH_CACHE,
  8023. APR_HASH_KEY_STRING));
  8024. const auth_ssl_server_cert_info_t * cert_info =
  8025. static_cast<const auth_ssl_server_cert_info_t *>(apr_hash_get(parameters,
  8026. AUTH_PARAM_SSL_SERVER_CERT_INFO,
  8027. APR_HASH_KEY_STRING));
  8028. WEBDAV_ERR(pb->prompt_func((auth_cred_ssl_server_trust_t **)
  8029. credentials_p, pb->prompt_baton, realmstring,
  8030. *failures, cert_info, !no_auth_cache &&
  8031. !(*failures & WEBDAV_AUTH_SSL_OTHER), pool));
  8032. *iter_baton = NULL;
  8033. return WEBDAV_NO_ERROR;
  8034. }
  8035. static const auth_provider_t ssl_server_trust_prompt_provider =
  8036. {
  8037. AUTH_CRED_SSL_SERVER_TRUST,
  8038. ssl_server_trust_prompt_first_cred,
  8039. NULL,
  8040. NULL
  8041. };
  8042. // Public API to SSL prompting providers.
  8043. static void
  8044. auth_get_ssl_server_trust_prompt_provider(
  8045. auth_provider_object_t ** provider,
  8046. auth_ssl_server_trust_prompt_func_t prompt_func,
  8047. void * prompt_baton,
  8048. apr_pool_t * pool)
  8049. {
  8050. auth_provider_object_t * po =
  8051. static_cast<auth_provider_object_t *>(apr_pcalloc(pool, sizeof(*po)));
  8052. ssl_server_trust_prompt_provider_baton_t * pb =
  8053. static_cast<ssl_server_trust_prompt_provider_baton_t *>(apr_pcalloc(pool, sizeof(*pb)));
  8054. pb->prompt_func = prompt_func;
  8055. pb->prompt_baton = prompt_baton;
  8056. po->vtable = &ssl_server_trust_prompt_provider;
  8057. po->provider_baton = pb;
  8058. *provider = po;
  8059. }
  8060. //---------------------------------------------------------------------------
  8061. // from cmdline.h
  8062. typedef struct cmdline_prompt_baton2_t
  8063. {
  8064. cancel_func_t cancel_func;
  8065. void * cancel_baton;
  8066. } cmdline_prompt_baton2_t;
  8067. //---------------------------------------------------------------------------
  8068. // from prompt.c
  8069. // This is a helper for plaintext prompt functions.
  8070. static error_t
  8071. plaintext_prompt_helper(
  8072. bool * may_save_plaintext,
  8073. const char * realmstring,
  8074. const char * prompt_string,
  8075. const char * prompt_text,
  8076. void * baton,
  8077. apr_pool_t * pool)
  8078. {
  8079. cmdline_prompt_baton2_t * pb = static_cast<cmdline_prompt_baton2_t *>(baton);
  8080. auth_baton_t * ab = static_cast<auth_baton_t *>(pb->cancel_baton);
  8081. assert(ab);
  8082. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(ab->parameters,
  8083. CONST_FS_KEY,
  8084. APR_HASH_KEY_STRING));
  8085. assert(fs);
  8086. unsigned int RequestResult = 0;
  8087. error_t err = fs->SimplePrompt(prompt_text, prompt_string, RequestResult);
  8088. if (err)
  8089. {
  8090. if (err == WEBDAV_ERR_CANCELLED)
  8091. {
  8092. error_clear(&err);
  8093. *may_save_plaintext = FALSE;
  8094. return WEBDAV_NO_ERROR;
  8095. }
  8096. else
  8097. return err;
  8098. }
  8099. if (RequestResult == qaYes)
  8100. {
  8101. *may_save_plaintext = TRUE;
  8102. }
  8103. else if (RequestResult == qaNo)
  8104. {
  8105. *may_save_plaintext = FALSE;
  8106. }
  8107. return WEBDAV_NO_ERROR;
  8108. }
  8109. // This implements 'auth_plaintext_prompt_func_t'.
  8110. static error_t
  8111. cmdline_auth_plaintext_prompt(
  8112. bool * may_save_plaintext,
  8113. const char * realmstring,
  8114. void * baton,
  8115. apr_pool_t * pool)
  8116. {
  8117. const char * prompt_string = "Store password unencrypted (yes/no)? ";
  8118. const char * prompt_text =
  8119. "\n-----------------------------------------------------------------------"
  8120. "\nATTENTION! Your password for authentication realm:\n"
  8121. "\n"
  8122. " %s\n"
  8123. "\n"
  8124. "can only be stored to disk unencrypted! You are advised to configure\n"
  8125. "your system so that system can store passwords encrypted, if\n"
  8126. "possible. See the documentation for details.\n"
  8127. "\n"
  8128. "You can avoid future appearances of this warning by setting the value\n"
  8129. "of the 'store-plaintext-passwords' option to either 'yes' or 'no' in\n"
  8130. "'%s'.\n"
  8131. "-----------------------------------------------------------------------\n"
  8132. ;
  8133. return plaintext_prompt_helper(may_save_plaintext, realmstring,
  8134. prompt_string, prompt_text, baton,
  8135. pool);
  8136. }
  8137. // This implements 'auth_plaintext_passphrase_prompt_func_t'.
  8138. static error_t
  8139. cmdline_auth_plaintext_passphrase_prompt(
  8140. bool * may_save_plaintext,
  8141. const char * realmstring,
  8142. void * baton,
  8143. apr_pool_t * pool)
  8144. {
  8145. const char * prompt_string = "Store passphrase unencrypted (yes/no)? ";
  8146. const char * prompt_text =
  8147. "\n-----------------------------------------------------------------------\n"
  8148. "ATTENTION! Your passphrase for client certificate:\n"
  8149. "\n"
  8150. " %s\n"
  8151. "\n"
  8152. "can only be stored to disk unencrypted! You are advised to configure\n"
  8153. "your system so that system can store passphrase encrypted, if\n"
  8154. "possible. See the documentation for details.\n"
  8155. "\n"
  8156. "You can avoid future appearances of this warning by setting the value\n"
  8157. "of the 'store-ssl-client-cert-pp-plaintext' option to either 'yes' or\n"
  8158. "'no' in '%s'.\n"
  8159. "-----------------------------------------------------------------------\n"
  8160. ;
  8161. return plaintext_prompt_helper(may_save_plaintext, realmstring,
  8162. prompt_string, prompt_text, baton,
  8163. pool);
  8164. }
  8165. // This implements 'auth_ssl_server_trust_prompt_func_t'.
  8166. static error_t
  8167. cmdline_auth_ssl_server_trust_prompt(
  8168. auth_cred_ssl_server_trust_t ** cred_p,
  8169. void * baton,
  8170. const char * realm,
  8171. apr_uint32_t failures,
  8172. const auth_ssl_server_cert_info_t * cert_info,
  8173. bool may_save,
  8174. apr_pool_t * pool)
  8175. {
  8176. cmdline_prompt_baton2_t * pb =
  8177. static_cast<cmdline_prompt_baton2_t *>(baton);
  8178. stringbuf_t * buf = stringbuf_create("", pool);
  8179. /*if (failures & WEBDAV_AUTH_SSL_UNKNOWNCA)
  8180. {
  8181. stringbuf_appendcstr(buf,
  8182. " - The certificate is not issued by a trusted authority. Use the\n"
  8183. " fingerprint to validate the certificate manually!\n");
  8184. }*/
  8185. if (failures & WEBDAV_AUTH_SSL_CNMISMATCH)
  8186. {
  8187. stringbuf_appendcstr(buf, "- The certificate hostname does not match.\n");
  8188. }
  8189. if (failures & WEBDAV_AUTH_SSL_NOTYETVALID)
  8190. {
  8191. stringbuf_appendcstr(buf, "- The certificate is not yet valid.\n");
  8192. }
  8193. if (failures & WEBDAV_AUTH_SSL_EXPIRED)
  8194. {
  8195. stringbuf_appendcstr(buf, "- The certificate has expired.\n");
  8196. }
  8197. if (failures & WEBDAV_AUTH_SSL_OTHER)
  8198. {
  8199. stringbuf_appendcstr(buf, "- The certificate has an unknown error.\n");
  8200. }
  8201. stringbuf_t * msg = stringbuf_createf(pool,
  8202. // "Certificate information:\n"
  8203. " - Hostname: %s\n"
  8204. " - Valid: from %s until %s\n"
  8205. " - Issuer: %s\n"
  8206. " - Fingerprint: %s",
  8207. cert_info->hostname,
  8208. cert_info->valid_from,
  8209. cert_info->valid_until,
  8210. cert_info->issuer_dname,
  8211. cert_info->fingerprint);
  8212. stringbuf_appendstr(buf, msg);
  8213. auth_baton_t * ab = static_cast<auth_baton_t *>(pb->cancel_baton);
  8214. assert(ab);
  8215. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(ab->parameters,
  8216. CONST_FS_KEY,
  8217. APR_HASH_KEY_STRING));
  8218. assert(fs);
  8219. unsigned int RequestResult = 0;
  8220. WEBDAV_ERR(fs->VerifyCertificate(buf->data, cert_info->fingerprint, RequestResult));
  8221. if (RequestResult == qaYes)
  8222. {
  8223. *cred_p = static_cast<auth_cred_ssl_server_trust_t *>(apr_pcalloc(pool, sizeof(**cred_p)));
  8224. (*cred_p)->may_save = TRUE;
  8225. (*cred_p)->accepted_failures = failures;
  8226. }
  8227. else if (RequestResult == qaNo)
  8228. {
  8229. *cred_p = static_cast<auth_cred_ssl_server_trust_t *>(apr_pcalloc(pool, sizeof(**cred_p)));
  8230. (*cred_p)->may_save = FALSE;
  8231. (*cred_p)->accepted_failures = failures;
  8232. }
  8233. else
  8234. {
  8235. *cred_p = NULL;
  8236. }
  8237. return WEBDAV_NO_ERROR;
  8238. }
  8239. // This implements 'auth_ssl_client_cert_prompt_func_t'.
  8240. static error_t
  8241. cmdline_auth_ssl_client_cert_prompt(
  8242. auth_cred_ssl_client_cert_t ** cred_p,
  8243. void * baton,
  8244. const char * realm,
  8245. bool may_save,
  8246. apr_pool_t * pool)
  8247. {
  8248. auth_cred_ssl_client_cert_t * cred = NULL;
  8249. const char * cert_file = NULL;
  8250. const char * abs_cert_file = NULL;
  8251. cmdline_prompt_baton2_t * pb =
  8252. static_cast<cmdline_prompt_baton2_t *>(baton);
  8253. auth_baton_t * ab = static_cast<auth_baton_t *>(pb->cancel_baton);
  8254. assert(ab);
  8255. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(ab->parameters,
  8256. CONST_FS_KEY,
  8257. APR_HASH_KEY_STRING));
  8258. assert(fs);
  8259. unsigned int RequestResult = 0;
  8260. WEBDAV_ERR(fs->AskForClientCertificateFilename(&cert_file, RequestResult, pool));
  8261. if (RequestResult != qaOK) return WEBDAV_NO_ERROR;
  8262. WEBDAV_ERR(dirent_get_absolute(&abs_cert_file, cert_file, pool));
  8263. cred = static_cast<auth_cred_ssl_client_cert_t *>(apr_pcalloc(pool, sizeof(*cred)));
  8264. cred->cert_file = abs_cert_file;
  8265. cred->may_save = may_save;
  8266. *cred_p = cred;
  8267. return WEBDAV_NO_ERROR;
  8268. }
  8269. // This implements 'auth_ssl_client_cert_pw_prompt_func_t'.
  8270. static error_t
  8271. cmdline_auth_ssl_client_cert_pw_prompt(
  8272. auth_cred_ssl_client_cert_pw_t ** cred_p,
  8273. void * baton,
  8274. const char * realm,
  8275. bool may_save,
  8276. apr_pool_t * pool)
  8277. {
  8278. auth_cred_ssl_client_cert_pw_t * cred = NULL;
  8279. cmdline_prompt_baton2_t * pb =
  8280. static_cast<cmdline_prompt_baton2_t *>(baton);
  8281. auth_baton_t * ab = static_cast<auth_baton_t *>(pb->cancel_baton);
  8282. assert(ab);
  8283. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(ab->parameters,
  8284. CONST_FS_KEY,
  8285. APR_HASH_KEY_STRING));
  8286. assert(fs);
  8287. unsigned int RequestResult = 0;
  8288. const char * result = NULL;
  8289. WEBDAV_ERR(fs->AskForPassphrase(&result, realm, RequestResult, pool));
  8290. if (RequestResult != qaOK) return WEBDAV_NO_ERROR;
  8291. cred = static_cast<auth_cred_ssl_client_cert_pw_t *>(apr_pcalloc(pool, sizeof(*cred)));
  8292. cred->password = result;
  8293. cred->may_save = may_save;
  8294. *cred_p = cred;
  8295. return WEBDAV_NO_ERROR;
  8296. }
  8297. // This implements 'auth_simple_prompt_func_t'.
  8298. static error_t
  8299. cmdline_auth_simple_prompt(
  8300. auth_cred_simple_t ** cred_p,
  8301. void * baton,
  8302. const char * realm,
  8303. const char * username,
  8304. bool may_save,
  8305. apr_pool_t * pool)
  8306. {
  8307. auth_cred_simple_t * ret =
  8308. static_cast<auth_cred_simple_t *>(apr_pcalloc(pool, sizeof(*ret)));
  8309. cmdline_prompt_baton2_t * pb =
  8310. static_cast<cmdline_prompt_baton2_t *>(baton);
  8311. auth_baton_t * ab = static_cast<auth_baton_t *>(pb->cancel_baton);
  8312. assert(ab);
  8313. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(ab->parameters,
  8314. CONST_FS_KEY,
  8315. APR_HASH_KEY_STRING));
  8316. assert(fs);
  8317. unsigned int RequestResult = 0;
  8318. if (username)
  8319. ret->username = apr_pstrdup(pool, username);
  8320. else
  8321. {
  8322. WEBDAV_ERR(fs->AskForUsername(&ret->username, RequestResult, pool));
  8323. if (RequestResult != qaOK) return WEBDAV_NO_ERROR;
  8324. }
  8325. WEBDAV_ERR(fs->AskForUserPassword(&ret->password, RequestResult, pool));
  8326. if (RequestResult != qaOK) return WEBDAV_NO_ERROR;
  8327. ret->may_save = may_save;
  8328. *cred_p = ret;
  8329. return WEBDAV_NO_ERROR;
  8330. }
  8331. // This implements 'auth_username_prompt_func_t'.
  8332. static error_t
  8333. cmdline_auth_username_prompt(
  8334. auth_cred_username_t ** cred_p,
  8335. void * baton,
  8336. const char * realm,
  8337. bool may_save,
  8338. apr_pool_t * pool)
  8339. {
  8340. auth_cred_username_t * ret =
  8341. static_cast<auth_cred_username_t *>(apr_pcalloc(pool, sizeof(*ret)));
  8342. cmdline_prompt_baton2_t * pb =
  8343. static_cast<cmdline_prompt_baton2_t *>(baton);
  8344. auth_baton_t * ab = static_cast<auth_baton_t *>(pb->cancel_baton);
  8345. assert(ab);
  8346. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(ab->parameters,
  8347. CONST_FS_KEY,
  8348. APR_HASH_KEY_STRING));
  8349. assert(fs);
  8350. unsigned int RequestResult = 0;
  8351. WEBDAV_ERR(fs->AskForUsername(&ret->username, RequestResult, pool));
  8352. if (RequestResult != qaOK) return WEBDAV_NO_ERROR;
  8353. ret->may_save = may_save;
  8354. *cred_p = ret;
  8355. return WEBDAV_NO_ERROR;
  8356. }
  8357. //---------------------------------------------------------------------------
  8358. // from cmdline.c
  8359. static error_t
  8360. ssl_trust_unknown_server_cert(
  8361. auth_cred_ssl_server_trust_t ** cred_p,
  8362. void * baton,
  8363. const char * realm,
  8364. apr_uint32_t failures,
  8365. const auth_ssl_server_cert_info_t * cert_info,
  8366. bool may_save,
  8367. apr_pool_t * pool)
  8368. {
  8369. *cred_p = NULL;
  8370. if (failures == 0 || failures == WEBDAV_AUTH_SSL_UNKNOWNCA)
  8371. {
  8372. *cred_p = static_cast<auth_cred_ssl_server_trust_t *>(apr_pcalloc(pool, sizeof(**cred_p)));
  8373. (*cred_p)->may_save = FALSE;
  8374. (*cred_p)->accepted_failures = failures;
  8375. }
  8376. return WEBDAV_NO_ERROR;
  8377. }
  8378. static error_t
  8379. auth_baton_init(
  8380. auth_baton_t * ab,
  8381. bool non_interactive,
  8382. const char * auth_username,
  8383. const char * auth_password,
  8384. bool no_auth_cache,
  8385. bool trust_server_cert,
  8386. TWebDAVFileSystem * fs,
  8387. cancel_func_t cancel_func,
  8388. void * cancel_baton,
  8389. apr_pool_t * pool)
  8390. {
  8391. bool store_password_val = TRUE;
  8392. bool store_auth_creds_val = TRUE;
  8393. auth_provider_object_t * provider = NULL;
  8394. cmdline_prompt_baton2_t * pb = NULL;
  8395. // The whole list of registered providers
  8396. apr_array_header_t * providers = NULL;
  8397. // Populate the registered providers with the platform-specific providers
  8398. WEBDAV_ERR(auth_get_platform_specific_client_providers(&providers,
  8399. pool));
  8400. // If we have a cancellation function, cram it and the stuff it
  8401. // needs into the prompt baton.
  8402. if (cancel_func)
  8403. {
  8404. pb = static_cast<cmdline_prompt_baton2_t *>(apr_pcalloc(pool, sizeof(*pb)));
  8405. pb->cancel_func = cancel_func;
  8406. pb->cancel_baton = cancel_baton;
  8407. }
  8408. if (non_interactive == FALSE)
  8409. {
  8410. // This provider doesn't prompt the user in order to get creds;
  8411. // it prompts the user regarding the caching of creds.
  8412. auth_get_simple_provider2(&provider,
  8413. cmdline_auth_plaintext_prompt,
  8414. pb, pool);
  8415. }
  8416. else
  8417. {
  8418. auth_get_simple_provider2(&provider, NULL, NULL, pool);
  8419. }
  8420. APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
  8421. auth_get_username_provider(&provider, pool);
  8422. APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
  8423. // The server-cert, client-cert, and client-cert-password providers.
  8424. WEBDAV_ERR(auth_get_platform_specific_provider(&provider,
  8425. "windows",
  8426. "ssl_server_trust",
  8427. pool));
  8428. APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
  8429. auth_get_ssl_server_trust_file_provider(&provider, pool);
  8430. APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
  8431. auth_get_ssl_client_cert_file_provider(&provider, pool);
  8432. APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
  8433. if (non_interactive == FALSE)
  8434. {
  8435. // This provider doesn't prompt the user in order to get creds;
  8436. // it prompts the user regarding the caching of creds.
  8437. auth_get_ssl_client_cert_pw_file_provider2(&provider, cmdline_auth_plaintext_passphrase_prompt,
  8438. pb, pool);
  8439. }
  8440. else
  8441. {
  8442. auth_get_ssl_client_cert_pw_file_provider2(&provider, NULL, NULL,
  8443. pool);
  8444. }
  8445. APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
  8446. if (non_interactive == FALSE)
  8447. {
  8448. // Two basic prompt providers: username/password, and just username.
  8449. auth_get_simple_prompt_provider(&provider,
  8450. cmdline_auth_simple_prompt,
  8451. pb,
  8452. 2, // retry limit
  8453. pool);
  8454. APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
  8455. auth_get_username_prompt_provider(&provider, cmdline_auth_username_prompt, pb,
  8456. 2, /* retry limit */ pool);
  8457. APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
  8458. // Three ssl prompt providers, for server-certs, client-certs,
  8459. // and client-cert-passphrases.
  8460. auth_get_ssl_server_trust_prompt_provider(&provider, cmdline_auth_ssl_server_trust_prompt, pb, pool);
  8461. APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
  8462. auth_get_ssl_client_cert_prompt_provider(&provider, cmdline_auth_ssl_client_cert_prompt, pb, 2, pool);
  8463. APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
  8464. auth_get_ssl_client_cert_pw_prompt_provider(&provider, cmdline_auth_ssl_client_cert_pw_prompt, pb, 2, pool);
  8465. APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
  8466. }
  8467. else if (trust_server_cert)
  8468. {
  8469. // Remember, only register this provider if non_interactive.
  8470. auth_get_ssl_server_trust_prompt_provider(&provider, ssl_trust_unknown_server_cert, NULL, pool);
  8471. APR_ARRAY_PUSH(providers, auth_provider_object_t *) = provider;
  8472. }
  8473. // Build an authentication baton to give to libclient.
  8474. create_baton_open(ab, providers, pool);
  8475. auth_baton_set_parameter(ab, CONST_FS_KEY, fs);
  8476. // Place any default username or password credentials into the
  8477. // auth_baton's run-time parameter hash.
  8478. if (auth_username)
  8479. auth_baton_set_parameter(ab, WEBDAV_AUTH_PARAM_DEFAULT_USERNAME,
  8480. auth_username);
  8481. if (auth_password)
  8482. auth_baton_set_parameter(ab, WEBDAV_AUTH_PARAM_DEFAULT_PASSWORD,
  8483. auth_password);
  8484. // Same with the non-interactive option.
  8485. if (non_interactive)
  8486. auth_baton_set_parameter(ab, WEBDAV_AUTH_PARAM_NON_INTERACTIVE, "");
  8487. if (!store_password_val)
  8488. auth_baton_set_parameter(ab, WEBDAV_AUTH_PARAM_DONT_STORE_PASSWORDS, "");
  8489. if (no_auth_cache || !store_auth_creds_val)
  8490. auth_baton_set_parameter(ab, WEBDAV_AUTH_PARAM_NO_AUTH_CACHE, "");
  8491. return WEBDAV_NO_ERROR;
  8492. }
  8493. //---------------------------------------------------------------------------
  8494. // from main.c
  8495. // A flag to see if we've been canceled by the client or not.
  8496. static volatile atomic_t cancelled = FALSE;
  8497. // Our cancellation callback.
  8498. static error_t
  8499. check_cancel(void * baton)
  8500. {
  8501. if (cancelled)
  8502. return error_create(WEBDAV_ERR_CANCELLED, NULL, "Cancelled");
  8503. else
  8504. return WEBDAV_NO_ERROR;
  8505. }
  8506. //---------------------------------------------------------------------------
  8507. // from ra.c
  8508. static error_t
  8509. cancel_callback(void * baton)
  8510. {
  8511. callback_baton_t * cb = static_cast<callback_baton_t *>(baton);
  8512. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(cb->ctx->auth_baton->parameters,
  8513. CONST_FS_KEY,
  8514. APR_HASH_KEY_STRING));
  8515. assert(fs);
  8516. cancelled = static_cast<atomic_t>(fs->GetIsCancelled());
  8517. return error_trace((cb->ctx->cancel_func)(cb->ctx->cancel_baton));
  8518. }
  8519. static error_t
  8520. get_client_string(
  8521. void * baton,
  8522. const char ** name,
  8523. apr_pool_t * pool)
  8524. {
  8525. callback_baton_t * b = static_cast<callback_baton_t *>(baton);
  8526. *name = apr_pstrdup(pool, b->ctx->client_name);
  8527. return WEBDAV_NO_ERROR;
  8528. }
  8529. // see ra.c::client_session_from_path
  8530. static error_t
  8531. init_session_from_path(
  8532. session_t * session,
  8533. const char ** url_p,
  8534. const char * path_or_url,
  8535. apr_pool_t * pool)
  8536. {
  8537. const char * initial_url, *url;
  8538. neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
  8539. assert(ras);
  8540. WEBDAV_ERR(client_url_from_path2(&initial_url, path_or_url,
  8541. ras->url, pool, pool));
  8542. if (!initial_url)
  8543. return error_createf(WEBDAV_ERR_ENTRY_MISSING_URL, NULL,
  8544. "'%s' has no URL", path_or_url);
  8545. url = initial_url;
  8546. // Make the session point to the real URL.
  8547. WEBDAV_ERR(reparent(session, url, pool));
  8548. *url_p = url;
  8549. return WEBDAV_NO_ERROR;
  8550. }
  8551. static error_t
  8552. client_open_session_internal(
  8553. session_t ** ra_session,
  8554. const char ** corrected_url,
  8555. const char * base_url,
  8556. client_ctx_t * ctx,
  8557. apr_pool_t * pool)
  8558. {
  8559. // prepare callbacks, contexts
  8560. callbacks2_t * cbtable = static_cast<callbacks2_t *>(apr_pcalloc(pool, sizeof(*cbtable)));
  8561. callback_baton_t * cb = static_cast<callback_baton_t *>(apr_pcalloc(pool, sizeof(*cb)));
  8562. cbtable->auth_baton = ctx->auth_baton;
  8563. cbtable->progress_func = ctx->progress_func;
  8564. cbtable->progress_baton = ctx->progress_baton;
  8565. cbtable->cancel_func = ctx->cancel_func ? cancel_callback : NULL;
  8566. cbtable->get_client_string = get_client_string;
  8567. cb->pool = pool;
  8568. cb->ctx = ctx;
  8569. if (corrected_url)
  8570. {
  8571. apr_hash_t * attempted = apr_hash_make(pool);
  8572. int attempts_left = MAX_REDIRECT_ATTEMPTS;
  8573. while (attempts_left--)
  8574. {
  8575. const char * corrected = NULL;
  8576. WEBDAV_ERR(session_open(
  8577. ra_session,
  8578. attempts_left == 0 ? NULL : &corrected,
  8579. base_url, cbtable, cb,
  8580. pool));
  8581. // No error and no corrected URL? We're done here.
  8582. if (!corrected)
  8583. break;
  8584. // Our caller will want to know what our final corrected URL was.
  8585. *corrected_url = corrected;
  8586. // Make sure we've not attempted this URL before.
  8587. if (apr_hash_get(attempted, corrected, APR_HASH_KEY_STRING))
  8588. return WEBDAV_ERR_CLIENT_CYCLE_DETECTED;
  8589. // Remember this CORRECTED_URL so we don't wind up in a loop.
  8590. apr_hash_set(attempted, apr_pstrdup(pool, corrected), APR_HASH_KEY_STRING, (void *)1);
  8591. base_url = corrected;
  8592. }
  8593. }
  8594. else
  8595. {
  8596. WEBDAV_ERR(session_open(ra_session, NULL, base_url,
  8597. cbtable, cb,
  8598. pool));
  8599. }
  8600. return WEBDAV_NO_ERROR;
  8601. }
  8602. //---------------------------------------------------------------------------
  8603. // from list.c
  8604. static error_t
  8605. get_dir_contents(
  8606. apr_uint32_t dirent_fields,
  8607. const char * dir,
  8608. session_t * ra_session,
  8609. const char * fs_path,
  8610. depth_t depth,
  8611. client_list_func_t list_func,
  8612. void * baton,
  8613. apr_pool_t * pool)
  8614. {
  8615. apr_hash_t * tmpdirents = NULL;
  8616. apr_pool_t * iterpool = webdav_pool_create(pool);
  8617. apr_array_header_t * array = NULL;
  8618. error_t err = 0;
  8619. if (depth == depth_empty)
  8620. return WEBDAV_NO_ERROR;
  8621. // Get the directory's entries, but not its props. Ignore any
  8622. // not-authorized errors.
  8623. err = get_dir2(ra_session, &tmpdirents,
  8624. dir,
  8625. dirent_fields, pool);
  8626. if (err && ((err == WEBDAV_ERR_NOT_AUTHORIZED) ||
  8627. (err == WEBDAV_ERR_DAV_FORBIDDEN)))
  8628. {
  8629. error_clear(&err);
  8630. return WEBDAV_NO_ERROR;
  8631. }
  8632. WEBDAV_ERR(err);
  8633. neon_session_t * ras = static_cast<neon_session_t *>(ra_session->priv);
  8634. assert(ras);
  8635. if (ras->callbacks->cancel_func)
  8636. WEBDAV_ERR(ras->callbacks->cancel_func(ras->callback_baton));
  8637. // Sort the hash, so we can call the callback in a "deterministic" order.
  8638. array = sort_hash(tmpdirents, sort_compare_items_lexically, pool);
  8639. for (int i = 0; i < array->nelts; ++i)
  8640. {
  8641. sort_item_t * item = &APR_ARRAY_IDX(array, i, sort_item_t);
  8642. dirent_t * the_ent = static_cast<dirent_t *>(apr_hash_get(tmpdirents, item->key, item->klen));
  8643. webdav_pool_clear(iterpool);
  8644. const char * path = relpath_join(dir, static_cast<const char *>(item->key), iterpool);
  8645. if ((the_ent->kind == node_file) ||
  8646. (depth == depth_immediates) ||
  8647. (depth == depth_infinity))
  8648. WEBDAV_ERR(list_func(baton, path,
  8649. the_ent,
  8650. fs_path, iterpool));
  8651. if (depth == depth_infinity && the_ent->kind == node_dir)
  8652. WEBDAV_ERR(get_dir_contents(dirent_fields, path,
  8653. ra_session,
  8654. fs_path, depth,
  8655. list_func, baton, iterpool));
  8656. }
  8657. webdav_pool_destroy(iterpool);
  8658. return WEBDAV_NO_ERROR;
  8659. }
  8660. //------------------------------------------------------------------------------
  8661. // from options.c
  8662. static const neon_xml_elm_t options_elements[] =
  8663. {
  8664. { "DAV:", "href", ELEM_href, NEON_XML_CDATA },
  8665. { "DAV:", "options-response", ELEM_options_response, 0 },
  8666. { NULL }
  8667. };
  8668. typedef struct options_ctx_t
  8669. {
  8670. // WARNING: WANT_CDATA should stay the first element in the baton:
  8671. // neon_xml_collect_cdata() assumes the baton starts with a stringbuf.
  8672. stringbuf_t * want_cdata;
  8673. stringbuf_t * cdata;
  8674. apr_pool_t * pool;
  8675. } options_ctx_t;
  8676. static int
  8677. options_validate_element(
  8678. neon_xml_elmid parent,
  8679. neon_xml_elmid child)
  8680. {
  8681. switch (parent)
  8682. {
  8683. case ELEM_root:
  8684. if (child == ELEM_options_response)
  8685. return child;
  8686. else
  8687. return NEON_XML_INVALID;
  8688. case ELEM_options_response:
  8689. return NEON_XML_DECLINE; // not concerned with other response
  8690. default:
  8691. return NEON_XML_DECLINE;
  8692. }
  8693. // NOTREACHED
  8694. }
  8695. static error_t
  8696. options_start_element(
  8697. int * elem,
  8698. void * baton,
  8699. int parent,
  8700. const char * nspace,
  8701. const char * name,
  8702. const char ** atts)
  8703. {
  8704. options_ctx_t * oc = static_cast<options_ctx_t *>(baton);
  8705. const neon_xml_elm_t * elm = neon_lookup_xml_elem(options_elements, nspace, name);
  8706. *elem = elm ? options_validate_element(parent, elm->id) : NEON_XML_DECLINE;
  8707. if (*elem < 1) // Not a valid element
  8708. return WEBDAV_NO_ERROR;
  8709. if (elm->id == ELEM_href)
  8710. oc->want_cdata = oc->cdata;
  8711. else
  8712. oc->want_cdata = NULL;
  8713. return WEBDAV_NO_ERROR;
  8714. }
  8715. static error_t
  8716. options_end_element(
  8717. void * baton,
  8718. int state,
  8719. const char * nspace,
  8720. const char * name)
  8721. {
  8722. return WEBDAV_NO_ERROR;
  8723. }
  8724. static error_t
  8725. neon_exchange_capabilities(
  8726. neon_session_t * ras,
  8727. const char ** relocation_location,
  8728. apr_pool_t * pool)
  8729. {
  8730. neon_request_t * req = NULL;
  8731. error_t err = WEBDAV_NO_ERROR;
  8732. ne_xml_parser * parser = NULL;
  8733. options_ctx_t oc = { 0 };
  8734. int status_code = 0;
  8735. oc.pool = pool;
  8736. oc.cdata = stringbuf_create("", pool);
  8737. if (relocation_location)
  8738. *relocation_location = NULL;
  8739. WEBDAV_ERR(neon_request_create(&req, ras,
  8740. "OPTIONS", ras->url->data, pool));
  8741. // Use a symbolic name somewhere for this MIME type?
  8742. ne_add_request_header(req->ne_req, "Content-Type", "text/xml");
  8743. apr_hash_t * extra_headers = apr_hash_make(pool);
  8744. neon_add_depth_header(extra_headers, NEON_DEPTH_ZERO);
  8745. // Create a parser to read the normal response body
  8746. parser = neon_xml_parser_create(req, ne_accept_2xx, options_start_element,
  8747. neon_xml_collect_cdata,
  8748. options_end_element, &oc);
  8749. // Run the request and get the resulting status code.
  8750. if ((err = neon_request_dispatch(&status_code, req, extra_headers,
  8751. "<?xml version=\"1.0\" "
  8752. "encoding=\"utf-8\"?>"
  8753. "<D:options xmlns:D=\"DAV:\">"
  8754. "<D:resourcetype/>"
  8755. "</D:options>",
  8756. 200,
  8757. relocation_location ? 301 : 0,
  8758. false,
  8759. pool)) != WEBDAV_NO_ERROR)
  8760. goto cleanup;
  8761. if (req->code == 301)
  8762. {
  8763. *relocation_location = neon_request_get_location(req, pool);
  8764. goto cleanup;
  8765. }
  8766. // Was there an XML parse error somewhere?
  8767. err = neon_check_parse_error("OPTIONS", parser, ras->url->data);
  8768. if (err)
  8769. goto cleanup;
  8770. cleanup:
  8771. neon_request_destroy(req);
  8772. return err;
  8773. }
  8774. //------------------------------------------------------------------------------
  8775. // from props.c
  8776. typedef struct propfind_ctx_t
  8777. {
  8778. // WARNING: WANT_CDATA should stay the first element in the baton:
  8779. // neon_xml_collect_cdata() assumes the baton starts with a stringbuf.
  8780. stringbuf_t * cdata;
  8781. apr_hash_t * props; // const char *URL-PATH -> neon_resource_t
  8782. neon_resource_t * rsrc; // the current resource.
  8783. const char * encoding; // property encoding (or NULL)
  8784. int status; // status for the current <propstat> (or 0 if unknown).
  8785. apr_hash_t * propbuffer; // holds properties until their status is known.
  8786. neon_xml_elmid last_open_id; // the id of the last opened tag.
  8787. ne_xml_parser * parser; // xml parser handling the PROPSET request.
  8788. apr_pool_t * pool;
  8789. } propfind_ctx_t;
  8790. // When we begin a checkout, we fetch these from the "public" resources.
  8791. // We fetch the resourcetype to
  8792. // verify that we're accessing a collection.
  8793. static const ne_propname starting_props[] =
  8794. {
  8795. { "DAV:", "resourcetype" },
  8796. { "DAV:", "creationdate" },
  8797. { "DAV:", "getlastmodified" },
  8798. { "DAV:", "getcontentlength" },
  8799. { NULL }
  8800. };
  8801. static error_t
  8802. neon_get_starting_props(
  8803. neon_resource_t ** rsrc,
  8804. neon_session_t * sess,
  8805. const char * url,
  8806. bool check_errors,
  8807. apr_pool_t * pool)
  8808. {
  8809. WEBDAV_ERR(neon_get_props_resource(rsrc, sess, url,
  8810. starting_props, check_errors, pool));
  8811. // Cache some of the resource information.
  8812. if (!sess->webdav_root)
  8813. {
  8814. string_t * propval = NULL;
  8815. if (propval)
  8816. {
  8817. ne_uri uri = {0};
  8818. stringbuf_t * urlbuf = stringbuf_create(url, pool);
  8819. path_remove_components(urlbuf,
  8820. path_component_count(propval->data));
  8821. uri = sess->root;
  8822. uri.path = urlbuf->data;
  8823. sess->webdav_root = neon_uri_unparse(&uri, sess->pool);
  8824. }
  8825. }
  8826. return WEBDAV_NO_ERROR;
  8827. }
  8828. // Propfind Implementation
  8829. typedef struct elem_defn
  8830. {
  8831. neon_xml_elmid id;
  8832. const char * name;
  8833. int is_property; // is it a property, or part of some structure?
  8834. } elem_defn;
  8835. static const elem_defn elem_definitions[] =
  8836. {
  8837. // NOTE: Make sure that every item in here is also represented in
  8838. // propfind_elements[]
  8839. // DAV elements
  8840. { ELEM_multistatus, "DAV:multistatus", 0 },
  8841. { ELEM_response, "DAV:response", 0 },
  8842. { ELEM_href, "DAV:href", NEON_XML_CDATA },
  8843. { ELEM_propstat, "DAV:propstat", 0 },
  8844. { ELEM_prop, "DAV:prop", 0 },
  8845. { ELEM_status, "DAV:status", NEON_XML_CDATA },
  8846. { ELEM_collection, "DAV:collection", NEON_XML_CDATA },
  8847. { ELEM_resourcetype, "DAV:resourcetype", 0 },
  8848. { ELEM_get_content_length, NEON_PROP_GETCONTENTLENGTH, 1 },
  8849. { ELEM_creationdate, NEON_PROP_CREATIONDATE, 1 },
  8850. { 0 }
  8851. };
  8852. static const neon_xml_elm_t propfind_elements[] =
  8853. {
  8854. // NOTE: Make sure that every item in here is also represented in
  8855. // elem_definitions[]
  8856. // DAV elements
  8857. { "DAV:", "multistatus", ELEM_multistatus, 0 },
  8858. { "DAV:", "response", ELEM_response, 0 },
  8859. { "DAV:", "href", ELEM_href, NEON_XML_CDATA },
  8860. { "DAV:", "propstat", ELEM_propstat, 0 },
  8861. { "DAV:", "prop", ELEM_prop, 0 },
  8862. { "DAV:", "status", ELEM_status, NEON_XML_CDATA },
  8863. { "DAV:", "collection", ELEM_collection, NEON_XML_CDATA },
  8864. { "DAV:", "resourcetype", ELEM_resourcetype, 0 },
  8865. { "DAV:", "getcontentlength", ELEM_get_content_length, NEON_XML_CDATA },
  8866. { "DAV:", "getlastmodified", ELEM_get_last_modified, NEON_XML_CDATA },
  8867. {
  8868. "DAV:", "creator-displayname", ELEM_creator_displayname,
  8869. NEON_XML_CDATA
  8870. },
  8871. // Unknowns
  8872. { "", "", ELEM_unknown, NEON_XML_COLLECT },
  8873. { NULL }
  8874. };
  8875. // Look up an element definition ID. May return NULL if the elem is
  8876. // not recognized.
  8877. static const elem_defn *
  8878. defn_from_id(
  8879. neon_xml_elmid id)
  8880. {
  8881. for (const elem_defn * defn = elem_definitions; defn->name != NULL; ++defn)
  8882. {
  8883. if (id == defn->id)
  8884. return defn;
  8885. }
  8886. return NULL;
  8887. }
  8888. // Assign URL to RSRC. Use POOL for any allocations.
  8889. static error_t
  8890. assign_rsrc_url(
  8891. neon_resource_t * rsrc,
  8892. const char * url,
  8893. apr_pool_t * pool)
  8894. {
  8895. char * url_path = NULL;
  8896. apr_size_t len = 0;
  8897. ne_uri parsed_url = {0};
  8898. // Parse the PATH element out of the URL.
  8899. // NOTE: mod_dav does not (currently) use an absolute URL, but simply a
  8900. // server-relative path (i.e. this uri_parse is effectively a no-op).
  8901. if (ne_uri_parse(url, &parsed_url) != 0)
  8902. {
  8903. ne_uri_free(&parsed_url);
  8904. return error_createf(WEBDAV_ERR_DAV_MALFORMED_DATA, NULL,
  8905. "Unable to parse URL '%s'", url);
  8906. }
  8907. url_path = apr_pstrdup(pool, parsed_url.path);
  8908. ne_uri_free(&parsed_url);
  8909. // Clean up trailing slashes from the URL.
  8910. len = strlen(url_path);
  8911. if ((len > 1) && (url_path[len - 1] == '/'))
  8912. url_path[len - 1] = '\0';
  8913. rsrc->url = url_path;
  8914. return WEBDAV_NO_ERROR;
  8915. }
  8916. // Determine whether we're receiving the expected XML response.
  8917. // Return CHILD when interested in receiving the child's contents
  8918. // or one of NEON_XML_INVALID and NEON_XML_DECLINE
  8919. // when respectively this is the incorrect response or
  8920. // the element (and its children) are uninteresting
  8921. static int
  8922. props_validate_element(
  8923. neon_xml_elmid parent,
  8924. neon_xml_elmid child)
  8925. {
  8926. switch (parent)
  8927. {
  8928. case ELEM_root:
  8929. if (child == ELEM_multistatus)
  8930. return child;
  8931. else
  8932. return NEON_XML_INVALID;
  8933. case ELEM_multistatus:
  8934. if (child == ELEM_response)
  8935. return child;
  8936. else
  8937. return NEON_XML_DECLINE;
  8938. case ELEM_response:
  8939. if ((child == ELEM_href) || (child == ELEM_propstat))
  8940. return child;
  8941. else
  8942. return NEON_XML_DECLINE;
  8943. case ELEM_propstat:
  8944. if ((child == ELEM_prop) || (child == ELEM_status))
  8945. return child;
  8946. else
  8947. return NEON_XML_DECLINE;
  8948. case ELEM_prop:
  8949. return child; // handle all children of <prop>
  8950. case ELEM_resourcetype:
  8951. if (child == ELEM_collection)
  8952. return child;
  8953. else
  8954. return NEON_XML_DECLINE; // not concerned with other types (now)
  8955. default:
  8956. return NEON_XML_DECLINE;
  8957. }
  8958. // NOTREACHED
  8959. }
  8960. static error_t
  8961. props_start_element(
  8962. int * elem,
  8963. void * baton,
  8964. int parent,
  8965. const char * nspace,
  8966. const char * name,
  8967. const char ** atts)
  8968. {
  8969. propfind_ctx_t * pc = static_cast<propfind_ctx_t *>(baton);
  8970. const neon_xml_elm_t * elm = neon_lookup_xml_elem(propfind_elements, nspace, name);
  8971. *elem = elm ? props_validate_element(parent, elm->id) : NEON_XML_DECLINE;
  8972. if (*elem < 1) // not a valid element
  8973. return WEBDAV_NO_ERROR;
  8974. stringbuf_setempty(pc->cdata);
  8975. *elem = elm ? elm->id : ELEM_unknown;
  8976. switch (*elem)
  8977. {
  8978. case ELEM_response:
  8979. if (pc->rsrc)
  8980. return error_create(WEBDAV_ERR_XML_MALFORMED, NULL, NULL);
  8981. // Create a new resource.
  8982. pc->rsrc = static_cast<neon_resource_t *>(apr_pcalloc(pc->pool, sizeof(*(pc->rsrc))));
  8983. pc->rsrc->pool = pc->pool;
  8984. pc->rsrc->propset = apr_hash_make(pc->pool);
  8985. pc->status = 0;
  8986. break;
  8987. case ELEM_propstat:
  8988. pc->status = 0;
  8989. break;
  8990. case ELEM_href:
  8991. pc->rsrc->href_parent = pc->last_open_id;
  8992. break;
  8993. case ELEM_collection:
  8994. pc->rsrc->is_collection = 1;
  8995. break;
  8996. case ELEM_unknown:
  8997. // these are our user-visible properties, presumably.
  8998. if (pc->encoding)
  8999. pc->encoding = apr_pstrdup(pc->pool, pc->encoding);
  9000. break;
  9001. default:
  9002. // nothing to do for these
  9003. break;
  9004. }
  9005. // Remember the last tag we opened.
  9006. pc->last_open_id = *elem;
  9007. return WEBDAV_NO_ERROR;
  9008. }
  9009. static error_t
  9010. props_end_element(
  9011. void * baton,
  9012. int state,
  9013. const char * nspace,
  9014. const char * name)
  9015. {
  9016. propfind_ctx_t * pc = static_cast<propfind_ctx_t *>(baton);
  9017. neon_resource_t * rsrc = pc->rsrc;
  9018. const string_t * value = NULL;
  9019. const elem_defn * parent_defn = NULL;
  9020. const elem_defn * defn = NULL;
  9021. ne_status status = {0};
  9022. const char * cdata = pc->cdata->data;
  9023. switch (state)
  9024. {
  9025. case ELEM_response:
  9026. // Verify that we've received a URL for this resource.
  9027. if (!pc->rsrc->url)
  9028. return error_create(WEBDAV_ERR_XML_MALFORMED, NULL, NULL);
  9029. // Store the resource in the top-level hash table.
  9030. apr_hash_set(pc->props, pc->rsrc->url, APR_HASH_KEY_STRING, pc->rsrc);
  9031. pc->rsrc = NULL;
  9032. return WEBDAV_NO_ERROR;
  9033. case ELEM_propstat:
  9034. // We're at the end of a set of properties. Do the right thing status-wise.
  9035. if (pc->status)
  9036. {
  9037. for (apr_hash_index_t * hi = apr_hash_first(pc->pool, pc->propbuffer); hi;
  9038. hi = apr_hash_next(hi))
  9039. {
  9040. const void * key;
  9041. apr_ssize_t klen;
  9042. void * val;
  9043. apr_hash_this(hi, &key, &klen, &val);
  9044. if (pc->status == 200)
  9045. apr_hash_set(rsrc->propset, key, klen, val);
  9046. apr_hash_set(pc->propbuffer, key, klen, NULL);
  9047. }
  9048. }
  9049. else if (!pc->status)
  9050. {
  9051. // No status at all? Bogosity.
  9052. return error_create(WEBDAV_ERR_XML_MALFORMED, NULL, NULL);
  9053. }
  9054. return WEBDAV_NO_ERROR;
  9055. case ELEM_status:
  9056. // Parse the <status> tag's CDATA for a status code.
  9057. if (ne_parse_statusline(cdata, &status))
  9058. return error_create(WEBDAV_ERR_XML_MALFORMED, NULL, NULL);
  9059. ne_free(status.reason_phrase);
  9060. pc->status = status.code;
  9061. return WEBDAV_NO_ERROR;
  9062. case ELEM_href:
  9063. // Special handling for <href> that belongs to the <response> tag.
  9064. if (rsrc->href_parent == ELEM_response)
  9065. return assign_rsrc_url(pc->rsrc,
  9066. urlpath_canonicalize(cdata, pc->pool),
  9067. pc->pool);
  9068. // Use the parent element's name, not the href.
  9069. parent_defn = defn_from_id(rsrc->href_parent);
  9070. // No known parent? Get outta here.
  9071. if (!parent_defn)
  9072. return WEBDAV_NO_ERROR;
  9073. // All other href's we'll treat as property values.
  9074. name = parent_defn->name;
  9075. value = string_create(urlpath_canonicalize(cdata, pc->pool),
  9076. pc->pool);
  9077. break;
  9078. default:
  9079. if (state == ELEM_unknown)
  9080. {
  9081. name = apr_pstrcat(pc->pool, nspace, name, (char *)NULL);
  9082. }
  9083. else
  9084. {
  9085. defn = defn_from_id(state);
  9086. if (!(defn && defn->is_property))
  9087. return WEBDAV_NO_ERROR;
  9088. name = defn->name;
  9089. }
  9090. // Check for encoding attribute.
  9091. if (pc->encoding == NULL)
  9092. {
  9093. // Handle the property value by converting it to string.
  9094. value = string_create(cdata, pc->pool);
  9095. break;
  9096. }
  9097. // Check for known encoding type
  9098. if (strcmp(pc->encoding, "base64") != 0)
  9099. return error_create(WEBDAV_ERR_XML_MALFORMED, NULL, NULL);
  9100. pc->encoding = NULL; // Reset encoding for future attribute(s).
  9101. }
  9102. // Handling resource properties from here out.
  9103. // Add properties to the temporary propbuffer. At the end of the
  9104. // <propstat>, we'll either dump the props as invalid or move them
  9105. // into the resource's property hash.
  9106. apr_hash_set(pc->propbuffer, name, APR_HASH_KEY_STRING, value);
  9107. return WEBDAV_NO_ERROR;
  9108. }
  9109. static void
  9110. props_set_parser(
  9111. ne_xml_parser * parser,
  9112. void * baton)
  9113. {
  9114. propfind_ctx_t * pc = static_cast<propfind_ctx_t *>(baton);
  9115. pc->parser = parser;
  9116. }
  9117. static error_t
  9118. neon_get_props(
  9119. apr_hash_t ** results,
  9120. neon_session_t * sess,
  9121. const char * url,
  9122. int depth,
  9123. const ne_propname * which_props,
  9124. bool check_errors,
  9125. apr_pool_t * pool)
  9126. {
  9127. apr_hash_t * extra_headers = apr_hash_make(pool);
  9128. neon_add_depth_header(extra_headers, depth);
  9129. // It's easier to roll our own PROPFIND here than use neon's current interfaces.
  9130. // The start of the request body is fixed:
  9131. stringbuf_t * body = stringbuf_create("<?xml version=\"1.0\" encoding=\"utf-8\"?>" DEBUG_CR
  9132. "<propfind xmlns=\"DAV:\">" DEBUG_CR, pool);
  9133. // Are we asking for specific propert(y/ies), or just all of them?
  9134. if (which_props)
  9135. {
  9136. apr_pool_t * iterpool = webdav_pool_create(pool);
  9137. stringbuf_appendcstr(body, "<prop>" DEBUG_CR);
  9138. for (int n = 0; which_props[n].name != NULL; n++)
  9139. {
  9140. webdav_pool_clear(iterpool);
  9141. stringbuf_appendcstr(body, apr_pstrcat(iterpool, "<", which_props[n].name,
  9142. " xmlns=\"", which_props[n].nspace, "\"/>" DEBUG_CR,
  9143. (char *)NULL));
  9144. }
  9145. stringbuf_appendcstr(body, "</prop></propfind>" DEBUG_CR);
  9146. webdav_pool_destroy(iterpool);
  9147. }
  9148. else
  9149. {
  9150. stringbuf_appendcstr(body, "<allprop/></propfind>" DEBUG_CR);
  9151. }
  9152. // Initialize our baton.
  9153. propfind_ctx_t pc;
  9154. memset(&pc, 0, sizeof(pc));
  9155. pc.pool = pool;
  9156. pc.propbuffer = apr_hash_make(pool);
  9157. pc.props = apr_hash_make(pool);
  9158. pc.cdata = stringbuf_create("", pool);
  9159. // Create and dispatch the request!
  9160. WEBDAV_ERR(neon_parsed_request(sess, "PROPFIND", url,
  9161. body->data, 0,
  9162. props_set_parser,
  9163. props_start_element,
  9164. neon_xml_collect_cdata,
  9165. props_end_element,
  9166. &pc, extra_headers, NULL,
  9167. check_errors,
  9168. pool));
  9169. *results = pc.props;
  9170. return WEBDAV_NO_ERROR;
  9171. }
  9172. static error_t
  9173. neon_get_props_resource(
  9174. neon_resource_t ** rsrc,
  9175. neon_session_t * sess,
  9176. const char * url,
  9177. const ne_propname * which_props,
  9178. bool check_errors,
  9179. apr_pool_t * pool)
  9180. {
  9181. apr_hash_t * props = NULL;
  9182. char * url_path = apr_pstrdup(pool, url);
  9183. apr_size_t len = strlen(url);
  9184. // Clean up any trailing slashes.
  9185. if ((len > 1) && (url[len - 1] == '/'))
  9186. url_path[len - 1] = '\0';
  9187. WEBDAV_ERR(neon_get_props(&props, sess, url_path, NEON_DEPTH_ZERO,
  9188. which_props, check_errors, pool));
  9189. // HACK. We need to have the client canonicalize paths, get rid
  9190. // of double slashes and such. This check is just a check against
  9191. // non-SVN servers; in the long run we want to re-enable this.
  9192. {
  9193. // pick out the first response: the URL requested will not match
  9194. // the response href.
  9195. apr_hash_index_t * hi = apr_hash_first(pool, props);
  9196. if (hi)
  9197. {
  9198. void * ent;
  9199. apr_hash_this(hi, NULL, NULL, &ent);
  9200. *rsrc = static_cast<neon_resource_t *>(ent);
  9201. }
  9202. else
  9203. *rsrc = NULL;
  9204. }
  9205. if (*rsrc == NULL)
  9206. {
  9207. // hmmm, should have been in there...
  9208. return error_createf(APR_EGENERAL, NULL,
  9209. "Failed to find label '%s' for URL '%s'",
  9210. "NULL", url_path);
  9211. }
  9212. return WEBDAV_NO_ERROR;
  9213. }
  9214. //------------------------------------------------------------------------------
  9215. static error_t
  9216. client_list2(
  9217. session_t * session,
  9218. const char * path_or_url,
  9219. depth_t depth,
  9220. apr_uint32_t dirent_fields,
  9221. client_list_func_t list_func,
  9222. void * baton,
  9223. apr_pool_t * pool)
  9224. {
  9225. dirent_t * dirent = NULL;
  9226. const char * url = NULL;
  9227. const char * webdav_root = NULL;
  9228. const char * fs_path = NULL;
  9229. error_t err = 0;
  9230. assert(session);
  9231. // We use the kind field to determine if we should recurse, so we
  9232. // always need it.
  9233. dirent_fields |= WEBDAV_DIRENT_KIND;
  9234. WEBDAV_ERR(init_session_from_path(session,
  9235. &url, path_or_url,
  9236. pool));
  9237. WEBDAV_ERR(get_webdav_resource_root2(session, &webdav_root, pool));
  9238. WEBDAV_ERR(client_path_relative_to_root(&fs_path,
  9239. url,
  9240. webdav_root, TRUE, session,
  9241. pool, pool));
  9242. err = stat(session, "", &dirent, pool);
  9243. if (err)
  9244. return error_trace(err);
  9245. if (!dirent)
  9246. return error_createf(WEBDAV_ERR_FS_NOT_FOUND, NULL,
  9247. "URL '%s' non-existent",
  9248. url);
  9249. // Report the dirent for the target.
  9250. WEBDAV_ERR(list_func(baton, "", dirent, fs_path, pool));
  9251. if (dirent->kind == node_dir && (depth == depth_files ||
  9252. depth == depth_immediates ||
  9253. depth == depth_infinity))
  9254. {
  9255. WEBDAV_ERR(get_dir_contents(dirent_fields, "",
  9256. session,
  9257. fs_path, depth,
  9258. list_func, baton, pool));
  9259. }
  9260. return WEBDAV_NO_ERROR;
  9261. }
  9262. static error_t
  9263. client_get_file(
  9264. session_t * session,
  9265. const char * remote_path,
  9266. apr_os_file_t * thefile,
  9267. apr_pool_t * pool)
  9268. {
  9269. const char * remote_url = NULL;
  9270. WEBDAV_ERR(init_session_from_path(session,
  9271. &remote_url, path_uri_encode(remote_path, pool),
  9272. pool));
  9273. stream_t * fstream = NULL;
  9274. WEBDAV_ERR(stream_open_writable(&fstream, thefile,
  9275. pool, pool));
  9276. const char * src_rel = NULL;
  9277. WEBDAV_ERR(get_path_relative_to_session(session, &src_rel,
  9278. remote_url,
  9279. pool));
  9280. WEBDAV_ERR(get_file(session, src_rel, fstream, NULL, pool));
  9281. WEBDAV_ERR(stream_close(fstream));
  9282. return WEBDAV_NO_ERROR;
  9283. }
  9284. static error_t
  9285. client_put_file(
  9286. session_t * session,
  9287. const char * remote_path,
  9288. const char * local_path,
  9289. apr_pool_t * pool)
  9290. {
  9291. neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
  9292. assert(ras);
  9293. error_t err = 0;
  9294. int code = 0;
  9295. apr_hash_t * extra_headers = NULL; // apr_hash_make(pool);
  9296. neon_request_t * request = NULL;
  9297. const char * put_target = path_uri_encode(remote_path, pool);
  9298. apr_file_t * body_file = NULL;
  9299. WEBDAV_ERR(io_file_open(&body_file, local_path, APR_READ | APR_BUFFERED | APR_BINARY,
  9300. APR_OS_DEFAULT, pool));
  9301. // create/prep the request
  9302. WEBDAV_ERR(neon_request_create(&request, ras, "PUT",
  9303. put_target, pool));
  9304. // Give the file to neon. The provider will rewind the file.
  9305. err = neon_set_neon_body_provider(request, body_file);
  9306. if (err)
  9307. goto cleanup;
  9308. // run the request and get the resulting status code (and error_t)
  9309. err = neon_request_dispatch(&code, request, extra_headers, NULL,
  9310. 201 /* Created */,
  9311. 204 /* No Content */,
  9312. false,
  9313. pool);
  9314. if (err && (err == WEBDAV_ERR_DAV_REQUEST_FAILED))
  9315. {
  9316. err = error_createf(WEBDAV_ERR_CANNOT_PUT_FILE, NULL,
  9317. "Cannot create '%s'"
  9318. " (Status %d on PUT Request)",
  9319. put_target, code);
  9320. }
  9321. cleanup:
  9322. neon_request_destroy(request);
  9323. WEBDAV_ERR(err);
  9324. return WEBDAV_NO_ERROR;
  9325. }
  9326. static error_t
  9327. client_move_file_or_directory(
  9328. session_t * session,
  9329. const char * remote_path_from,
  9330. const char * remote_path_to,
  9331. void * baton,
  9332. apr_pool_t * pool)
  9333. {
  9334. neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
  9335. assert(ras);
  9336. error_t err = 0;
  9337. const char * target_from = path_uri_encode(remote_path_from, pool);
  9338. const char * target_to = path_uri_encode(remote_path_to, pool);
  9339. int code = 0;
  9340. apr_hash_t * extra_headers = apr_hash_make(pool);
  9341. apr_hash_set(extra_headers, "Destination", APR_HASH_KEY_STRING, target_to);
  9342. neon_add_depth_header(extra_headers, NEON_DEPTH_INFINITE);
  9343. err = neon_simple_request(&code, ras, "MOVE", target_from,
  9344. extra_headers, NULL,
  9345. 201 /* Created */,
  9346. 204 /* No Content */,
  9347. pool);
  9348. if (err && (err == WEBDAV_ERR_DAV_REQUEST_FAILED))
  9349. {
  9350. err = error_createf(WEBDAV_ERR_CANNOT_MOVE, NULL,
  9351. "Cannot move '%s' to '%s'"
  9352. " (Status %d on MOVE Request)",
  9353. target_from, target_to, code);
  9354. }
  9355. return err;
  9356. }
  9357. static error_t
  9358. client_delete_file(
  9359. session_t * session,
  9360. const char * remote_path,
  9361. void * baton,
  9362. apr_pool_t * pool)
  9363. {
  9364. neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
  9365. assert(ras);
  9366. error_t err = 0;
  9367. const char * target = path_uri_encode(remote_path, pool);
  9368. int code = 0;
  9369. err = neon_simple_request(&code, ras, "DELETE", target,
  9370. NULL, NULL,
  9371. 200,
  9372. 204, // No Content
  9373. pool);
  9374. if (err && (err == WEBDAV_ERR_DAV_REQUEST_FAILED))
  9375. {
  9376. err = error_createf(WEBDAV_ERR_CANNOT_DELETE_FILE, NULL,
  9377. "Cannot delete '%s'"
  9378. " (Status %d on DELETE Request)",
  9379. target, code);
  9380. }
  9381. return err;
  9382. }
  9383. static error_t
  9384. client_check_path(
  9385. session_t * session,
  9386. const char * remote_path,
  9387. node_kind_t * kind,
  9388. apr_pool_t * pool)
  9389. {
  9390. neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
  9391. assert(ras);
  9392. *kind = node_none;
  9393. error_t err = 0;
  9394. char * target = apr_pstrdup(pool, path_uri_encode(remote_path, pool));
  9395. const char * rel_path = NULL;
  9396. apr_size_t len = strlen(target);
  9397. if ((len > 1) && ((target)[len - 1] == '/'))
  9398. {
  9399. (target)[len - 1] = '\0';
  9400. }
  9401. if (*target == '/')
  9402. {
  9403. // check if root has trailing slash
  9404. apr_size_t len = strlen(ras->webdav_root);
  9405. if ((len > 1) && ((ras->webdav_root)[len - 1] == '/'))
  9406. {
  9407. target++;
  9408. }
  9409. const char * abs_path = apr_pstrcat(pool, ras->webdav_root, target, NULL);
  9410. err = get_path_relative_to_root(
  9411. session,
  9412. &rel_path,
  9413. abs_path,
  9414. pool);
  9415. WEBDAV_ERR(err);
  9416. }
  9417. else
  9418. {
  9419. rel_path = target;
  9420. }
  9421. err = check_path(
  9422. session,
  9423. rel_path,
  9424. kind,
  9425. pool
  9426. );
  9427. return err;
  9428. }
  9429. static error_t
  9430. client_make_directory(
  9431. session_t * session,
  9432. const char * remote_path,
  9433. void * baton,
  9434. apr_pool_t * pool)
  9435. {
  9436. neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
  9437. assert(ras);
  9438. error_t err = 0;
  9439. const char * target = path_uri_encode(remote_path, pool);
  9440. int code = 0;
  9441. err = neon_simple_request(
  9442. &code, ras, "MKCOL", target,
  9443. NULL, NULL,
  9444. 201, 207, pool);
  9445. if (err && (err == WEBDAV_ERR_DAV_REQUEST_FAILED))
  9446. {
  9447. err = error_createf(WEBDAV_ERR_CANNOT_MKCOL, NULL,
  9448. "Cannot create directory '%s'"
  9449. " (Status %d on MKCOL Request)",
  9450. target, code);
  9451. }
  9452. return err;
  9453. }
  9454. static error_t
  9455. client_send_propfind_request(
  9456. session_t * session,
  9457. const char * remote_path,
  9458. int * response_code,
  9459. apr_pool_t * pool)
  9460. {
  9461. neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
  9462. assert(ras);
  9463. error_t err = 0;
  9464. int code = 0;
  9465. apr_hash_t * props = NULL;
  9466. const char * target = path_uri_encode(remote_path, pool);
  9467. char * url_path = apr_pstrdup(pool, target);
  9468. WEBDAV_ERR(neon_get_props(&props, ras, url_path, NEON_DEPTH_ZERO,
  9469. starting_props,
  9470. false,
  9471. pool));
  9472. if (err && (err == WEBDAV_ERR_DAV_REQUEST_FAILED))
  9473. {
  9474. err = error_createf(WEBDAV_ERR_CANNOT_PROPFIND, NULL,
  9475. "Cannot execute PROPFIND on '%s'"
  9476. " (Status %d on PROPFIND Request)",
  9477. target, code);
  9478. }
  9479. if (response_code)
  9480. *response_code = code;
  9481. return err;
  9482. }
  9483. //------------------------------------------------------------------------------
  9484. // from session.c
  9485. typedef struct neonprogress_baton_t
  9486. {
  9487. neon_session_t * ras;
  9488. apr_off_t last_progress;
  9489. apr_time_t last_progress_time;
  9490. apr_pool_t * pool;
  9491. } neonprogress_baton_t;
  9492. // Callback invoked to enter PKCS#11 PIN code.
  9493. static int
  9494. client_ssl_pkcs11_pin_entry(
  9495. void * userdata,
  9496. int attempt,
  9497. const char * slot_descr,
  9498. const char * token_label,
  9499. unsigned int flags,
  9500. char * pin)
  9501. {
  9502. neon_session_t * ras = static_cast<neon_session_t *>(userdata);
  9503. void * creds = NULL;
  9504. auth_cred_ssl_client_cert_pw_t * pw_creds = NULL;
  9505. // Always prevent PIN caching.
  9506. auth_baton_set_parameter(ras->callbacks->auth_baton,
  9507. AUTH_PARAM_NO_AUTH_CACHE, "");
  9508. error_t err = 0;
  9509. if (attempt == 0)
  9510. {
  9511. const char * realmstring;
  9512. realmstring = apr_psprintf(ras->pool,
  9513. "PIN for token \"%s\" in slot \"%s\"",
  9514. token_label, slot_descr);
  9515. err = auth_first_credentials(&creds,
  9516. &(ras->auth_iterstate),
  9517. AUTH_CRED_SSL_CLIENT_CERT_PW,
  9518. realmstring,
  9519. ras->callbacks->auth_baton,
  9520. ras->pool);
  9521. }
  9522. else
  9523. {
  9524. err = auth_next_credentials(&creds, ras->auth_iterstate, ras->pool);
  9525. }
  9526. if (err || !creds)
  9527. {
  9528. error_clear(&err);
  9529. return -1;
  9530. }
  9531. pw_creds = static_cast<auth_cred_ssl_client_cert_pw_t *>(creds);
  9532. strncpy(pin, pw_creds->password, NE_SSL_P11PINLEN);
  9533. return 0;
  9534. }
  9535. static bool
  9536. client_ssl_decrypt_cert(
  9537. neon_session_t * ras,
  9538. const char * cert_file,
  9539. ne_ssl_client_cert * clicert)
  9540. {
  9541. auth_iterstate_t * state = NULL;
  9542. error_t error = 0;
  9543. apr_pool_t * pool = NULL;
  9544. bool ok = false;
  9545. void * creds = NULL;
  9546. int try_count = 0;
  9547. apr_pool_create(&pool, ras->pool);
  9548. for (try_count = 0; TRUE; ++try_count)
  9549. {
  9550. if (try_count == 0)
  9551. {
  9552. error = auth_first_credentials(&creds, &state,
  9553. AUTH_CRED_SSL_CLIENT_CERT_PW,
  9554. cert_file,
  9555. ras->callbacks->auth_baton,
  9556. pool);
  9557. }
  9558. else
  9559. {
  9560. error = auth_next_credentials(&creds, state, pool);
  9561. }
  9562. if (error || !creds)
  9563. {
  9564. // Failure or too many attempts
  9565. error_clear(&error);
  9566. break;
  9567. }
  9568. else
  9569. {
  9570. auth_cred_ssl_client_cert_pw_t * pw_creds = static_cast<auth_cred_ssl_client_cert_pw_t *>(creds);
  9571. if (ne_ssl_clicert_decrypt(clicert, pw_creds->password) == 0)
  9572. {
  9573. error = auth_save_credentials(state, pool);
  9574. if (error)
  9575. error_clear(&error);
  9576. // Success
  9577. ok = TRUE;
  9578. break;
  9579. }
  9580. }
  9581. }
  9582. webdav_pool_destroy(pool);
  9583. return ok;
  9584. }
  9585. static void
  9586. client_ssl_callback(
  9587. void * userdata,
  9588. ne_session * sess,
  9589. const ne_ssl_dname * const * dnames,
  9590. int dncount)
  9591. {
  9592. neon_session_t * ras = static_cast<neon_session_t *>(userdata);
  9593. ne_ssl_client_cert * clicert = NULL;
  9594. void * creds = NULL;
  9595. auth_iterstate_t * state = NULL;
  9596. const char * realmstring = NULL;
  9597. apr_pool_t * pool = NULL;
  9598. error_t error = 0;
  9599. int try_count = 0;
  9600. apr_pool_create(&pool, ras->pool);
  9601. realmstring = apr_psprintf(pool, "%s://%s:%d", ras->root.scheme,
  9602. ras->root.host, ras->root.port);
  9603. for (try_count = 0; TRUE; ++try_count)
  9604. {
  9605. if (try_count == 0)
  9606. {
  9607. error = auth_first_credentials(&creds, &state,
  9608. AUTH_CRED_SSL_CLIENT_CERT,
  9609. realmstring,
  9610. ras->callbacks->auth_baton,
  9611. pool);
  9612. }
  9613. else
  9614. {
  9615. error = auth_next_credentials(&creds, state, pool);
  9616. }
  9617. if (error || !creds)
  9618. {
  9619. // Failure or too many attempts
  9620. error_clear(&error);
  9621. break;
  9622. }
  9623. else
  9624. {
  9625. auth_cred_ssl_client_cert_t * client_creds = static_cast<auth_cred_ssl_client_cert_t *>(creds);
  9626. clicert = ne_ssl_clicert_read(client_creds->cert_file);
  9627. if (clicert)
  9628. {
  9629. if (!ne_ssl_clicert_encrypted(clicert) ||
  9630. client_ssl_decrypt_cert(ras, client_creds->cert_file,
  9631. clicert))
  9632. {
  9633. ne_ssl_set_clicert(sess, clicert);
  9634. }
  9635. ne_ssl_clicert_free(clicert);
  9636. clicert = NULL;
  9637. break;
  9638. }
  9639. }
  9640. }
  9641. webdav_pool_destroy(pool);
  9642. }
  9643. static const apr_uint32_t neon_failure_map[][2] =
  9644. {
  9645. { NE_SSL_NOTYETVALID, WEBDAV_AUTH_SSL_NOTYETVALID },
  9646. { NE_SSL_EXPIRED, WEBDAV_AUTH_SSL_EXPIRED },
  9647. { NE_SSL_IDMISMATCH, WEBDAV_AUTH_SSL_CNMISMATCH },
  9648. { NE_SSL_UNTRUSTED, WEBDAV_AUTH_SSL_UNKNOWNCA }
  9649. };
  9650. // Convert neon's SSL failure mask to our own failure mask.
  9651. static apr_uint32_t
  9652. convert_neon_failures(
  9653. int neon_failures)
  9654. {
  9655. apr_uint32_t failures = 0;
  9656. for (apr_size_t i = 0; i < sizeof(neon_failure_map) / (2 * sizeof(int)); ++i)
  9657. {
  9658. if (neon_failures & neon_failure_map[i][0])
  9659. {
  9660. failures |= neon_failure_map[i][1];
  9661. neon_failures &= ~neon_failure_map[i][0];
  9662. }
  9663. }
  9664. // Map any remaining neon failure bits to our OTHER bit.
  9665. if (neon_failures)
  9666. {
  9667. failures |= WEBDAV_AUTH_SSL_OTHER;
  9668. }
  9669. return failures;
  9670. }
  9671. // A neon-session callback to validate the SSL certificate when the CA
  9672. // is unknown (e.g. a self-signed cert), or there are other SSL
  9673. // certificate problems.
  9674. static int
  9675. server_ssl_callback(
  9676. void * userdata,
  9677. int failures,
  9678. const ne_ssl_certificate * cert)
  9679. {
  9680. neon_session_t * ras = static_cast<neon_session_t *>(userdata);
  9681. auth_cred_ssl_server_trust_t * server_creds = NULL;
  9682. void * creds = NULL;
  9683. auth_iterstate_t * state = NULL;
  9684. apr_pool_t * pool = NULL;
  9685. error_t error = 0;
  9686. char * ascii_cert = ne_ssl_cert_export(cert);
  9687. char * issuer_dname = ne_ssl_readable_dname(ne_ssl_cert_issuer(cert));
  9688. auth_ssl_server_cert_info_t cert_info = {0};
  9689. char fingerprint[NE_SSL_DIGESTLEN] = {0};
  9690. char valid_from[NE_SSL_VDATELEN] = {0}, valid_until[NE_SSL_VDATELEN] = {0};
  9691. apr_uint32_t * webdav_failures = static_cast<apr_uint32_t *>(apr_pcalloc(ras->pool, sizeof(*webdav_failures)));
  9692. // Construct the realmstring, e.g. https://svn.collab.net:80
  9693. const char * realmstring = apr_pstrdup(ras->pool, Format("%s://%s:%d", ras->root.scheme,
  9694. ras->root.host, ras->root.port).c_str());
  9695. *webdav_failures = convert_neon_failures(failures);
  9696. auth_baton_set_parameter(ras->callbacks->auth_baton,
  9697. AUTH_PARAM_SSL_SERVER_FAILURES,
  9698. webdav_failures);
  9699. // Extract the info from the certificate
  9700. cert_info.hostname = ne_ssl_cert_identity(cert);
  9701. if (ne_ssl_cert_digest(cert, fingerprint) != 0)
  9702. {
  9703. strcpy(fingerprint, "<unknown>");
  9704. }
  9705. cert_info.fingerprint = fingerprint;
  9706. ne_ssl_cert_validity(cert, valid_from, valid_until);
  9707. cert_info.valid_from = valid_from;
  9708. cert_info.valid_until = valid_until;
  9709. cert_info.issuer_dname = issuer_dname;
  9710. cert_info.ascii_cert = ascii_cert;
  9711. auth_baton_set_parameter(ras->callbacks->auth_baton,
  9712. AUTH_PARAM_SSL_SERVER_CERT_INFO,
  9713. &cert_info);
  9714. apr_pool_create(&pool, ras->pool);
  9715. error = auth_first_credentials(&creds, &state,
  9716. AUTH_CRED_SSL_SERVER_TRUST,
  9717. realmstring,
  9718. ras->callbacks->auth_baton,
  9719. pool);
  9720. if (error || !creds)
  9721. {
  9722. error_clear(&error);
  9723. }
  9724. else
  9725. {
  9726. server_creds = static_cast<auth_cred_ssl_server_trust_t *>(creds);
  9727. error = auth_save_credentials(state, pool);
  9728. if (error)
  9729. {
  9730. // It would be nice to show the error to the user somehow...
  9731. error_clear(&error);
  9732. }
  9733. }
  9734. free(issuer_dname);
  9735. free(ascii_cert);
  9736. auth_baton_set_parameter(ras->callbacks->auth_baton,
  9737. AUTH_PARAM_SSL_SERVER_CERT_INFO, NULL);
  9738. webdav_pool_destroy(pool);
  9739. return !server_creds;
  9740. }
  9741. // An `ne_request_auth' callback, see ne_auth.h. USERDATA is a struct proxy_auth_baton_t *
  9742. // If ATTEMPT < 10, copy USERDATA->username and USERDATA->password
  9743. // into USERNAME and PASSWORD respectively (but do not copy more than
  9744. // NE_ABUFSIZ bytes of either), and return zero to indicate to Neon
  9745. // that authentication should be attempted.
  9746. // If ATTEMPT >= 10, copy nothing into USERNAME and PASSWORD and
  9747. // return 1, to cancel further authentication attempts.
  9748. // Ignore REALM.
  9749. static int
  9750. proxy_auth(
  9751. void * userdata,
  9752. const char * realm,
  9753. int attempt,
  9754. char * username,
  9755. char * password)
  9756. {
  9757. proxy_auth_baton_t * pab = static_cast<proxy_auth_baton_t *>(userdata);
  9758. if (attempt >= 10)
  9759. return 1;
  9760. // Else.
  9761. strncpy(username, pab->username, NE_ABUFSIZ);
  9762. strncpy(password, pab->password, NE_ABUFSIZ);
  9763. return 0;
  9764. }
  9765. // A neon-session callback to 'pull' authentication data when
  9766. // challenged. In turn, this routine 'pulls' the data from the client
  9767. // callbacks if needed.
  9768. static int
  9769. request_auth(
  9770. void * userdata,
  9771. const char * realm,
  9772. int attempt,
  9773. char * username,
  9774. char * password)
  9775. {
  9776. error_t err = 0;
  9777. neon_session_t * ras = static_cast<neon_session_t *>(userdata);
  9778. void * creds = NULL;
  9779. auth_cred_simple_t * simple_creds = NULL;
  9780. // Start by marking the current credentials invalid.
  9781. ras->auth_used = false;
  9782. // No auth_baton? Give up.
  9783. if (!ras->callbacks->auth_baton)
  9784. return -1;
  9785. // Neon automatically tries some auth protocols and bumps the attempt
  9786. // count without using our callbacks, so we can't depend
  9787. // on attempt == 0 the first time we are called -- we need to check
  9788. // if the auth state has been initted as well.
  9789. if (attempt == 0 || ras->auth_iterstate == NULL)
  9790. {
  9791. const char * realmstring = apr_psprintf(ras->pool, "<%s://%s:%d> %s",
  9792. ras->root.scheme, ras->root.host,
  9793. ras->root.port, realm);
  9794. err = auth_first_credentials(&creds,
  9795. &(ras->auth_iterstate),
  9796. AUTH_CRED_SIMPLE,
  9797. realmstring,
  9798. ras->callbacks->auth_baton,
  9799. ras->pool);
  9800. }
  9801. else // attempt > 0
  9802. // TODO: if the http realm changed this time around, we
  9803. // should be calling first_creds(), not next_creds().
  9804. err = auth_next_credentials(&creds,
  9805. ras->auth_iterstate,
  9806. ras->pool);
  9807. if (err || !creds)
  9808. {
  9809. error_clear(&err);
  9810. return -1;
  9811. }
  9812. simple_creds = static_cast<auth_cred_simple_t *>(creds);
  9813. // Make neon_request_dispatch store the credentials after it
  9814. // sees a successful response
  9815. ras->auth_used = true;
  9816. // silently truncates username/password to 256 chars.
  9817. if (simple_creds->username) strncpy(username, simple_creds->username, NE_ABUFSIZ);
  9818. if (simple_creds->password) strncpy(password, simple_creds->password, NE_ABUFSIZ);
  9819. return 0;
  9820. }
  9821. // a cleanup routine attached to the pool that contains the RA session baton.
  9822. static apr_status_t
  9823. cleanup_session(
  9824. void * sess)
  9825. {
  9826. ne_session_destroy(static_cast<ne_session *>(sess));
  9827. return APR_SUCCESS;
  9828. }
  9829. // a cleanup routine attached to the pool that contains the PKCS#11
  9830. // provider object.
  9831. static apr_status_t
  9832. cleanup_p11provider(
  9833. void * provider)
  9834. {
  9835. ne_ssl_pkcs11_provider * prov = static_cast<ne_ssl_pkcs11_provider *>(provider);
  9836. ne_ssl_pkcs11_provider_destroy(prov);
  9837. return APR_SUCCESS;
  9838. }
  9839. #ifdef NETBOX_DEBUG
  9840. typedef struct debug_file_baton_t
  9841. {
  9842. FILE * file;
  9843. } debug_file_baton_t;
  9844. // a cleanup routine
  9845. static apr_status_t
  9846. cleanup_neon_debug_file(
  9847. void * debug_file_baton)
  9848. {
  9849. debug_file_baton_t * baton = static_cast<debug_file_baton_t *>(debug_file_baton);
  9850. if (baton->file) fclose(baton->file);
  9851. return APR_SUCCESS;
  9852. }
  9853. #endif
  9854. static void
  9855. progress_func(
  9856. apr_off_t progress,
  9857. apr_off_t total,
  9858. void * baton,
  9859. apr_pool_t * pool)
  9860. {
  9861. client_ctx_t * ctx = static_cast<client_ctx_t *>(baton);
  9862. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(ctx->auth_baton->parameters,
  9863. CONST_FS_KEY,
  9864. APR_HASH_KEY_STRING));
  9865. assert(fs);
  9866. if (total == -1)
  9867. fs->ReadDirectoryProgress(progress);
  9868. else
  9869. fs->FileTransferProgress(total, progress);
  9870. }
  9871. static void
  9872. ra_neon_neonprogress(
  9873. void * baton,
  9874. apr_off_t progress,
  9875. apr_off_t total)
  9876. {
  9877. neonprogress_baton_t * pb = static_cast<neonprogress_baton_t *>(baton);
  9878. neon_session_t * ras = pb->ras;
  9879. if (ras->progress_func)
  9880. {
  9881. apr_time_t now = apr_time_now();
  9882. if (now - pb->last_progress_time > 200000) // 0.2 sec
  9883. {
  9884. if (total < 0)
  9885. {
  9886. // Neon sends the total number of bytes sent for this specific
  9887. // session and there are two sessions active at once.
  9888. // For this case we combine the totals to allow clients to provide
  9889. // a better progress indicator.
  9890. if (progress >= pb->last_progress)
  9891. ras->total_progress += (progress - pb->last_progress);
  9892. else
  9893. // Session total has been reset. A new stream started
  9894. ras->total_progress += pb->last_progress;
  9895. pb->last_progress = progress;
  9896. ras->progress_func(ras->total_progress, -1, ras->progress_baton, pb->pool);
  9897. }
  9898. else
  9899. {
  9900. // Neon provides total bytes to receive information. Pass literally
  9901. // to allow providing a percentage.
  9902. ras->progress_func(progress, total, ras->progress_baton, pb->pool);
  9903. }
  9904. pb->last_progress_time = now;
  9905. }
  9906. }
  9907. }
  9908. static atomic_t neon_initialized = 0;
  9909. static error_t
  9910. initialize_neon(
  9911. void * baton,
  9912. apr_pool_t * scratch_pool)
  9913. {
  9914. if (ne_sock_init() != 0)
  9915. return error_create(WEBDAV_ERR_DAV_SOCK_INIT, NULL,
  9916. "Network socket initialization failed");
  9917. return WEBDAV_NO_ERROR;
  9918. }
  9919. static error_t
  9920. ensure_neon_initialized()
  9921. {
  9922. return atomic_init_once(&neon_initialized, initialize_neon, NULL, NULL);
  9923. }
  9924. static const char * const *
  9925. ra_neon_get_schemes(apr_pool_t * pool)
  9926. {
  9927. static const char * schemes_no_ssl[] = { "http", NULL };
  9928. static const char * schemes_ssl[] = { "http", "https", NULL };
  9929. return ne_has_support(NE_FEATURE_SSL) ? schemes_ssl : schemes_no_ssl;
  9930. }
  9931. static error_t
  9932. neon_open(
  9933. session_t * session,
  9934. const char ** corrected_url,
  9935. const char * session_URL,
  9936. const callbacks2_t * callbacks,
  9937. void * callback_baton,
  9938. apr_pool_t * pool)
  9939. {
  9940. assert(callback_baton);
  9941. callback_baton_t * cb = static_cast<callback_baton_t *>(callback_baton);
  9942. *corrected_url = NULL;
  9943. ne_uri * uri = NULL;
  9944. WEBDAV_ERR(parse_ne_uri(&uri, session_URL, pool));
  9945. // Initialize neon if required
  9946. WEBDAV_ERR(ensure_neon_initialized());
  9947. int is_ssl_session = (strcmp(uri->scheme, "https") == 0);
  9948. if (is_ssl_session)
  9949. {
  9950. if (ne_has_support(NE_FEATURE_SSL) == 0)
  9951. return error_create(WEBDAV_ERR_DAV_SOCK_INIT, NULL,
  9952. "TLS is not supported");
  9953. }
  9954. ne_session * sess = ne_session_create(uri->scheme, uri->host, uri->port);
  9955. apr_pool_cleanup_register(pool, sess, cleanup_session, apr_pool_cleanup_null);
  9956. bool compression = FALSE;
  9957. unsigned int neon_auth_types = 0;
  9958. const char * pkcs11_provider = NULL;
  9959. const char * ssl_authority_file = NULL;
  9960. {
  9961. int proxy_method = 0;
  9962. const char * proxy_host = NULL;
  9963. unsigned int proxy_port = 0;
  9964. const char * proxy_username = NULL;
  9965. const char * proxy_password = NULL;
  9966. int timeout = 0;
  9967. int debug = 0;
  9968. const char * neon_debug_file_name = NULL;
  9969. TWebDAVFileSystem * fs = static_cast<TWebDAVFileSystem *>(apr_hash_get(cb->ctx->auth_baton->parameters,
  9970. CONST_FS_KEY,
  9971. APR_HASH_KEY_STRING));
  9972. assert(fs);
  9973. WEBDAV_ERR(fs->GetServerSettings(
  9974. &proxy_method,
  9975. &proxy_host,
  9976. &proxy_port,
  9977. &proxy_username,
  9978. &proxy_password,
  9979. &timeout,
  9980. &debug,
  9981. &neon_debug_file_name,
  9982. &compression,
  9983. &pkcs11_provider,
  9984. &ssl_authority_file,
  9985. pool));
  9986. if (neon_auth_types == 0)
  9987. {
  9988. // If there were no auth types specified in the configuration
  9989. // file, provide the appropriate defaults.
  9990. neon_auth_types = NE_AUTH_BASIC | NE_AUTH_DIGEST;
  9991. if (is_ssl_session)
  9992. neon_auth_types |= NE_AUTH_NEGOTIATE;
  9993. }
  9994. if (debug && neon_debug_file_name)
  9995. {
  9996. #ifdef NETBOX_DEBUG
  9997. debug_file_baton_t * baton = static_cast<debug_file_baton_t *>(apr_pcalloc(pool, sizeof(*baton)));
  9998. neon_debug_file_name = apr_pstrcat(pool, neon_debug_file_name, ".neondebug.log", NULL);
  9999. baton->file = _fsopen(neon_debug_file_name, "w", SH_DENYWR);
  10000. if (baton->file)
  10001. {
  10002. debug = NE_DBG_HTTP |
  10003. // NE_DBG_XML | NE_DBG_HTTPAUTH |
  10004. NE_DBG_HTTPPLAIN |
  10005. // NE_DBG_XMLPARSE |
  10006. NE_DBG_HTTPBODY |
  10007. // NE_DBG_SSL |
  10008. NE_DBG_FLUSH;
  10009. ne_debug_init(baton->file, debug);
  10010. }
  10011. apr_pool_cleanup_register(pool, baton,
  10012. cleanup_neon_debug_file,
  10013. apr_pool_cleanup_null);
  10014. #else
  10015. ne_debug_init(NULL, 0);
  10016. #endif // #ifdef NETBOX_DEBUG
  10017. }
  10018. TProxyMethod method = (TProxyMethod)proxy_method;
  10019. if (method != ::pmNone)
  10020. {
  10021. if ((method == pmSocks4) || (method == pmSocks5))
  10022. {
  10023. enum ne_sock_sversion vers = method == pmSocks4 ? NE_SOCK_SOCKSV4A : NE_SOCK_SOCKSV5;
  10024. ne_session_socks_proxy(sess, vers, proxy_host, proxy_port, proxy_username, proxy_password);
  10025. }
  10026. else if (proxy_host)
  10027. {
  10028. ne_session_proxy(sess, proxy_host, proxy_port);
  10029. if (proxy_username)
  10030. {
  10031. proxy_auth_baton_t * pab = static_cast<proxy_auth_baton_t *>(apr_pcalloc(pool, sizeof(*pab)));
  10032. pab->username = proxy_username;
  10033. pab->password = proxy_password ? proxy_password : "";
  10034. ne_set_proxy_auth(sess, proxy_auth, pab);
  10035. }
  10036. else
  10037. {
  10038. // Enable (only) the Negotiate scheme for proxy
  10039. // authentication, if no username/password is
  10040. // configured.
  10041. ne_add_proxy_auth(sess, NE_AUTH_NEGOTIATE, NULL, NULL);
  10042. }
  10043. }
  10044. }
  10045. if (!timeout)
  10046. timeout = DEFAULT_HTTP_TIMEOUT;
  10047. ne_set_read_timeout(sess, timeout);
  10048. ne_set_connect_timeout(sess, timeout);
  10049. }
  10050. {
  10051. static std::string useragent = "WinSCP";
  10052. ne_set_useragent(sess, useragent.c_str());
  10053. }
  10054. // Create and fill a session_baton.
  10055. neon_session_t * ras = static_cast<neon_session_t *>(apr_pcalloc(pool, sizeof(*ras)));
  10056. ras->pool = pool;
  10057. {
  10058. // canonicalize url
  10059. const char * remote_url = urlpath_canonicalize(session_URL, pool);
  10060. ras->url = stringbuf_create(remote_url, pool);
  10061. }
  10062. // copies uri pointer members, they get free'd in __close.
  10063. ras->root = *uri;
  10064. ras->ne_sess = sess;
  10065. ras->callbacks = callbacks;
  10066. ras->callback_baton = callback_baton;
  10067. ras->compression = compression;
  10068. ras->progress_baton = callbacks->progress_baton;
  10069. ras->progress_func = callbacks->progress_func;
  10070. ras->capabilities = apr_hash_make(ras->pool);
  10071. // note that ras->username and ras->password are still NULL at this point.
  10072. // Register an authentication 'pull' callback with the neon sessions
  10073. ne_add_server_auth(sess, neon_auth_types, request_auth, ras);
  10074. if (is_ssl_session)
  10075. {
  10076. bool trust_default_ca = false;
  10077. // PEM-encoded Certificate Authority (CA) SSL certificate
  10078. const char * authorities = ssl_authority_file;
  10079. if (authorities != NULL && *authorities)
  10080. {
  10081. const char * file = authorities;
  10082. ne_ssl_certificate * ca_cert = NULL;
  10083. ca_cert = ne_ssl_cert_read(file);
  10084. if (ca_cert == NULL)
  10085. {
  10086. return error_createf(
  10087. WEBDAV_ERR_BAD_CONFIG_VALUE, NULL,
  10088. "Invalid config: unable to load certificate file '%s'", file);
  10089. }
  10090. ne_ssl_trust_cert(sess, ca_cert);
  10091. ne_ssl_cert_free(ca_cert);
  10092. ca_cert = NULL;
  10093. }
  10094. // When the CA certificate or server certificate has
  10095. // verification problems, neon will call our verify function before
  10096. // outright rejection of the connection.*/
  10097. ne_ssl_set_verify(sess, server_ssl_callback, ras);
  10098. // For client connections, we register a callback for if the server
  10099. // wants to authenticate the client via client certificate.
  10100. if (pkcs11_provider && *pkcs11_provider)
  10101. {
  10102. ne_ssl_pkcs11_provider * provider;
  10103. int rv;
  10104. // Initialize the PKCS#11 provider.
  10105. rv = ne_ssl_pkcs11_provider_init(&provider, pkcs11_provider);
  10106. if (rv != NE_PK11_OK)
  10107. {
  10108. return error_createf(WEBDAV_ERR_BAD_CONFIG_VALUE, NULL,
  10109. "Invalid config: unable to load PKCS#11 provider '%s'",
  10110. pkcs11_provider);
  10111. }
  10112. // Share the provider between the two sessions.
  10113. ne_ssl_set_pkcs11_provider(sess, provider);
  10114. ne_ssl_pkcs11_provider_pin(provider, client_ssl_pkcs11_pin_entry, ras);
  10115. apr_pool_cleanup_register(pool, provider, cleanup_p11provider,
  10116. apr_pool_cleanup_null);
  10117. }
  10118. // Note the "else"; if a PKCS#11 provider is set up, a client
  10119. // cert callback is already configured, so don't displace it
  10120. // with the normal one here.
  10121. else
  10122. {
  10123. ne_ssl_provide_clicert(sess, client_ssl_callback, ras);
  10124. }
  10125. // See if the user wants us to trust "default" openssl CAs.
  10126. // TODO: option "trust default CA"
  10127. trust_default_ca = true;
  10128. if (trust_default_ca)
  10129. {
  10130. ne_ssl_trust_default_ca(sess);
  10131. }
  10132. }
  10133. if (ras->progress_func)
  10134. {
  10135. neonprogress_baton_t * progress1 = static_cast<neonprogress_baton_t *>(apr_pcalloc(pool, sizeof(*progress1)));
  10136. neonprogress_baton_t * progress2 = static_cast<neonprogress_baton_t *>(apr_pcalloc(pool, sizeof(*progress2)));
  10137. progress1->pool = pool;
  10138. progress1->ras = ras;
  10139. progress1->last_progress = 0;
  10140. progress2->pool = pool;
  10141. progress2->ras = ras;
  10142. progress2->last_progress = 0;
  10143. ne_set_progress(sess, ra_neon_neonprogress, progress1);
  10144. }
  10145. session->priv = ras;
  10146. const char * corrected = NULL;
  10147. error_t err = neon_exchange_capabilities(ras, &corrected, pool);
  10148. if (corrected)
  10149. *corrected_url = corrected;
  10150. return err;
  10151. }
  10152. static error_t
  10153. neon_reparent(
  10154. session_t * session,
  10155. const char * url,
  10156. apr_pool_t * pool)
  10157. {
  10158. neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
  10159. ne_uri * uri = NULL;
  10160. WEBDAV_ERR(parse_ne_uri(&uri, url, session->pool));
  10161. ras->root = *uri;
  10162. stringbuf_set(ras->url, url);
  10163. ras->webdav_root = neon_uri_unparse(uri, session->pool);
  10164. return WEBDAV_NO_ERROR;
  10165. }
  10166. static error_t
  10167. neon_get_session_url(
  10168. session_t * session,
  10169. const char ** url,
  10170. apr_pool_t * pool)
  10171. {
  10172. neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
  10173. assert(ras);
  10174. *url = apr_pstrmemdup(pool, ras->url->data, ras->url->len);
  10175. return WEBDAV_NO_ERROR;
  10176. }
  10177. static const ne_propname restype_props[] =
  10178. {
  10179. { "DAV:", "resourcetype" },
  10180. { NULL }
  10181. };
  10182. static error_t
  10183. neon_get_file(
  10184. session_t * session,
  10185. const char * path,
  10186. stream_t * stream,
  10187. apr_hash_t ** props,
  10188. apr_pool_t * pool)
  10189. {
  10190. neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
  10191. assert(ras);
  10192. const char * url = path_url_add_component2(ras->url->data, path, pool);
  10193. const ne_propname * which_props = NULL;
  10194. const char * final_url = url;
  10195. if (props)
  10196. {
  10197. // Request all properties if caller requested them.
  10198. which_props = starting_props;
  10199. }
  10200. else
  10201. {
  10202. // Request only resource type on other cases.
  10203. which_props = restype_props;
  10204. }
  10205. neon_resource_t * rsrc = NULL;
  10206. WEBDAV_ERR(neon_get_props_resource(&rsrc, ras, final_url,
  10207. which_props,
  10208. false,
  10209. pool));
  10210. if (rsrc->is_collection)
  10211. {
  10212. return error_create(WEBDAV_ERR_FS_NOT_FILE, NULL,
  10213. "Can't get text contents of a directory");
  10214. }
  10215. if (stream)
  10216. {
  10217. file_write_ctx_t fwc = {0};
  10218. fwc.stream = stream;
  10219. // Fetch the file, shoving it at the provided stream.
  10220. WEBDAV_ERR(custom_get_request(ras, final_url, path,
  10221. get_file_reader, &fwc,
  10222. ras->callback_baton,
  10223. pool));
  10224. }
  10225. return WEBDAV_NO_ERROR;
  10226. }
  10227. static error_t
  10228. neon_get_dir(
  10229. session_t * session,
  10230. apr_hash_t ** dirents,
  10231. const char * path,
  10232. apr_uint32_t dirent_fields,
  10233. apr_pool_t * pool)
  10234. {
  10235. neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
  10236. const char * url = path_url_add_component2(ras->url->data, path, pool);
  10237. const char * final_url = url;
  10238. if (dirents)
  10239. {
  10240. // Just like Nautilus, Cadaver, or any other browser, we do a
  10241. // PROPFIND on the directory of depth 1.
  10242. apr_hash_t * resources = NULL;
  10243. WEBDAV_ERR(neon_get_props(&resources, ras,
  10244. final_url, NEON_DEPTH_ONE,
  10245. starting_props,
  10246. false,
  10247. pool));
  10248. // Count the number of path components in final_url.
  10249. apr_size_t final_url_n_components = path_component_count(final_url);
  10250. // Now we have a hash that maps a bunch of url children to resource
  10251. // objects. Each resource object contains the properties of the
  10252. // child. Parse these resources into dirent_t structs.
  10253. *dirents = apr_hash_make(pool);
  10254. for (apr_hash_index_t * hi = apr_hash_first(pool, resources); hi;
  10255. hi = apr_hash_next(hi))
  10256. {
  10257. const void * key = NULL;
  10258. void * val = NULL;
  10259. const char * childname = NULL;
  10260. neon_resource_t * resource = NULL;
  10261. const string_t * propval = NULL;
  10262. dirent_t * entry = NULL;
  10263. apr_hash_this(hi, &key, NULL, &val);
  10264. childname = relpath_canonicalize(static_cast<const char *>(key), pool);
  10265. resource = static_cast<neon_resource_t *>(val);
  10266. // Skip the effective '.' entry that comes back from
  10267. // NEON_DEPTH_ONE. The children must have one more
  10268. // component then final_url.
  10269. // Note that we can't just strcmp the URLs because of URL encoding
  10270. // differences (i.e. %3c vs. %3C etc.)
  10271. if (path_component_count(childname) < final_url_n_components - 1)
  10272. continue;
  10273. entry = static_cast<dirent_t *>(apr_pcalloc(pool, sizeof(*entry)));
  10274. if (dirent_fields & WEBDAV_DIRENT_KIND)
  10275. {
  10276. // node kind
  10277. entry->kind = resource->is_collection ? node_dir : node_file;
  10278. }
  10279. if (dirent_fields & WEBDAV_DIRENT_SIZE)
  10280. {
  10281. // size
  10282. propval = static_cast<const string_t *>(apr_hash_get(resource->propset,
  10283. NEON_PROP_GETCONTENTLENGTH,
  10284. APR_HASH_KEY_STRING));
  10285. if (propval == NULL)
  10286. entry->size = 0;
  10287. else
  10288. entry->size = atoui64(propval->data);
  10289. }
  10290. if (dirent_fields & WEBDAV_DIRENT_TIME)
  10291. {
  10292. propval = static_cast<const string_t *>(apr_hash_get(resource->propset,
  10293. NEON_PROP_CREATIONDATE,
  10294. APR_HASH_KEY_STRING));
  10295. if (propval != NULL)
  10296. WEBDAV_ERR(time_from_cstring(&(entry->time),
  10297. propval->data, pool));
  10298. }
  10299. apr_hash_set(*dirents,
  10300. path_uri_decode(relpath_basename(childname,
  10301. pool),
  10302. pool),
  10303. APR_HASH_KEY_STRING, entry);
  10304. }
  10305. }
  10306. return WEBDAV_NO_ERROR;
  10307. }
  10308. static error_t
  10309. neon_check_path(
  10310. session_t * session,
  10311. const char * path,
  10312. node_kind_t * kind,
  10313. apr_pool_t * pool)
  10314. {
  10315. neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
  10316. assert(ras);
  10317. const char * url = ras->url->data;
  10318. error_t err = 0;
  10319. bool is_dir = FALSE;
  10320. // If we were given a relative path to append, append it.
  10321. if (path)
  10322. url = path_url_add_component2(url, path, pool);
  10323. if (!err)
  10324. {
  10325. neon_resource_t * rsrc;
  10326. const char * full_bc_url = url;
  10327. // query the DAV:resourcetype of the full, assembled URL.
  10328. err = neon_get_starting_props(&rsrc, ras, full_bc_url, true, pool);
  10329. if (!err)
  10330. is_dir = rsrc->is_collection != 0;
  10331. }
  10332. if (err == WEBDAV_NO_ERROR)
  10333. {
  10334. if (is_dir)
  10335. *kind = node_dir;
  10336. else
  10337. *kind = node_file;
  10338. }
  10339. else if (err == WEBDAV_ERR_FS_NOT_FOUND)
  10340. {
  10341. error_clear(&err);
  10342. err = WEBDAV_NO_ERROR;
  10343. *kind = node_none;
  10344. }
  10345. return err;
  10346. }
  10347. static error_t
  10348. neon_stat(
  10349. session_t * session,
  10350. const char * path,
  10351. dirent_t ** dirent,
  10352. apr_pool_t * pool)
  10353. {
  10354. neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
  10355. assert(ras);
  10356. const char * url = ras->url->data;
  10357. // If we were given a relative path to append, append it.
  10358. if (path)
  10359. url = path_url_add_component2(url, path, pool);
  10360. const char * final_url = url;
  10361. // Depth-zero PROPFIND is the One True DAV Way.
  10362. apr_hash_t * resources = NULL;
  10363. error_t err = neon_get_props(&resources, ras, final_url,
  10364. NEON_DEPTH_ZERO,
  10365. starting_props,
  10366. false,
  10367. pool);
  10368. if (err)
  10369. {
  10370. if (err == WEBDAV_ERR_FS_NOT_FOUND)
  10371. {
  10372. // easy out:
  10373. error_clear(&err);
  10374. *dirent = NULL;
  10375. return WEBDAV_NO_ERROR;
  10376. }
  10377. else
  10378. return err;
  10379. }
  10380. // Copying parsing code from neon_get_dir() here. The hash
  10381. // of resources only contains one item, but there's no other way to
  10382. // get the item.
  10383. for (apr_hash_index_t * hi = apr_hash_first(pool, resources); hi;
  10384. hi = apr_hash_next(hi))
  10385. {
  10386. void * val = NULL;
  10387. apr_hash_this(hi, NULL, NULL, &val);
  10388. neon_resource_t * resource = static_cast<neon_resource_t *>(val);
  10389. dirent_t * entry = static_cast<dirent_t *>(apr_pcalloc(pool, sizeof(*entry)));
  10390. entry->kind = resource->is_collection ? node_dir : node_file;
  10391. const string_t * propval = NULL;
  10392. // entry->size is already 0 by virtue of pcalloc().
  10393. if (entry->kind == node_file)
  10394. {
  10395. propval = static_cast<const string_t *>(apr_hash_get(resource->propset,
  10396. NEON_PROP_GETCONTENTLENGTH,
  10397. APR_HASH_KEY_STRING));
  10398. if (propval)
  10399. entry->size = atoui64(propval->data);
  10400. }
  10401. propval = static_cast<const string_t *>(apr_hash_get(resource->propset,
  10402. NEON_PROP_CREATIONDATE,
  10403. APR_HASH_KEY_STRING));
  10404. if (propval != NULL)
  10405. WEBDAV_ERR(time_from_cstring(&(entry->time),
  10406. propval->data, pool));
  10407. *dirent = entry;
  10408. }
  10409. return WEBDAV_NO_ERROR;
  10410. }
  10411. static error_t
  10412. neon_get_webdav_resource_root(
  10413. session_t * session,
  10414. const char ** url,
  10415. apr_pool_t * pool)
  10416. {
  10417. neon_session_t * ras = static_cast<neon_session_t *>(session->priv);
  10418. assert(ras);
  10419. *url = ras->webdav_root;
  10420. return WEBDAV_NO_ERROR;
  10421. }
  10422. static const vtable_t neon_vtable =
  10423. {
  10424. NULL, // get_description
  10425. ra_neon_get_schemes, // get_schemes
  10426. neon_open, // open_session
  10427. neon_reparent, // reparent
  10428. neon_get_session_url, // get_session_url
  10429. neon_get_file, // get_file
  10430. neon_get_dir, // get_dir
  10431. neon_check_path, // check_path
  10432. neon_stat, // stat
  10433. neon_get_webdav_resource_root, // get_webdav_resource_root
  10434. };
  10435. static error_t
  10436. neon_init(
  10437. const vtable_t ** vtable,
  10438. apr_pool_t * pool)
  10439. {
  10440. *vtable = &neon_vtable;
  10441. return WEBDAV_NO_ERROR;
  10442. }
  10443. } // namespace webdav
  10444. //---------------------------------------------------------------------------
  10445. class TSessionData;
  10446. //---------------------------------------------------------------------------
  10447. class TWebDAVFileListHelper
  10448. {
  10449. public:
  10450. explicit TWebDAVFileListHelper(TWebDAVFileSystem * FileSystem, TRemoteFileList * FileList,
  10451. bool IgnoreFileList) :
  10452. FFileSystem(FileSystem),
  10453. FFileList(FFileSystem->FFileList),
  10454. FIgnoreFileList(FFileSystem->FIgnoreFileList)
  10455. {
  10456. FFileSystem->FFileList = FileList;
  10457. FFileSystem->FIgnoreFileList = IgnoreFileList;
  10458. }
  10459. ~TWebDAVFileListHelper()
  10460. {
  10461. FFileSystem->FFileList = FFileList;
  10462. FFileSystem->FIgnoreFileList = FIgnoreFileList;
  10463. }
  10464. private:
  10465. TWebDAVFileSystem * FFileSystem;
  10466. TRemoteFileList * FFileList;
  10467. bool FIgnoreFileList;
  10468. };
  10469. //---------------------------------------------------------------------------
  10470. #undef FILE_OPERATION_LOOP_EX
  10471. #define FILE_OPERATION_LOOP_EX(ALLOW_SKIP, MESSAGE, OPERATION) \
  10472. FILE_OPERATION_LOOP_CUSTOM(FTerminal, ALLOW_SKIP, MESSAGE, OPERATION, L"")
  10473. //---------------------------------------------------------------------------
  10474. static const UnicodeString CONST_WEBDAV_PROTOCOL_BASE_NAME = L"WebDAV";
  10475. //===========================================================================
  10476. TWebDAVFileSystem::TWebDAVFileSystem(TTerminal * ATerminal) :
  10477. TCustomFileSystem(ATerminal),
  10478. FFileList(NULL),
  10479. FOnCaptureOutput(NULL),
  10480. FPasswordFailed(false),
  10481. FActive(false),
  10482. FFileTransferAbort(ftaNone),
  10483. FIgnoreFileList(false),
  10484. FFileTransferCancelled(false),
  10485. FFileTransferResumed(0),
  10486. FFileTransferPreserveTime(false),
  10487. FHasTrailingSlash(false),
  10488. FFileTransferCPSLimit(0),
  10489. FLastReadDirectoryProgress(0),
  10490. FCurrentOperationProgress(NULL),
  10491. FTransferStatusCriticalSection(new TCriticalSection()),
  10492. webdav_pool(NULL),
  10493. FSession(NULL)
  10494. {
  10495. FFileSystemInfo.ProtocolBaseName = CONST_WEBDAV_PROTOCOL_BASE_NAME;
  10496. FFileSystemInfo.ProtocolName = FFileSystemInfo.ProtocolBaseName;
  10497. if (apr_initialize() != APR_SUCCESS)
  10498. throw ExtException(UnicodeString(L"Cannot init APR"), NULL);
  10499. apr_pool_create(&webdav_pool, NULL);
  10500. }
  10501. //---------------------------------------------------------------------------
  10502. __fastcall TWebDAVFileSystem::~TWebDAVFileSystem()
  10503. {
  10504. delete FTransferStatusCriticalSection;
  10505. FTransferStatusCriticalSection = NULL;
  10506. webdav_pool_destroy(webdav_pool);
  10507. apr_terminate();
  10508. webdav_pool = NULL;
  10509. ne_sock_exit();
  10510. }
  10511. //---------------------------------------------------------------------------
  10512. void __fastcall TWebDAVFileSystem::Open()
  10513. {
  10514. FCurrentDirectory = L"";
  10515. FHasTrailingSlash = false;
  10516. TSessionData * Data = FTerminal->SessionData;
  10517. FSessionInfo.LoginTime = Now();
  10518. bool Ssl = (FTerminal->SessionData->Ftps != ftpsNone);
  10519. if (Ssl)
  10520. {
  10521. FSessionInfo.SecurityProtocolName = LoadStr(FTPS_IMPLICIT);
  10522. }
  10523. UnicodeString HostName = Data->HostNameExpanded;
  10524. size_t Port = Data->PortNumber;
  10525. UnicodeString ProtocolName = !Ssl ? L"http" : L"https";
  10526. UnicodeString UserName = Data->UserNameExpanded;
  10527. UnicodeString Path = Data->RemoteDirectory;
  10528. UnicodeString Url = FORMAT(L"%s://%s:%d%s", (ProtocolName.c_str(), HostName.c_str(), Port, Path.c_str()));
  10529. FPasswordFailed = false;
  10530. FTerminal->Information(LoadStr(STATUS_CONNECT), true);
  10531. for (int I = 0; I < 5; I++)
  10532. {
  10533. FActive = false;
  10534. try
  10535. {
  10536. FActive = (WEBDAV_NO_ERROR == OpenURL(Url, webdav_pool));
  10537. if (FActive)
  10538. {
  10539. break;
  10540. }
  10541. }
  10542. catch (...)
  10543. {
  10544. if (FFileTransferCancelled)
  10545. break;
  10546. apr_sleep(200000); // 0.2 sec
  10547. }
  10548. }
  10549. if (!FActive)
  10550. {
  10551. FTerminal->Closed();
  10552. throw Exception(LoadStr(CONNECTION_FAILED));
  10553. }
  10554. }
  10555. //---------------------------------------------------------------------------
  10556. void __fastcall TWebDAVFileSystem::Close()
  10557. {
  10558. assert(FActive);
  10559. FTerminal->Closed();
  10560. FActive = false;
  10561. }
  10562. //---------------------------------------------------------------------------
  10563. bool __fastcall TWebDAVFileSystem::GetActive()
  10564. {
  10565. return FActive;
  10566. }
  10567. //---------------------------------------------------------------------------
  10568. void __fastcall TWebDAVFileSystem::CollectUsage()
  10569. {
  10570. }
  10571. //---------------------------------------------------------------------------
  10572. const TSessionInfo & __fastcall TWebDAVFileSystem::GetSessionInfo()
  10573. {
  10574. return FSessionInfo;
  10575. }
  10576. //---------------------------------------------------------------------------
  10577. const TFileSystemInfo & __fastcall TWebDAVFileSystem::GetFileSystemInfo(bool Retrieve)
  10578. {
  10579. return FFileSystemInfo;
  10580. }
  10581. //---------------------------------------------------------------------------
  10582. bool __fastcall TWebDAVFileSystem::TemporaryTransferFile(const UnicodeString & /*FileName*/)
  10583. {
  10584. return false;
  10585. }
  10586. //---------------------------------------------------------------------------
  10587. bool __fastcall TWebDAVFileSystem::GetStoredCredentialsTried()
  10588. {
  10589. return false;
  10590. }
  10591. //---------------------------------------------------------------------------
  10592. UnicodeString __fastcall TWebDAVFileSystem::GetUserName()
  10593. {
  10594. return FUserName;
  10595. }
  10596. //---------------------------------------------------------------------------
  10597. void __fastcall TWebDAVFileSystem::Idle()
  10598. {
  10599. // TODO: Keep session alive
  10600. return;
  10601. }
  10602. //---------------------------------------------------------------------------
  10603. UnicodeString __fastcall TWebDAVFileSystem::AbsolutePath(const UnicodeString Path, bool /*Local*/)
  10604. {
  10605. return ::AbsolutePath(GetCurrentDirectory(), Path);
  10606. }
  10607. //---------------------------------------------------------------------------
  10608. bool __fastcall TWebDAVFileSystem::IsCapable(int Capability) const
  10609. {
  10610. assert(FTerminal);
  10611. switch (Capability)
  10612. {
  10613. case fcUserGroupListing:
  10614. case fcModeChanging:
  10615. case fcModeChangingUpload:
  10616. case fcPreservingTimestampUpload:
  10617. case fcGroupChanging:
  10618. case fcOwnerChanging:
  10619. case fcAnyCommand:
  10620. case fcShellAnyCommand:
  10621. case fcHardLink:
  10622. case fcSymbolicLink:
  10623. case fcResolveSymlink:
  10624. return false;
  10625. case fcRename:
  10626. case fcRemoteMove:
  10627. case fcRemoteCopy:
  10628. return true;
  10629. case fcTextMode:
  10630. case fcNativeTextMode:
  10631. case fcNewerOnlyUpload:
  10632. case fcTimestampChanging:
  10633. case fcLoadingAdditionalProperties:
  10634. case fcCheckingSpaceAvailable:
  10635. case fcIgnorePermErrors:
  10636. case fcCalculatingChecksum:
  10637. case fcSecondaryShell: // has fcShellAnyCommand
  10638. case fcGroupOwnerChangingByID: // by name
  10639. case fcRemoveCtrlZUpload:
  10640. case fcRemoveBOMUpload:
  10641. return false;
  10642. default:
  10643. assert(false);
  10644. return false;
  10645. }
  10646. }
  10647. //---------------------------------------------------------------------------
  10648. void __fastcall TWebDAVFileSystem::EnsureLocation()
  10649. {
  10650. if (!FCachedDirectoryChange.IsEmpty())
  10651. {
  10652. FTerminal->LogEvent(FORMAT(L"Locating to cached directory \"%s\".",
  10653. (FCachedDirectoryChange.c_str())));
  10654. UnicodeString Directory = FCachedDirectoryChange;
  10655. FCachedDirectoryChange = L"";
  10656. try
  10657. {
  10658. ChangeDirectory(Directory);
  10659. }
  10660. catch (...)
  10661. {
  10662. // when location to cached directory fails, pretend again
  10663. // location in cached directory
  10664. // here used to be check (CurrentDirectory != Directory), but it is
  10665. // false always (currentdirectory is already set to cached directory),
  10666. // making the condition below useless. check removed.
  10667. if (FTerminal->GetActive())
  10668. {
  10669. FCachedDirectoryChange = Directory;
  10670. }
  10671. throw;
  10672. }
  10673. }
  10674. }
  10675. //---------------------------------------------------------------------------
  10676. UnicodeString __fastcall TWebDAVFileSystem::GetCurrentDirectory()
  10677. {
  10678. return FCurrentDirectory;
  10679. }
  10680. //---------------------------------------------------------------------------
  10681. void __fastcall TWebDAVFileSystem::DoStartup()
  10682. {
  10683. FTerminal->SetExceptionOnFail(true);
  10684. // retrieve initialize working directory to save it as home directory
  10685. ReadCurrentDirectory();
  10686. FTerminal->SetExceptionOnFail(false);
  10687. }
  10688. //---------------------------------------------------------------------------
  10689. //---------------------------------------------------------------------------
  10690. void __fastcall TWebDAVFileSystem::LookupUsersGroups()
  10691. {
  10692. }
  10693. //---------------------------------------------------------------------------
  10694. void __fastcall TWebDAVFileSystem::ReadCurrentDirectory()
  10695. {
  10696. if (FCachedDirectoryChange.IsEmpty())
  10697. {
  10698. FCurrentDirectory = FCurrentDirectory.IsEmpty() ? UnicodeString(L"/") : FCurrentDirectory;
  10699. }
  10700. else
  10701. {
  10702. FCurrentDirectory = FCachedDirectoryChange;
  10703. }
  10704. }
  10705. //---------------------------------------------------------------------------
  10706. void __fastcall TWebDAVFileSystem::HomeDirectory()
  10707. {
  10708. }
  10709. //---------------------------------------------------------------------------
  10710. void __fastcall TWebDAVFileSystem::AnnounceFileListOperation()
  10711. {
  10712. // noop
  10713. }
  10714. //---------------------------------------------------------------------------
  10715. void __fastcall TWebDAVFileSystem::DoChangeDirectory(const UnicodeString Directory)
  10716. {
  10717. }
  10718. //---------------------------------------------------------------------------
  10719. void __fastcall TWebDAVFileSystem::ChangeDirectory(const UnicodeString ADirectory)
  10720. {
  10721. UnicodeString Directory = ADirectory;
  10722. bool HasTrailingSlash = (Directory.Length() > 0) && (Directory[Directory.Length()] == L'/');
  10723. try
  10724. {
  10725. // For changing directory, we do not make paths absolute, instead we
  10726. // delegate this to the server, hence we synchronize current working
  10727. // directory with the server and only then we ask for the change with
  10728. // relative path.
  10729. // But if synchronization fails, typically because current working directory
  10730. // no longer exists, we fall back to out own resolution, to give
  10731. // user chance to leave the non-existing directory.
  10732. EnsureLocation();
  10733. }
  10734. catch (...)
  10735. {
  10736. if (FTerminal->GetActive())
  10737. {
  10738. Directory = AbsolutePath(Directory, false);
  10739. if (HasTrailingSlash)
  10740. Directory = ::UnixIncludeTrailingBackslash(Directory);
  10741. }
  10742. else
  10743. {
  10744. throw;
  10745. }
  10746. }
  10747. FCurrentDirectory = AbsolutePath(Directory, false);
  10748. if (HasTrailingSlash)
  10749. FCurrentDirectory = ::UnixIncludeTrailingBackslash(FCurrentDirectory);
  10750. // make next ReadCurrentDirectory retrieve actual server-side current directory
  10751. FCachedDirectoryChange = L"";
  10752. }
  10753. //---------------------------------------------------------------------------
  10754. void __fastcall TWebDAVFileSystem::CachedChangeDirectory(const UnicodeString Directory)
  10755. {
  10756. FCachedDirectoryChange = UnixExcludeTrailingBackslash(Directory);
  10757. }
  10758. void __fastcall TWebDAVFileSystem::DoReadDirectory(TRemoteFileList * FileList)
  10759. {
  10760. FileList->Reset();
  10761. // add parent directory
  10762. FileList->AddFile(new TRemoteParentDirectory(FTerminal));
  10763. FLastReadDirectoryProgress = 0;
  10764. TWebDAVFileListHelper Helper(this, FileList, false);
  10765. // always specify path to list, do not attempt to
  10766. // list "current" dir as:
  10767. // 1) List() lists again the last listed directory, not the current working directory
  10768. // 2) we handle this way the cached directory change
  10769. UnicodeString Directory = AbsolutePath(FileList->Directory, false);
  10770. if (FHasTrailingSlash)
  10771. Directory = ::UnixIncludeTrailingBackslash(Directory);
  10772. WebDAVGetList(Directory);
  10773. }
  10774. //---------------------------------------------------------------------------
  10775. void __fastcall TWebDAVFileSystem::ReadDirectory(TRemoteFileList * FileList)
  10776. {
  10777. assert(FileList);
  10778. bool Repeat = false;
  10779. do
  10780. {
  10781. Repeat = false;
  10782. try
  10783. {
  10784. DoReadDirectory(FileList);
  10785. }
  10786. catch (Exception &)
  10787. {
  10788. if (!FTerminal->GetActive())
  10789. {
  10790. FTerminal->Reopen(ropNoReadDirectory);
  10791. Repeat = true;
  10792. }
  10793. else
  10794. {
  10795. throw;
  10796. }
  10797. }
  10798. }
  10799. while (Repeat);
  10800. }
  10801. //---------------------------------------------------------------------------
  10802. void __fastcall TWebDAVFileSystem::ReadSymlink(TRemoteFile * SymlinkFile,
  10803. TRemoteFile *& File)
  10804. {
  10805. CustomReadFile(SymlinkFile->LinkTo, File, SymlinkFile);
  10806. }
  10807. //---------------------------------------------------------------------------
  10808. void __fastcall TWebDAVFileSystem::ReadFile(const UnicodeString FileName,
  10809. TRemoteFile *& File)
  10810. {
  10811. CustomReadFile(FileName, File, NULL);
  10812. }
  10813. //---------------------------------------------------------------------------
  10814. void __fastcall TWebDAVFileSystem::CustomReadFile(const UnicodeString FileName,
  10815. TRemoteFile *& File, TRemoteFile * ALinkedByFile)
  10816. {
  10817. File = NULL;
  10818. bool isExist = false;
  10819. int is_dir = 0;
  10820. isExist = WebDAVCheckExisting(FileName.c_str(), is_dir);
  10821. if (isExist)
  10822. {
  10823. File = new TRemoteFile();
  10824. if (is_dir)
  10825. File->Type = FILETYPE_DIRECTORY;
  10826. }
  10827. }
  10828. //---------------------------------------------------------------------------
  10829. void __fastcall TWebDAVFileSystem::DeleteFile(const UnicodeString FileName,
  10830. const TRemoteFile * File, int Params, TRmSessionAction & Action)
  10831. {
  10832. USEDPARAM(File);
  10833. USEDPARAM(Params);
  10834. UnicodeString FullFileName = File->FullFileName;
  10835. bool res = WebDAVDeleteFile(FullFileName.c_str());
  10836. if (!res)
  10837. {
  10838. THROW_SKIP_FILE(NULL, L"");
  10839. }
  10840. }
  10841. //---------------------------------------------------------------------------
  10842. void __fastcall TWebDAVFileSystem::RenameFile(const UnicodeString FileName,
  10843. const UnicodeString NewName)
  10844. {
  10845. UnicodeString FullFileName = ::UnixIncludeTrailingBackslash(FCurrentDirectory) + FileName;
  10846. bool res = WebDAVRenameFile(FullFileName.c_str(), NewName.c_str());
  10847. if (!res)
  10848. {
  10849. THROW_SKIP_FILE(NULL, L"");
  10850. }
  10851. }
  10852. //---------------------------------------------------------------------------
  10853. void __fastcall TWebDAVFileSystem::CopyFile(const UnicodeString FileName,
  10854. const UnicodeString NewName)
  10855. {
  10856. }
  10857. //---------------------------------------------------------------------------
  10858. void __fastcall TWebDAVFileSystem::CreateDirectory(const UnicodeString DirName)
  10859. {
  10860. UnicodeString FullDirName = AbsolutePath(DirName, true);
  10861. bool res = WebDAVMakeDirectory(FullDirName.c_str());
  10862. if (!res)
  10863. {
  10864. TStringList * Strings = new TStringList();
  10865. Strings->Delimiter = L'/';
  10866. Strings->DelimitedText = DirName;
  10867. UnicodeString CurDir;
  10868. for (int i = 0; i < Strings->Count; i++)
  10869. {
  10870. if (Strings->Strings[i].IsEmpty())
  10871. {
  10872. continue;
  10873. }
  10874. CurDir += L"/" + Strings->Strings[i];
  10875. res = WebDAVMakeDirectory(CurDir.c_str());
  10876. }
  10877. if (!res)
  10878. {
  10879. THROW_SKIP_FILE(NULL, L"");
  10880. }
  10881. }
  10882. }
  10883. //---------------------------------------------------------------------------
  10884. void __fastcall TWebDAVFileSystem::CreateLink(const UnicodeString FileName,
  10885. const UnicodeString PointTo, bool Symbolic)
  10886. {
  10887. }
  10888. //---------------------------------------------------------------------------
  10889. void __fastcall TWebDAVFileSystem::ChangeFileProperties(const UnicodeString FileName,
  10890. const TRemoteFile * File, const TRemoteProperties * Properties,
  10891. TChmodSessionAction & Action)
  10892. {
  10893. assert(Properties);
  10894. }
  10895. //---------------------------------------------------------------------------
  10896. bool __fastcall TWebDAVFileSystem::LoadFilesProperties(TStrings * /*FileList*/)
  10897. {
  10898. assert(false);
  10899. return false;
  10900. }
  10901. //---------------------------------------------------------------------------
  10902. void __fastcall TWebDAVFileSystem::CalculateFilesChecksum(const UnicodeString & /*Alg*/,
  10903. TStrings * /*FileList*/, TStrings * /*Checksums*/,
  10904. TCalculatedChecksumEvent /*OnCalculatedChecksum*/)
  10905. {
  10906. assert(false);
  10907. }
  10908. //---------------------------------------------------------------------------
  10909. bool __fastcall TWebDAVFileSystem::ConfirmOverwrite(UnicodeString & FileName,
  10910. TOverwriteMode & OverwriteMode, TFileOperationProgressType * OperationProgress,
  10911. const TOverwriteFileParams * FileParams, const TCopyParamType * CopyParam,
  10912. int Params, bool AutoResume, unsigned int &Answer)
  10913. {
  10914. bool Result;
  10915. bool CanAutoResume = FLAGSET(Params, cpNoConfirmation) && AutoResume;
  10916. bool CanResume = false; // disable resume
  10917. Answer = 0;
  10918. if (CanAutoResume && CanResume)
  10919. {
  10920. Answer = qaRetry;
  10921. }
  10922. else
  10923. {
  10924. // retry = "resume"
  10925. // all = "yes to newer"
  10926. // ignore = "rename"
  10927. int Answers = qaYes | qaNo | qaCancel | qaYesToAll | qaNoToAll | qaAll | qaIgnore;
  10928. if (CanResume)
  10929. {
  10930. Answers |= qaRetry;
  10931. }
  10932. TQueryButtonAlias Aliases[3];
  10933. Aliases[0].Button = qaRetry;
  10934. Aliases[0].Alias = LoadStr(RESUME_BUTTON);
  10935. Aliases[1].Button = qaAll;
  10936. Aliases[1].Alias = LoadStr(YES_TO_NEWER_BUTTON);
  10937. Aliases[2].Button = qaIgnore;
  10938. Aliases[2].Alias = LoadStr(RENAME_BUTTON);
  10939. TQueryParams QueryParams(qpNeverAskAgainCheck);
  10940. QueryParams.Aliases = Aliases;
  10941. QueryParams.AliasesCount = LENOF(Aliases);
  10942. SUSPEND_OPERATION (
  10943. Answer = FTerminal->ConfirmFileOverwrite(FileName, FileParams,
  10944. Answers, &QueryParams,
  10945. OperationProgress->Side == osLocal ? osRemote : osLocal,
  10946. CopyParam, Params, OperationProgress);
  10947. )
  10948. }
  10949. Result = true;
  10950. switch (Answer)
  10951. {
  10952. // resume
  10953. case qaRetry:
  10954. OverwriteMode = omResume;
  10955. assert(FileParams != NULL);
  10956. assert(CanResume);
  10957. FFileTransferResumed = FileParams->DestSize;
  10958. break;
  10959. // rename
  10960. case qaIgnore:
  10961. if (FTerminal->PromptUser(FTerminal->SessionData, pkFileName,
  10962. LoadStr(RENAME_TITLE), L"", LoadStr(RENAME_PROMPT2), true, 0, FileName))
  10963. {
  10964. OverwriteMode = omOverwrite;
  10965. }
  10966. else
  10967. {
  10968. if (!OperationProgress->Cancel)
  10969. {
  10970. OperationProgress->Cancel = csCancel;
  10971. }
  10972. FFileTransferAbort = ftaCancel;
  10973. Result = false;
  10974. }
  10975. break;
  10976. case qaYes:
  10977. OverwriteMode = omOverwrite;
  10978. break;
  10979. case qaNo:
  10980. FFileTransferAbort = ftaSkip;
  10981. Result = false;
  10982. break;
  10983. case qaCancel:
  10984. if (!OperationProgress->Cancel)
  10985. {
  10986. OperationProgress->Cancel = csCancel;
  10987. }
  10988. FFileTransferAbort = ftaCancel;
  10989. Result = false;
  10990. break;
  10991. default:
  10992. assert(false);
  10993. Result = false;
  10994. break;
  10995. }
  10996. return Result;
  10997. }
  10998. //---------------------------------------------------------------------------
  10999. void __fastcall TWebDAVFileSystem::CustomCommandOnFile(const UnicodeString FileName,
  11000. const TRemoteFile * File, UnicodeString Command, int Params, TCaptureOutputEvent OutputEvent)
  11001. {
  11002. assert(File);
  11003. bool Dir = File->IsDirectory && !File->IsSymLink;
  11004. if (Dir && (Params & ccRecursive))
  11005. {
  11006. TCustomCommandParams AParams;
  11007. AParams.Command = Command;
  11008. AParams.Params = Params;
  11009. AParams.OutputEvent = OutputEvent;
  11010. FTerminal->ProcessDirectory(FileName, FTerminal->CustomCommandOnFile, &AParams);
  11011. }
  11012. if (!Dir || (Params & ccApplyToDirectories))
  11013. {
  11014. TCustomCommandData Data(FTerminal);
  11015. UnicodeString Cmd = TRemoteCustomCommand(
  11016. Data, FTerminal->GetCurrentDirectory(), FileName, L"").
  11017. Complete(Command, true);
  11018. }
  11019. }
  11020. //---------------------------------------------------------------------------
  11021. void __fastcall TWebDAVFileSystem::AnyCommand(const UnicodeString Command,
  11022. TCaptureOutputEvent OutputEvent)
  11023. {
  11024. }
  11025. //---------------------------------------------------------------------------
  11026. UnicodeString __fastcall TWebDAVFileSystem::FileUrl(const UnicodeString FileName)
  11027. {
  11028. return FTerminal->FileUrl(FTerminal->SessionData->Ftps == ftpsNone ?
  11029. L"http" : L"https", FileName);
  11030. }
  11031. //---------------------------------------------------------------------------
  11032. TStrings * __fastcall TWebDAVFileSystem::GetFixedPaths()
  11033. {
  11034. return NULL;
  11035. }
  11036. //---------------------------------------------------------------------------
  11037. void __fastcall TWebDAVFileSystem::SpaceAvailable(const UnicodeString Path,
  11038. TSpaceAvailable & /*ASpaceAvailable*/)
  11039. {
  11040. assert(false);
  11041. }
  11042. //---------------------------------------------------------------------------
  11043. void __fastcall TWebDAVFileSystem::CopyToRemote(TStrings * FilesToCopy,
  11044. const UnicodeString ATargetDir, const TCopyParamType * CopyParam,
  11045. int Params, TFileOperationProgressType * OperationProgress,
  11046. TOnceDoneOperation & OnceDoneOperation)
  11047. {
  11048. assert((FilesToCopy != NULL) && (OperationProgress != NULL));
  11049. Params &= ~cpAppend;
  11050. UnicodeString FileName, FileNameOnly;
  11051. UnicodeString TargetDir = AbsolutePath(ATargetDir, false);
  11052. UnicodeString FullTargetDir = ::UnixIncludeTrailingBackslash(TargetDir);
  11053. intptr_t Index = 0;
  11054. while ((Index < FilesToCopy->Count) && !OperationProgress->Cancel)
  11055. {
  11056. bool Success = false;
  11057. FileName = FilesToCopy->Strings[Index];
  11058. FileNameOnly = ExtractFileName(FileName, false);
  11059. try
  11060. {
  11061. try
  11062. {
  11063. if (FTerminal->SessionData->CacheDirectories)
  11064. {
  11065. FTerminal->DirectoryModified(TargetDir, false);
  11066. if (::DirectoryExists(::ExtractFilePath(FileName)))
  11067. {
  11068. FTerminal->DirectoryModified(FullTargetDir + FileNameOnly, true);
  11069. }
  11070. }
  11071. WebDAVSourceRobust(FileName, FullTargetDir, CopyParam, Params, OperationProgress,
  11072. tfFirstLevel);
  11073. Success = true;
  11074. }
  11075. catch (EScpSkipFile & E)
  11076. {
  11077. SUSPEND_OPERATION (
  11078. if (!FTerminal->HandleException(&E))
  11079. {
  11080. throw;
  11081. }
  11082. );
  11083. }
  11084. }
  11085. __finally
  11086. {
  11087. OperationProgress->Finish(FileName, Success, OnceDoneOperation);
  11088. }
  11089. Index++;
  11090. }
  11091. }
  11092. //---------------------------------------------------------------------------
  11093. void __fastcall TWebDAVFileSystem::WebDAVSourceRobust(const UnicodeString FileName,
  11094. const UnicodeString TargetDir, const TCopyParamType * CopyParam, int Params,
  11095. TFileOperationProgressType * OperationProgress, unsigned int Flags)
  11096. {
  11097. bool Retry = false;
  11098. TUploadSessionAction Action(FTerminal->ActionLog);
  11099. do
  11100. {
  11101. Retry = false;
  11102. try
  11103. {
  11104. WebDAVSource(FileName, TargetDir, CopyParam, Params, OperationProgress,
  11105. Flags, Action);
  11106. }
  11107. catch (Exception & E)
  11108. {
  11109. Retry = true;
  11110. if (FTerminal->GetActive() ||
  11111. !FTerminal->QueryReopen(&E, ropNoReadDirectory, OperationProgress))
  11112. {
  11113. FTerminal->RollbackAction(Action, OperationProgress, &E);
  11114. throw;
  11115. }
  11116. }
  11117. if (Retry)
  11118. {
  11119. OperationProgress->RollbackTransfer();
  11120. Action.Restart();
  11121. // prevent overwrite confirmations
  11122. // (should not be set for directories!)
  11123. Params |= cpNoConfirmation;
  11124. Flags |= tfAutoResume;
  11125. }
  11126. }
  11127. while (Retry);
  11128. }
  11129. //---------------------------------------------------------------------------
  11130. void __fastcall TWebDAVFileSystem::WebDAVSource(const UnicodeString FileName,
  11131. const UnicodeString TargetDir, const TCopyParamType * CopyParam, int Params,
  11132. TFileOperationProgressType * OperationProgress, unsigned int Flags,
  11133. TUploadSessionAction & Action)
  11134. {
  11135. bool CheckExistence = UnixComparePaths(TargetDir, FTerminal->GetCurrentDirectory()) &&
  11136. (FTerminal->FFiles != NULL) && FTerminal->FFiles->Loaded;
  11137. bool CanProceed = false;
  11138. UnicodeString FileNameOnly =
  11139. CopyParam->ChangeFileName(ExtractFileName(FileName, false), osLocal, true);
  11140. if (CheckExistence)
  11141. {
  11142. TRemoteFile * File = FTerminal->FFiles->FindFile(FileNameOnly);
  11143. if (File != NULL)
  11144. {
  11145. unsigned int Answer = 0;
  11146. if (File->IsDirectory)
  11147. {
  11148. UnicodeString Message = FMTLOAD(DIRECTORY_OVERWRITE, (FileNameOnly.c_str()));
  11149. TQueryParams QueryParams(qpNeverAskAgainCheck);
  11150. SUSPEND_OPERATION (
  11151. Answer = FTerminal->ConfirmFileOverwrite(
  11152. FileNameOnly /*not used*/, NULL,
  11153. qaYes | qaNo | qaCancel | qaYesToAll | qaNoToAll,
  11154. &QueryParams, osRemote, CopyParam, Params, OperationProgress, Message);
  11155. );
  11156. switch (Answer)
  11157. {
  11158. case qaYes:
  11159. CanProceed = true;
  11160. break;
  11161. case qaCancel:
  11162. OperationProgress->Cancel = csCancel; // continue on next case
  11163. // FALLTHROUGH
  11164. case qaNo:
  11165. CanProceed = false;
  11166. break;
  11167. default:
  11168. break;
  11169. }
  11170. }
  11171. else
  11172. {
  11173. __int64 Size;
  11174. __int64 MTime;
  11175. TOverwriteFileParams FileParams;
  11176. FTerminal->OpenLocalFile(FileName, GENERIC_READ,
  11177. NULL, NULL, NULL, &MTime, NULL,
  11178. &Size);
  11179. FileParams.SourceSize = Size;
  11180. FileParams.SourceTimestamp = UnixToDateTime(MTime,
  11181. FTerminal->SessionData->DSTMode);
  11182. FileParams.DestSize = File->Size;
  11183. FileParams.DestTimestamp = File->Modification;
  11184. TOverwriteMode OverwriteMode = omOverwrite;
  11185. bool AutoResume = false;
  11186. ConfirmOverwrite(FileNameOnly, OverwriteMode, OperationProgress,
  11187. &FileParams, CopyParam, Params, AutoResume, Answer);
  11188. switch (Answer)
  11189. {
  11190. case qaYes:
  11191. CanProceed = true;
  11192. break;
  11193. case qaCancel:
  11194. OperationProgress->Cancel = csCancel; // continue on next case
  11195. // FALLTHROUGH
  11196. case qaNo:
  11197. CanProceed = false;
  11198. break;
  11199. default:
  11200. break;
  11201. }
  11202. }
  11203. }
  11204. else
  11205. {
  11206. CanProceed = true;
  11207. }
  11208. }
  11209. else
  11210. {
  11211. CanProceed = true;
  11212. }
  11213. if (CanProceed)
  11214. {
  11215. Action.FileName(ExpandUNCFileName(FileName));
  11216. OperationProgress->SetFile(FileName, false);
  11217. if (!FTerminal->AllowLocalFileTransfer(FileName, CopyParam))
  11218. {
  11219. FTerminal->LogEvent(FORMAT(L"File \"%s\" excluded from transfer", (FileName.c_str())));
  11220. THROW_SKIP_FILE_NULL;
  11221. }
  11222. __int64 Size;
  11223. int Attrs;
  11224. FTerminal->OpenLocalFile(FileName, GENERIC_READ, &Attrs,
  11225. NULL, NULL, NULL, NULL, &Size);
  11226. OperationProgress->SetFileInProgress();
  11227. bool Dir = FLAGSET(Attrs, faDirectory);
  11228. if (Dir)
  11229. {
  11230. Action.Cancel();
  11231. WebDAVDirectorySource(IncludeTrailingBackslash(FileName), TargetDir,
  11232. Attrs, CopyParam, Params, OperationProgress, Flags);
  11233. }
  11234. else
  11235. {
  11236. UnicodeString DestFileName = CopyParam->ChangeFileName(ExtractFileName(FileName, false),
  11237. osLocal, FLAGSET(Flags, tfFirstLevel));
  11238. FTerminal->LogEvent(FORMAT(L"Copying \"%s\" to remote directory started.", (FileName.c_str())));
  11239. OperationProgress->SetLocalSize(Size);
  11240. // Suppose same data size to transfer as to read
  11241. // (not true with ASCII transfer)
  11242. OperationProgress->SetTransferSize(OperationProgress->LocalSize);
  11243. OperationProgress->TransferingFile = false;
  11244. // Will we use ASCII of BINARY file transfer?
  11245. TFileMasks::TParams MaskParams;
  11246. MaskParams.Size = Size;
  11247. ResetFileTransfer();
  11248. TFileTransferData UserData;
  11249. {
  11250. unsigned int TransferType = 2;
  11251. // ignore file list
  11252. TWebDAVFileListHelper Helper(this, NULL, true);
  11253. FFileTransferCPSLimit = OperationProgress->CPSLimit;
  11254. // not used for uploads anyway
  11255. FFileTransferPreserveTime = CopyParam->PreserveTime;
  11256. // not used for uploads, but we get new name (if any) back in this field
  11257. UserData.FileName = DestFileName;
  11258. UserData.Params = Params;
  11259. UserData.AutoResume = FLAGSET(Flags, tfAutoResume);
  11260. UserData.CopyParam = CopyParam;
  11261. FileTransfer(FileName, FileName, DestFileName,
  11262. TargetDir, false, Size, TransferType, UserData, OperationProgress);
  11263. }
  11264. UnicodeString DestFullName = TargetDir + UserData.FileName;
  11265. // only now, we know the final destination
  11266. Action.Destination(DestFullName);
  11267. }
  11268. // TODO : Delete also read-only files.
  11269. if (FLAGSET(Params, cpDelete))
  11270. {
  11271. if (!Dir)
  11272. {
  11273. FILE_OPERATION_LOOP (FMTLOAD(DELETE_LOCAL_FILE_ERROR, (FileName.c_str())),
  11274. THROWOSIFFALSE(::DeleteFile(FileName.c_str()));
  11275. )
  11276. }
  11277. }
  11278. else if (CopyParam->ClearArchive && FLAGSET(Attrs, faArchive))
  11279. {
  11280. FILE_OPERATION_LOOP (FMTLOAD(CANT_SET_ATTRS, (FileName.c_str())),
  11281. THROWOSIFFALSE(FileSetAttr(FileName, Attrs & ~faArchive) == 0);
  11282. )
  11283. }
  11284. }
  11285. }
  11286. //---------------------------------------------------------------------------
  11287. void __fastcall TWebDAVFileSystem::WebDAVDirectorySource(const UnicodeString DirectoryName,
  11288. const UnicodeString TargetDir, int Attrs, const TCopyParamType * CopyParam,
  11289. int Params, TFileOperationProgressType * OperationProgress, unsigned int Flags)
  11290. {
  11291. UnicodeString DestDirectoryName = CopyParam->ChangeFileName(
  11292. ExtractFileName(ExcludeTrailingBackslash(DirectoryName), false), osLocal,
  11293. FLAGSET(Flags, tfFirstLevel));
  11294. UnicodeString DestFullName = UnixIncludeTrailingBackslash(TargetDir + DestDirectoryName);
  11295. // create DestFullName if it does not exist
  11296. int IsDir = 0;
  11297. bool Exists = WebDAVCheckExisting(DestFullName.c_str(), IsDir);
  11298. if (!Exists)
  11299. {
  11300. CreateDirectory(DestFullName);
  11301. }
  11302. OperationProgress->SetFile(DirectoryName);
  11303. WIN32_FIND_DATA SearchRec;
  11304. bool FindOK = false;
  11305. HANDLE findHandle = 0;
  11306. UnicodeString FindPath = DirectoryName + L"*.*";
  11307. FILE_OPERATION_LOOP (FMTLOAD(LIST_DIR_ERROR, (DirectoryName.c_str())),
  11308. findHandle = FindFirstFile(FindPath.c_str(), &SearchRec);
  11309. FindOK = (findHandle != 0);
  11310. if (!FindOK)
  11311. {
  11312. FindCheck(GetLastError(), FindPath);
  11313. }
  11314. );
  11315. bool CreateDir = true;
  11316. try
  11317. {
  11318. while (FindOK && !OperationProgress->Cancel)
  11319. {
  11320. UnicodeString FileName = DirectoryName + SearchRec.cFileName;
  11321. try
  11322. {
  11323. if ((wcscmp(SearchRec.cFileName, THISDIRECTORY) != 0) && (wcscmp(SearchRec.cFileName, PARENTDIRECTORY) != 0))
  11324. {
  11325. WebDAVSourceRobust(FileName, DestFullName, CopyParam, Params, OperationProgress,
  11326. Flags & ~(tfFirstLevel | tfAutoResume));
  11327. // if any file got uploaded (i.e. there were any file in the
  11328. // directory and at least one was not skipped),
  11329. // do not try to create the directory,
  11330. // as it should be already created by FZAPI during upload
  11331. CreateDir = false;
  11332. }
  11333. }
  11334. catch (EScpSkipFile & E)
  11335. {
  11336. // If ESkipFile occurs, just log it and continue with next file
  11337. SUSPEND_OPERATION (
  11338. // here a message to user was displayed, which was not appropriate
  11339. // when user refused to overwrite the file in subdirectory.
  11340. // hopefully it won't be missing in other situations.
  11341. if (!FTerminal->HandleException(&E))
  11342. {
  11343. throw;
  11344. }
  11345. );
  11346. }
  11347. FILE_OPERATION_LOOP (FMTLOAD(LIST_DIR_ERROR, (DirectoryName.c_str())),
  11348. FindOK = (::FindNextFile(findHandle, &SearchRec) != 0);
  11349. if (!FindOK)
  11350. {
  11351. FindCheck(GetLastError(), FindPath);
  11352. }
  11353. );
  11354. }
  11355. }
  11356. __finally
  11357. {
  11358. ::FindClose(findHandle);
  11359. }
  11360. if (CreateDir)
  11361. {
  11362. TRemoteProperties Properties;
  11363. if (CopyParam->PreserveRights)
  11364. {
  11365. Properties.Valid = TValidProperties() << vpRights;
  11366. Properties.Rights = CopyParam->RemoteFileRights(Attrs);
  11367. }
  11368. try
  11369. {
  11370. FTerminal->SetExceptionOnFail(true);
  11371. try
  11372. {
  11373. FTerminal->CreateDirectory(DestFullName, &Properties);
  11374. }
  11375. __finally
  11376. {
  11377. FTerminal->SetExceptionOnFail(false);
  11378. }
  11379. }
  11380. catch (...)
  11381. {
  11382. TRemoteFile * File = NULL;
  11383. // ignore non-fatal error when the directory already exists
  11384. UnicodeString fn = UnixExcludeTrailingBackslash(DestFullName);
  11385. if (fn.IsEmpty())
  11386. {
  11387. fn = L"/";
  11388. }
  11389. bool Rethrow =
  11390. !FTerminal->GetActive() ||
  11391. !FTerminal->FileExists(fn, &File) ||
  11392. (File && !File->IsDirectory);
  11393. delete File;
  11394. if (Rethrow)
  11395. {
  11396. throw;
  11397. }
  11398. }
  11399. }
  11400. // TODO : Delete also read-only directories.
  11401. // TODO : Show error message on failure.
  11402. if (!OperationProgress->Cancel)
  11403. {
  11404. if (FLAGSET(Params, cpDelete))
  11405. {
  11406. RemoveDir(DirectoryName);
  11407. }
  11408. else if (CopyParam->ClearArchive && FLAGSET(Attrs, faArchive))
  11409. {
  11410. FILE_OPERATION_LOOP (FMTLOAD(CANT_SET_ATTRS, (DirectoryName.c_str())),
  11411. THROWOSIFFALSE(FileSetAttr(DirectoryName, Attrs & ~faArchive) == 0);
  11412. )
  11413. }
  11414. }
  11415. }
  11416. //---------------------------------------------------------------------------
  11417. void __fastcall TWebDAVFileSystem::CopyToLocal(TStrings * FilesToCopy,
  11418. const UnicodeString TargetDir, const TCopyParamType * CopyParam,
  11419. int Params, TFileOperationProgressType * OperationProgress,
  11420. TOnceDoneOperation & OnceDoneOperation)
  11421. {
  11422. Params &= ~cpAppend;
  11423. UnicodeString FullTargetDir = ::IncludeTrailingBackslash(TargetDir);
  11424. int Index = 0;
  11425. while (Index < FilesToCopy->Count && !OperationProgress->Cancel)
  11426. {
  11427. UnicodeString FileName = FilesToCopy->Strings[Index];
  11428. const TRemoteFile * File = dynamic_cast<const TRemoteFile *>(FilesToCopy->Objects[Index]);
  11429. bool Success = false;
  11430. FTerminal->SetExceptionOnFail(true);
  11431. try
  11432. {
  11433. try
  11434. {
  11435. SinkRobust(AbsolutePath(FileName, false), File, FullTargetDir, CopyParam, Params,
  11436. OperationProgress, tfFirstLevel);
  11437. Success = true;
  11438. }
  11439. catch (EScpSkipFile & E)
  11440. {
  11441. SUSPEND_OPERATION (
  11442. if (!FTerminal->HandleException(&E))
  11443. {
  11444. throw;
  11445. }
  11446. );
  11447. }
  11448. }
  11449. __finally
  11450. {
  11451. OperationProgress->Finish(FileName, Success, OnceDoneOperation);
  11452. FTerminal->SetExceptionOnFail(false);
  11453. }
  11454. Index++;
  11455. }
  11456. }
  11457. //---------------------------------------------------------------------------
  11458. void __fastcall TWebDAVFileSystem::SinkRobust(const UnicodeString FileName,
  11459. const TRemoteFile * File, const UnicodeString TargetDir,
  11460. const TCopyParamType * CopyParam, int Params,
  11461. TFileOperationProgressType * OperationProgress, unsigned int Flags)
  11462. {
  11463. // the same in TSFTPFileSystem
  11464. bool Retry;
  11465. TDownloadSessionAction Action(FTerminal->ActionLog);
  11466. do
  11467. {
  11468. Retry = false;
  11469. try
  11470. {
  11471. Sink(FileName, File, TargetDir, CopyParam, Params, OperationProgress,
  11472. Flags, Action);
  11473. }
  11474. catch (Exception & E)
  11475. {
  11476. Retry = true;
  11477. if (FTerminal->GetActive() ||
  11478. !FTerminal->QueryReopen(&E, ropNoReadDirectory, OperationProgress))
  11479. {
  11480. FTerminal->RollbackAction(Action, OperationProgress, &E);
  11481. throw;
  11482. }
  11483. }
  11484. if (Retry)
  11485. {
  11486. OperationProgress->RollbackTransfer();
  11487. Action.Restart();
  11488. assert(File != NULL);
  11489. if (!File->IsDirectory)
  11490. {
  11491. // prevent overwrite confirmations
  11492. Params |= cpNoConfirmation;
  11493. Flags |= tfAutoResume;
  11494. }
  11495. }
  11496. }
  11497. while (Retry);
  11498. }
  11499. //---------------------------------------------------------------------------
  11500. void __fastcall TWebDAVFileSystem::Sink(const UnicodeString FileName,
  11501. const TRemoteFile * File, const UnicodeString TargetDir,
  11502. const TCopyParamType * CopyParam, int Params,
  11503. TFileOperationProgressType * OperationProgress, unsigned int Flags,
  11504. TDownloadSessionAction & Action)
  11505. {
  11506. UnicodeString FileNameOnly = UnixExtractFileName(FileName);
  11507. Action.FileName(FileName);
  11508. assert(File);
  11509. TFileMasks::TParams MaskParams;
  11510. MaskParams.Size = File->Size;
  11511. if (!CopyParam->AllowTransfer(FileName, osRemote, File->IsDirectory, MaskParams))
  11512. {
  11513. FTerminal->LogEvent(FORMAT(L"File \"%s\" excluded from transfer", (FileName.c_str())));
  11514. THROW_SKIP_FILE_NULL;
  11515. }
  11516. FTerminal->LogFileDetails(FileName, TDateTime(), File->Size);
  11517. OperationProgress->SetFile(FileNameOnly);
  11518. UnicodeString DestFileName = CopyParam->ChangeFileName(FileNameOnly,
  11519. osRemote, FLAGSET(Flags, tfFirstLevel));
  11520. UnicodeString DestFullName = TargetDir + DestFileName;
  11521. if (File->IsDirectory)
  11522. {
  11523. bool CanProceed = true;
  11524. if (::DirectoryExists(DestFullName))
  11525. {
  11526. unsigned int Answer = 0;
  11527. UnicodeString Message = FMTLOAD(DIRECTORY_OVERWRITE, (FileNameOnly.c_str()));
  11528. TQueryParams QueryParams(qpNeverAskAgainCheck);
  11529. SUSPEND_OPERATION (
  11530. Answer = FTerminal->ConfirmFileOverwrite(
  11531. FileNameOnly /*not used*/, NULL,
  11532. qaYes | qaNo | qaCancel | qaYesToAll | qaNoToAll,
  11533. &QueryParams, osRemote, CopyParam, Params, OperationProgress, Message);
  11534. );
  11535. switch (Answer)
  11536. {
  11537. case qaCancel:
  11538. OperationProgress->Cancel = csCancel; // continue on next case
  11539. // FALLTHROUGH
  11540. case qaNo:
  11541. CanProceed = false;
  11542. default:
  11543. break;
  11544. }
  11545. }
  11546. if (CanProceed)
  11547. {
  11548. Action.Cancel();
  11549. if (!File->IsSymLink)
  11550. {
  11551. FILE_OPERATION_LOOP (FMTLOAD(NOT_DIRECTORY_ERROR, (DestFullName.c_str())),
  11552. int Attrs = FileGetAttr(DestFullName);
  11553. if (FLAGCLEAR(Attrs, faDirectory)) { EXCEPTION; }
  11554. );
  11555. FILE_OPERATION_LOOP (FMTLOAD(CREATE_DIR_ERROR, (DestFullName.c_str())),
  11556. THROWOSIFFALSE(ForceDirectories(DestFullName));
  11557. );
  11558. TSinkFileParams SinkFileParams;
  11559. SinkFileParams.TargetDir = ::IncludeTrailingBackslash(DestFullName);
  11560. SinkFileParams.CopyParam = CopyParam;
  11561. SinkFileParams.Params = Params;
  11562. SinkFileParams.OperationProgress = OperationProgress;
  11563. SinkFileParams.Skipped = false;
  11564. SinkFileParams.Flags = Flags & ~(tfFirstLevel | tfAutoResume);
  11565. FTerminal->ProcessDirectory(FileName, SinkFile, &SinkFileParams);
  11566. // Do not delete directory if some of its files were skip.
  11567. // Throw "skip file" for the directory to avoid attempt to deletion
  11568. // of any parent directory
  11569. if (FLAGSET(Params, cpDelete) && SinkFileParams.Skipped)
  11570. {
  11571. THROW_SKIP_FILE_NULL;
  11572. }
  11573. }
  11574. else
  11575. {
  11576. // file is symlink to directory, currently do nothing, but it should be
  11577. // reported to user
  11578. }
  11579. }
  11580. }
  11581. else
  11582. {
  11583. FTerminal->LogEvent(FORMAT(L"Copying \"%s\" to local directory started.", (FileName.c_str())));
  11584. bool CanProceed = true;
  11585. if (FileExists(DestFullName))
  11586. {
  11587. __int64 Size;
  11588. __int64 MTime;
  11589. FTerminal->OpenLocalFile(DestFullName, GENERIC_READ, NULL,
  11590. NULL, NULL, &MTime, NULL, &Size);
  11591. TOverwriteFileParams FileParams;
  11592. FileParams.SourceSize = File->Size;
  11593. FileParams.SourceTimestamp = File->Modification;
  11594. FileParams.DestSize = Size;
  11595. FileParams.DestTimestamp = UnixToDateTime(MTime,
  11596. FTerminal->SessionData->DSTMode);
  11597. unsigned int Answer = 0;
  11598. TOverwriteMode OverwriteMode = omOverwrite;
  11599. bool AutoResume = false;
  11600. ConfirmOverwrite(DestFullName, OverwriteMode, OperationProgress,
  11601. &FileParams, CopyParam, Params, AutoResume, Answer);
  11602. switch (Answer)
  11603. {
  11604. case qaCancel:
  11605. OperationProgress->Cancel = csCancel; // continue on next case
  11606. // FALLTHROUGH
  11607. case qaNo:
  11608. CanProceed = false;
  11609. default:
  11610. break;
  11611. }
  11612. }
  11613. if (CanProceed)
  11614. {
  11615. // Suppose same data size to transfer as to write
  11616. OperationProgress->SetTransferSize(File->Size);
  11617. OperationProgress->SetLocalSize(OperationProgress->TransferSize);
  11618. int Attrs = -1;
  11619. FILE_OPERATION_LOOP (FMTLOAD(NOT_FILE_ERROR, (DestFullName.c_str())),
  11620. Attrs = FileGetAttr(DestFullName);
  11621. if ((Attrs >= 0) && FLAGSET(Attrs, faDirectory)) { EXCEPTION; }
  11622. );
  11623. OperationProgress->TransferingFile = false; // not set with FTP protocol
  11624. ResetFileTransfer();
  11625. TFileTransferData UserData;
  11626. UnicodeString FilePath = ::UnixExtractFilePath(FileName);
  11627. if (FilePath.IsEmpty())
  11628. {
  11629. FilePath = L"/";
  11630. }
  11631. {
  11632. unsigned int TransferType = 2;
  11633. // ignore file list
  11634. TWebDAVFileListHelper Helper(this, NULL, true);
  11635. FFileTransferCPSLimit = OperationProgress->CPSLimit;
  11636. FFileTransferPreserveTime = CopyParam->PreserveTime;
  11637. UserData.FileName = DestFileName;
  11638. UserData.Params = Params;
  11639. UserData.AutoResume = FLAGSET(Flags, tfAutoResume);
  11640. UserData.CopyParam = CopyParam;
  11641. FileTransfer(FileName, DestFullName, FileNameOnly,
  11642. FilePath, true, File->Size, TransferType, UserData, OperationProgress);
  11643. }
  11644. // in case dest filename is changed from overwrite dialog
  11645. if (DestFileName != UserData.FileName)
  11646. {
  11647. DestFullName = TargetDir + UserData.FileName;
  11648. Attrs = FileGetAttr(DestFullName);
  11649. }
  11650. Action.Destination(ExpandUNCFileName(DestFullName));
  11651. if (Attrs == -1)
  11652. {
  11653. Attrs = faArchive;
  11654. }
  11655. int NewAttrs = CopyParam->LocalFileAttrs(*File->Rights);
  11656. if ((NewAttrs & Attrs) != NewAttrs)
  11657. {
  11658. FILE_OPERATION_LOOP (FMTLOAD(CANT_SET_ATTRS, (DestFullName.c_str())),
  11659. THROWOSIFFALSE(FileSetAttr(DestFullName, Attrs | NewAttrs) == 0);
  11660. );
  11661. }
  11662. // set time
  11663. {
  11664. FILE_OPERATION_LOOP (FMTLOAD(CANT_SET_ATTRS, (DestFullName.c_str())),
  11665. HANDLE Handle;
  11666. Handle = CreateFile(DestFullName.c_str(), GENERIC_WRITE,
  11667. FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
  11668. FILETIME WrTime = DateTimeToFileTime(File->Modification,
  11669. FTerminal->SessionData->DSTMode);
  11670. bool Result = SetFileTime(Handle, &WrTime, &WrTime, &WrTime) > 0;
  11671. CloseHandle(Handle);
  11672. if (!Result)
  11673. {
  11674. Abort();
  11675. }
  11676. );
  11677. }
  11678. }
  11679. }
  11680. if (FLAGSET(Params, cpDelete))
  11681. {
  11682. // If file is directory, do not delete it recursively, because it should be
  11683. // empty already. If not, it should not be deleted (some files were
  11684. // skipped or some new files were copied to it, while we were downloading)
  11685. int Params = dfNoRecursive;
  11686. FTerminal->DeleteFile(FileName, File, &Params);
  11687. }
  11688. }
  11689. //---------------------------------------------------------------------------
  11690. void __fastcall TWebDAVFileSystem::SinkFile(const UnicodeString FileName,
  11691. const TRemoteFile * File, void * Param)
  11692. {
  11693. TSinkFileParams * Params = static_cast<TSinkFileParams *>(Param);
  11694. assert(Params->OperationProgress);
  11695. try
  11696. {
  11697. SinkRobust(FileName, File, Params->TargetDir, Params->CopyParam,
  11698. Params->Params, Params->OperationProgress, Params->Flags);
  11699. }
  11700. catch (EScpSkipFile & E)
  11701. {
  11702. TFileOperationProgressType * OperationProgress = Params->OperationProgress;
  11703. Params->Skipped = true;
  11704. SUSPEND_OPERATION (
  11705. if (!FTerminal->HandleException(&E))
  11706. {
  11707. throw;
  11708. }
  11709. );
  11710. if (OperationProgress->Cancel)
  11711. {
  11712. Abort();
  11713. }
  11714. }
  11715. }
  11716. //---------------------------------------------------------------------------
  11717. bool __fastcall TWebDAVFileSystem::HandleListData(const wchar_t * Path,
  11718. const TListDataEntry * Entries, unsigned int Count)
  11719. {
  11720. if (!FActive)
  11721. {
  11722. return false;
  11723. }
  11724. else if (FIgnoreFileList)
  11725. {
  11726. // directory listing provided implicitly by FZAPI during certain operations is ignored
  11727. assert(FFileList == NULL);
  11728. return false;
  11729. }
  11730. else
  11731. {
  11732. assert(FFileList != NULL);
  11733. // this can actually fail in real life,
  11734. // when connected to server with case insensitive paths
  11735. assert(UnixComparePaths(AbsolutePath(FFileList->Directory, false), Path));
  11736. USEDPARAM(Path);
  11737. for (size_t Index = 0; Index < Count; Index++)
  11738. {
  11739. const TListDataEntry * Entry = &Entries[Index];
  11740. TRemoteFile * File = new TRemoteFile();
  11741. try
  11742. {
  11743. File->Terminal = FTerminal;
  11744. File->FileName = UnicodeString(Entry->Name);
  11745. if (wcslen(Entry->Permissions) >= 10)
  11746. {
  11747. try
  11748. {
  11749. File->Rights->Text = Entry->Permissions + 1;
  11750. }
  11751. catch (...)
  11752. {
  11753. // ignore permissions errors with WebDAV
  11754. }
  11755. }
  11756. // FIXME
  11757. UnicodeString own = Entry->OwnerGroup;
  11758. const wchar_t * Space = wcschr(own.c_str(), ' ');
  11759. if (Space != NULL)
  11760. {
  11761. File->Owner.Name = UnicodeString(own.c_str(), Space - own.c_str());
  11762. File->Group.Name = Space + 1;
  11763. }
  11764. else
  11765. {
  11766. File->Owner.Name = Entry->OwnerGroup;
  11767. }
  11768. File->Size = Entry->Size;
  11769. if (Entry->Link)
  11770. {
  11771. File->Type = FILETYPE_SYMLINK;
  11772. }
  11773. else if (Entry->Dir)
  11774. {
  11775. File->Type = FILETYPE_DIRECTORY;
  11776. }
  11777. else
  11778. {
  11779. File->Type = L'-';
  11780. }
  11781. // ModificationFmt must be set after Modification
  11782. if (Entry->Time.HasDate)
  11783. {
  11784. // should be the same as ConvertRemoteTimestamp
  11785. TDateTime Modification =
  11786. EncodeDateVerbose(static_cast<unsigned short>(Entry->Time.Year), static_cast<unsigned short>(Entry->Time.Month),
  11787. static_cast<unsigned short>(Entry->Time.Day));
  11788. if (Entry->Time.HasTime)
  11789. {
  11790. unsigned short seconds = 0;
  11791. if (Entry->Time.HasSeconds)
  11792. seconds = static_cast<unsigned short>(Entry->Time.Second);
  11793. File->Modification = Modification +
  11794. EncodeTimeVerbose(static_cast<unsigned short>(Entry->Time.Hour),
  11795. static_cast<unsigned short>(Entry->Time.Minute),
  11796. seconds, 0);
  11797. // not exact as we got year as well, but it is most probably
  11798. // guessed by FZAPI anyway
  11799. File->ModificationFmt = mfMDHM;
  11800. }
  11801. else
  11802. {
  11803. File->Modification = Modification;
  11804. File->ModificationFmt = mfMDY;
  11805. }
  11806. }
  11807. else
  11808. {
  11809. // We estimate date to be today, if we have at least time
  11810. File->Modification = TDateTime(0.0);
  11811. File->ModificationFmt = mfNone;
  11812. }
  11813. File->LastAccess = File->Modification;
  11814. File->LinkTo = Entry->LinkTarget;
  11815. File->Complete();
  11816. }
  11817. catch (Exception & E)
  11818. {
  11819. delete File;
  11820. UnicodeString EntryData =
  11821. FORMAT(L"%s/%s/%s/%lld/%d/%d/%d/%d/%d/%d/%d/%d/%d",
  11822. (Entry->Name,
  11823. Entry->Permissions,
  11824. Entry->OwnerGroup,
  11825. Entry->Size,
  11826. int(Entry->Dir), int(Entry->Link), Entry->Time.Year, Entry->Time.Month, Entry->Time.Day,
  11827. Entry->Time.Hour, Entry->Time.Minute, int(Entry->Time.HasTime), int(Entry->Time.HasDate)));
  11828. throw ETerminal(&E, FMTLOAD(LIST_LINE_ERROR, (EntryData.c_str())), HELP_LIST_LINE_ERROR);
  11829. }
  11830. FFileList->AddFile(File);
  11831. }
  11832. return true;
  11833. }
  11834. }
  11835. //---------------------------------------------------------------------------
  11836. void __fastcall TWebDAVFileSystem::ResetFileTransfer()
  11837. {
  11838. FFileTransferAbort = ftaNone;
  11839. FFileTransferCancelled = false;
  11840. FFileTransferResumed = 0;
  11841. webdav::cancelled = FALSE;
  11842. }
  11843. //---------------------------------------------------------------------------
  11844. void __fastcall TWebDAVFileSystem::ReadDirectoryProgress(__int64 Bytes)
  11845. {
  11846. // with WebDAV we do not know exactly how many entries we have received,
  11847. // instead we know number of bytes received only.
  11848. // so we report approximation based on average size of entry.
  11849. size_t Progress = static_cast<size_t>(Bytes / 80);
  11850. if (Progress - FLastReadDirectoryProgress >= 10)
  11851. {
  11852. bool Cancel = false;
  11853. FLastReadDirectoryProgress = Progress;
  11854. FTerminal->DoReadDirectoryProgress(Progress, Cancel);
  11855. if (Cancel)
  11856. {
  11857. FTerminal->DoReadDirectoryProgress(-2, Cancel);
  11858. }
  11859. }
  11860. }
  11861. //---------------------------------------------------------------------------
  11862. void __fastcall TWebDAVFileSystem::DoFileTransferProgress(__int64 TransferSize,
  11863. __int64 Bytes)
  11864. {
  11865. TFileOperationProgressType * OperationProgress = FTerminal->OperationProgress;
  11866. if (!OperationProgress) return;
  11867. OperationProgress->SetTransferSize(TransferSize);
  11868. if (FFileTransferResumed > 0)
  11869. {
  11870. OperationProgress->AddResumed(FFileTransferResumed);
  11871. FFileTransferResumed = 0;
  11872. }
  11873. __int64 Diff = Bytes - OperationProgress->TransferedSize;
  11874. if (Diff >= 0)
  11875. {
  11876. OperationProgress->AddTransfered(Diff);
  11877. }
  11878. if (OperationProgress->Cancel == csCancel)
  11879. {
  11880. FFileTransferCancelled = true;
  11881. FFileTransferAbort = ftaCancel;
  11882. }
  11883. if (FFileTransferCPSLimit != OperationProgress->CPSLimit)
  11884. {
  11885. FFileTransferCPSLimit = OperationProgress->CPSLimit;
  11886. }
  11887. }
  11888. //---------------------------------------------------------------------------
  11889. void __fastcall TWebDAVFileSystem::FileTransferProgress(__int64 TransferSize,
  11890. __int64 Bytes)
  11891. {
  11892. TGuard Guard(FTransferStatusCriticalSection);
  11893. DoFileTransferProgress(TransferSize, Bytes);
  11894. }
  11895. //---------------------------------------------------------------------------
  11896. void __fastcall TWebDAVFileSystem::FileTransfer(const UnicodeString FileName,
  11897. const UnicodeString LocalFile, const UnicodeString RemoteFile,
  11898. const UnicodeString RemotePath, bool Get, __int64 Size, int Type,
  11899. TFileTransferData & UserData, TFileOperationProgressType * OperationProgress)
  11900. {
  11901. FCurrentOperationProgress = OperationProgress;
  11902. FILE_OPERATION_LOOP (FMTLOAD(TRANSFER_ERROR, (FileName.c_str())),
  11903. UnicodeString FullRemoteFileName = RemotePath + RemoteFile;
  11904. bool Result = false;
  11905. if (Get)
  11906. {
  11907. HANDLE LocalFileHandle = 0;
  11908. FTerminal->CreateLocalFile(LocalFile,
  11909. OperationProgress, &LocalFileHandle, true);
  11910. Result = WebDAVGetFile(FullRemoteFileName.c_str(), &LocalFileHandle);
  11911. if (!Result)
  11912. {
  11913. ::CloseHandle(LocalFileHandle);
  11914. }
  11915. }
  11916. else
  11917. {
  11918. Result = WebDAVPutFile(FullRemoteFileName.c_str(), LocalFile.c_str(), Size);
  11919. }
  11920. if (!Result)
  11921. EXCEPTION;
  11922. );
  11923. switch (FFileTransferAbort)
  11924. {
  11925. case ftaSkip:
  11926. THROW_SKIP_FILE(NULL, L"");
  11927. case ftaCancel:
  11928. Abort();
  11929. break;
  11930. }
  11931. if (!FFileTransferCancelled)
  11932. {
  11933. // show completion of transfer
  11934. // call non-guarded variant to avoid deadlock with keepalives
  11935. // (we are not waiting for reply anymore so keepalives are free to proceed)
  11936. DoFileTransferProgress(OperationProgress->TransferSize, OperationProgress->TransferSize);
  11937. }
  11938. }
  11939. bool TWebDAVFileSystem::SendPropFindRequest(const wchar_t * path, int & responseCode)
  11940. {
  11941. assert(path);
  11942. assert(FSession);
  11943. apr_pool_t * pool = webdav_pool_create(webdav_pool);
  11944. webdav::error_t err = 0;
  11945. const char * remote_path = NULL;
  11946. err = webdav::path_cstring_to_utf8(&remote_path, AnsiString(path).c_str(), pool);
  11947. if (err) return false;
  11948. err = webdav::client_send_propfind_request(
  11949. FSession,
  11950. remote_path,
  11951. &responseCode,
  11952. pool
  11953. );
  11954. webdav_pool_destroy(pool);
  11955. return err == WEBDAV_NO_ERROR;
  11956. }
  11957. bool TWebDAVFileSystem::WebDAVCheckExisting(const wchar_t * path, int & is_dir)
  11958. {
  11959. assert(path);
  11960. is_dir = 0;
  11961. assert(FSession);
  11962. apr_pool_t * pool = webdav_pool_create(webdav_pool);
  11963. webdav::error_t err = 0;
  11964. webdav::node_kind_t kind = webdav::node_none;
  11965. const char * remote_path = NULL;
  11966. err = webdav::path_cstring_to_utf8(&remote_path, AnsiString(path).c_str(), pool);
  11967. if (err) return false;
  11968. err = webdav::client_check_path(
  11969. FSession,
  11970. remote_path,
  11971. &kind,
  11972. pool
  11973. );
  11974. if (kind != webdav::node_none)
  11975. is_dir = kind == webdav::node_dir;
  11976. webdav_pool_destroy(pool);
  11977. return (err == WEBDAV_NO_ERROR) && (kind != webdav::node_none);
  11978. }
  11979. bool TWebDAVFileSystem::WebDAVMakeDirectory(const wchar_t * path)
  11980. {
  11981. assert(path);
  11982. assert(FSession);
  11983. apr_pool_t * pool = webdav_pool_create(webdav_pool);
  11984. webdav::error_t err = 0;
  11985. const char * remote_path = NULL;
  11986. err = webdav::path_cstring_to_utf8(&remote_path, AnsiString(path).c_str(), pool);
  11987. if (err) return false;
  11988. err = webdav::client_make_directory(
  11989. FSession,
  11990. remote_path,
  11991. NULL,
  11992. pool
  11993. );
  11994. webdav_pool_destroy(pool);
  11995. return err == WEBDAV_NO_ERROR;
  11996. }
  11997. bool TWebDAVFileSystem::WebDAVGetList(const UnicodeString Directory)
  11998. {
  11999. webdav::listdataentry_vector_t Entries;
  12000. assert(FSession);
  12001. webdav::list_func_baton_t baton = {0};
  12002. baton.verbose = true;
  12003. baton.entries = &Entries;
  12004. baton.session = FSession;
  12005. baton.pool = webdav_pool_create(webdav_pool);
  12006. webdav::error_t err = 0;
  12007. const char * remote_path = NULL;
  12008. err = webdav::path_cstring_to_utf8(&remote_path, AnsiString(Directory).c_str(), baton.pool);
  12009. if (err) return false;
  12010. err = webdav::client_list2(
  12011. FSession,
  12012. remote_path,
  12013. webdav::depth_immediates,
  12014. WEBDAV_DIRENT_ALL,
  12015. webdav::list_func,
  12016. &baton,
  12017. baton.pool
  12018. );
  12019. TListDataEntry * pEntries = !Entries.empty() ? &Entries[0] : NULL;
  12020. HandleListData(Directory.c_str(), pEntries, Entries.size());
  12021. webdav_pool_destroy(baton.pool);
  12022. return err == WEBDAV_NO_ERROR;
  12023. }
  12024. bool TWebDAVFileSystem::WebDAVGetFile(const wchar_t * remotePath,
  12025. HANDLE * LocalFileHandle)
  12026. {
  12027. assert(remotePath && *remotePath);
  12028. assert(LocalFileHandle);
  12029. assert(FSession);
  12030. apr_pool_t * pool = webdav_pool_create(webdav_pool);
  12031. webdav::error_t err = 0;
  12032. const char * remote_path = NULL;
  12033. err = webdav::path_cstring_to_utf8(&remote_path, AnsiString(remotePath).c_str(), pool);
  12034. if (err) return false;
  12035. err = webdav::client_get_file(
  12036. FSession,
  12037. remote_path,
  12038. LocalFileHandle,
  12039. pool);
  12040. webdav_pool_destroy(pool);
  12041. return err == WEBDAV_NO_ERROR;
  12042. }
  12043. bool TWebDAVFileSystem::WebDAVPutFile(const wchar_t * remotePath, const wchar_t * localPath, const unsigned __int64 /*fileSize*/)
  12044. {
  12045. assert(remotePath && *remotePath);
  12046. assert(localPath && *localPath);
  12047. assert(FSession);
  12048. apr_pool_t * pool = webdav_pool_create(webdav_pool);
  12049. webdav::error_t err = 0;
  12050. const char * remote_path = NULL;
  12051. const char * local_path = NULL;
  12052. err = webdav::path_cstring_to_utf8(&remote_path, AnsiString(remotePath).c_str(), pool);
  12053. if (err) return false;
  12054. err = webdav::path_cstring_to_utf8(&local_path, AnsiString(localPath).c_str(), pool);
  12055. if (err) return false;
  12056. err = webdav::client_put_file(
  12057. FSession,
  12058. remote_path,
  12059. local_path,
  12060. pool
  12061. );
  12062. webdav_pool_destroy(pool);
  12063. return err == WEBDAV_NO_ERROR;
  12064. }
  12065. bool TWebDAVFileSystem::WebDAVRenameFile(const wchar_t * srcPath, const wchar_t * dstPath)
  12066. {
  12067. assert(srcPath && *srcPath);
  12068. assert(dstPath && *dstPath);
  12069. assert(FSession);
  12070. apr_pool_t * pool = webdav_pool_create(webdav_pool);
  12071. webdav::error_t err = 0;
  12072. const char * src_path = NULL;
  12073. const char * dst_path = NULL;
  12074. err = webdav::path_cstring_to_utf8(&src_path, AnsiString(srcPath).c_str(), pool);
  12075. if (err) return false;
  12076. err = webdav::path_cstring_to_utf8(&dst_path, AnsiString(dstPath).c_str(), pool);
  12077. if (err) return false;
  12078. err = webdav::client_move_file_or_directory(
  12079. FSession,
  12080. src_path,
  12081. dst_path,
  12082. NULL,
  12083. pool
  12084. );
  12085. webdav_pool_destroy(pool);
  12086. return err == WEBDAV_NO_ERROR;
  12087. }
  12088. bool TWebDAVFileSystem::WebDAVDeleteFile(const wchar_t * path)
  12089. {
  12090. assert(path);
  12091. assert(FSession);
  12092. apr_pool_t * pool = webdav_pool_create(webdav_pool);
  12093. webdav::error_t err = 0;
  12094. const char * remote_path = NULL;
  12095. err = webdav::path_cstring_to_utf8(&remote_path, AnsiString(path).c_str(), pool);
  12096. if (err) return false;
  12097. err = webdav::client_delete_file(
  12098. FSession,
  12099. remote_path,
  12100. NULL,
  12101. pool
  12102. );
  12103. webdav_pool_destroy(pool);
  12104. return err == WEBDAV_NO_ERROR;
  12105. }
  12106. webdav::error_t TWebDAVFileSystem::OpenURL(const UnicodeString & session_URL,
  12107. apr_pool_t * pool)
  12108. {
  12109. webdav::client_ctx_t * ctx = NULL;
  12110. WEBDAV_ERR(client_create_context(&ctx, pool));
  12111. const char * auth_username = NULL;
  12112. const char * auth_password = NULL;
  12113. WEBDAV_ERR(webdav::utf_cstring_to_utf8(&auth_username,
  12114. AnsiString(FTerminal->SessionData->UserNameExpanded).c_str(), pool));
  12115. WEBDAV_ERR(webdav::utf_cstring_to_utf8(&auth_password,
  12116. AnsiString(FTerminal->SessionData->Password).c_str(), pool));
  12117. webdav::auth_baton_t * ab = NULL;
  12118. webdav::auth_baton_create(&ab, pool);
  12119. webdav::auth_baton_init(ab,
  12120. FALSE, // non_interactive
  12121. auth_username,
  12122. auth_password,
  12123. FALSE, // no_auth_cache
  12124. TRUE, // trust_server_cert
  12125. this,
  12126. webdav::check_cancel, ab,
  12127. pool);
  12128. ctx->auth_baton = ab;
  12129. // Set up our cancellation support.
  12130. ctx->cancel_func = webdav::check_cancel;
  12131. ctx->cancel_baton = ab;
  12132. ctx->progress_func = webdav::progress_func;
  12133. ctx->progress_baton = ctx;
  12134. webdav::session_t * session_p = NULL;
  12135. const char * corrected_url = NULL;
  12136. AnsiString base_url = AnsiString(session_URL).c_str();
  12137. const char * base_url_encoded = webdav::path_uri_encode(base_url.c_str(), pool);
  12138. WEBDAV_ERR(webdav::client_open_session_internal(
  12139. &session_p,
  12140. &corrected_url,
  12141. base_url_encoded,
  12142. ctx,
  12143. pool));
  12144. const char * url = NULL;
  12145. if (corrected_url)
  12146. {
  12147. url = apr_pstrdup(pool, corrected_url);
  12148. }
  12149. else
  12150. {
  12151. url = apr_pstrdup(pool, base_url_encoded);
  12152. }
  12153. ne_uri * uri = NULL;
  12154. if (WEBDAV_NO_ERROR == webdav::parse_ne_uri(&uri, url, pool))
  12155. {
  12156. FCurrentDirectory = uri->path;
  12157. FHasTrailingSlash = (FCurrentDirectory.Length() > 0) && (FCurrentDirectory[FCurrentDirectory.Length()] == L'/');
  12158. }
  12159. FSession = session_p;
  12160. return WEBDAV_NO_ERROR;
  12161. }
  12162. //---------------------------------------------------------------------------
  12163. webdav::error_t TWebDAVFileSystem::GetServerSettings(
  12164. int * proxy_method,
  12165. const char ** proxy_host,
  12166. unsigned int * proxy_port,
  12167. const char ** proxy_username,
  12168. const char ** proxy_password,
  12169. int * timeout_seconds,
  12170. int * neon_debug,
  12171. const char ** neon_debug_file_name,
  12172. bool * compression,
  12173. const char ** pk11_provider,
  12174. const char ** ssl_authority_file,
  12175. apr_pool_t * pool)
  12176. {
  12177. // If we find nothing, default to nulls.
  12178. *proxy_method = 0;
  12179. *proxy_host = NULL;
  12180. *proxy_port = (unsigned int)-1;
  12181. *proxy_username = NULL;
  12182. *proxy_password = NULL;
  12183. *pk11_provider = NULL;
  12184. *ssl_authority_file = NULL;
  12185. TSessionData * Data = FTerminal->SessionData;
  12186. TConfiguration * Configuration = FTerminal->Configuration;
  12187. {
  12188. TProxyMethod ProxyMethod = Data->ProxyMethod;
  12189. *proxy_method = (int)ProxyMethod;
  12190. if (ProxyMethod != (TProxyMethod)::pmNone)
  12191. {
  12192. WEBDAV_ERR(webdav::path_cstring_to_utf8(proxy_host, AnsiString(Data->ProxyHost).c_str(), pool));
  12193. WEBDAV_ERR(webdav::path_cstring_to_utf8(proxy_username, AnsiString(Data->ProxyUsername).c_str(), pool));
  12194. WEBDAV_ERR(webdav::path_cstring_to_utf8(proxy_password, AnsiString(Data->ProxyPassword).c_str(), pool));
  12195. }
  12196. }
  12197. // Apply non-proxy-specific settings regardless of exceptions:
  12198. if (compression)
  12199. *compression = Data->Compression;
  12200. int l_debug = Configuration->ActualLogProtocol >= 1 ? 1 : 0;
  12201. *pk11_provider = "";
  12202. *ssl_authority_file = apr_pstrdup(pool, AnsiString(Data->PublicKeyFile).c_str());
  12203. {
  12204. int l_proxy_port = Data->ProxyPort;
  12205. if (l_proxy_port < 0)
  12206. {
  12207. return webdav::error_create(WEBDAV_ERR_ILLEGAL_URL, NULL,
  12208. "Invalid URL: negative proxy port number");
  12209. }
  12210. if (l_proxy_port > 65535)
  12211. {
  12212. return webdav::error_create(WEBDAV_ERR_ILLEGAL_URL, NULL,
  12213. "Invalid URL: proxy port number greater "
  12214. "than maximum TCP port number 65535");
  12215. }
  12216. *proxy_port = l_proxy_port;
  12217. }
  12218. {
  12219. int l_timeout = Data->Timeout;
  12220. if (l_timeout < 0)
  12221. return webdav::error_create(WEBDAV_ERR_BAD_CONFIG_VALUE, NULL,
  12222. "Invalid config: negative timeout value");
  12223. *timeout_seconds = l_timeout;
  12224. }
  12225. if (l_debug)
  12226. {
  12227. *neon_debug = l_debug;
  12228. if (Configuration->LogToFile)
  12229. {
  12230. WEBDAV_ERR(webdav::path_cstring_to_utf8(neon_debug_file_name,
  12231. AnsiString(GetExpandedLogFileName(
  12232. Configuration->LogFileName,
  12233. Data)).c_str(), pool));
  12234. }
  12235. else
  12236. {
  12237. *neon_debug_file_name = NULL;
  12238. }
  12239. }
  12240. else
  12241. {
  12242. *neon_debug = 0;
  12243. *neon_debug_file_name = NULL;
  12244. }
  12245. return WEBDAV_NO_ERROR;
  12246. }
  12247. webdav::error_t TWebDAVFileSystem::VerifyCertificate(
  12248. const char * Prompt, const char * fingerprint,
  12249. unsigned int & RequestResult)
  12250. {
  12251. RequestResult = 0;
  12252. TClipboardHandler ClipboardHandler;
  12253. ClipboardHandler.Text = fingerprint;
  12254. TQueryButtonAlias Aliases[1];
  12255. Aliases[0].Button = qaRetry;
  12256. Aliases[0].Alias = LoadStr(COPY_KEY_BUTTON);
  12257. Aliases[0].OnClick = &ClipboardHandler.Copy;
  12258. TQueryParams Params;
  12259. Params.HelpKeyword = HELP_VERIFY_CERTIFICATE;
  12260. Params.NoBatchAnswers = qaYes | qaRetry;
  12261. Params.Aliases = Aliases;
  12262. Params.AliasesCount = LENOF(Aliases);
  12263. unsigned int Answer = FTerminal->QueryUser(
  12264. FMTLOAD(VERIFY_CERT_PROMPT3, (UnicodeString(Prompt).c_str())),
  12265. NULL, qaYes | qaNo | qaCancel | qaRetry, &Params, qtWarning);
  12266. RequestResult = Answer;
  12267. switch (RequestResult)
  12268. {
  12269. case qaCancel:
  12270. FTerminal->Configuration->Usage->Inc(L"HostNotVerified");
  12271. FFileTransferCancelled = true;
  12272. FFileTransferAbort = ftaCancel;
  12273. break;
  12274. }
  12275. return WEBDAV_NO_ERROR;
  12276. }
  12277. webdav::error_t TWebDAVFileSystem::AskForClientCertificateFilename(
  12278. const char ** cert_file, unsigned int & RequestResult,
  12279. apr_pool_t * pool)
  12280. {
  12281. RequestResult = 0;
  12282. TSessionData * Data = FTerminal->SessionData;
  12283. UnicodeString FileName;
  12284. if (!FTerminal->PromptUser(Data, pkFileName, LoadStr(CERT_FILENAME_PROMPT_TITLE), L"",
  12285. LoadStr(CERT_FILENAME_PROMPT), true, 0, FileName))
  12286. {
  12287. FFileTransferCancelled = true;
  12288. FFileTransferAbort = ftaCancel;
  12289. return WEBDAV_ERR_CANCELLED;
  12290. }
  12291. WEBDAV_ERR(webdav::path_cstring_to_utf8(cert_file, AnsiString(FileName).c_str(), pool));
  12292. RequestResult = qaOK;
  12293. return WEBDAV_NO_ERROR;
  12294. }
  12295. webdav::error_t TWebDAVFileSystem::AskForUsername(
  12296. const char ** user_name, unsigned int & RequestResult,
  12297. apr_pool_t * pool)
  12298. {
  12299. RequestResult = 0;
  12300. TSessionData * Data = FTerminal->SessionData;
  12301. UnicodeString UserName = Data->UserNameExpanded;
  12302. if (!FTerminal->PromptUser(Data, pkUserName, LoadStr(USERNAME_TITLE), L"",
  12303. LoadStr(USERNAME_PROMPT2), true, 0, UserName))
  12304. {
  12305. FFileTransferCancelled = true;
  12306. FFileTransferAbort = ftaCancel;
  12307. return WEBDAV_ERR_CANCELLED;
  12308. }
  12309. WEBDAV_ERR(webdav::path_cstring_to_utf8(user_name, AnsiString(UserName).c_str(), pool));
  12310. RequestResult = qaOK;
  12311. return WEBDAV_NO_ERROR;
  12312. }
  12313. webdav::error_t TWebDAVFileSystem::AskForUserPassword(
  12314. const char ** password,
  12315. unsigned int & RequestResult,
  12316. apr_pool_t * pool)
  12317. {
  12318. RequestResult = 0;
  12319. TSessionData * Data = FTerminal->SessionData;
  12320. UnicodeString Password = Data->Password;
  12321. if (!FTerminal->PromptUser(Data, pkPassword, LoadStr(PASSWORD_TITLE), L"",
  12322. LoadStr(PASSWORD_PROMPT), false, 0, Password))
  12323. {
  12324. FFileTransferCancelled = true;
  12325. FFileTransferAbort = ftaCancel;
  12326. return WEBDAV_ERR_CANCELLED;
  12327. }
  12328. WEBDAV_ERR(webdav::path_cstring_to_utf8(password, AnsiString(Password).c_str(), pool));
  12329. RequestResult = qaOK;
  12330. return WEBDAV_NO_ERROR;
  12331. }
  12332. //------------------------------------------------------------------------------
  12333. webdav::error_t TWebDAVFileSystem::AskForPassphrase(
  12334. const char ** passphrase,
  12335. const char * realm,
  12336. unsigned int & RequestResult,
  12337. apr_pool_t * pool)
  12338. {
  12339. RequestResult = 0;
  12340. TSessionData * Data = FTerminal->SessionData;
  12341. UnicodeString Passphrase = Data->UserNameExpanded;
  12342. UnicodeString Prompt = FORMAT(LoadStr(PROMPT_KEY_PASSPHRASE), (UnicodeString(realm)));
  12343. if (!FTerminal->PromptUser(Data, pkPassphrase, LoadStr(PASSPHRASE_TITLE), L"",
  12344. Prompt, false, 0, Passphrase))
  12345. {
  12346. FFileTransferCancelled = true;
  12347. FFileTransferAbort = ftaCancel;
  12348. return WEBDAV_ERR_CANCELLED;
  12349. }
  12350. WEBDAV_ERR(webdav::path_cstring_to_utf8(passphrase, AnsiString(Passphrase).c_str(), pool));
  12351. RequestResult = qaOK;
  12352. return WEBDAV_NO_ERROR;
  12353. }
  12354. webdav::error_t TWebDAVFileSystem::SimplePrompt(
  12355. const char * prompt_text,
  12356. const char * prompt_string,
  12357. unsigned int & RequestResult)
  12358. {
  12359. RequestResult = 0;
  12360. TStrings * MoreMessages = new TStringList();
  12361. try
  12362. {
  12363. MoreMessages->Add(UnicodeString(prompt_string));
  12364. unsigned int Answer = FTerminal->QueryUser(
  12365. UnicodeString(prompt_text),
  12366. MoreMessages, qaYes | qaNo | qaCancel, NULL, qtConfirmation);
  12367. RequestResult = Answer;
  12368. }
  12369. __finally
  12370. {
  12371. delete MoreMessages;
  12372. }
  12373. return RequestResult == qaCancel ? WEBDAV_ERR_CANCELLED : WEBDAV_NO_ERROR;
  12374. }
  12375. webdav::error_t TWebDAVFileSystem::CreateStorage(
  12376. THierarchicalStorage *& Storage)
  12377. {
  12378. Storage =
  12379. FTerminal->Configuration->CreateScpStorage(false);
  12380. return WEBDAV_NO_ERROR;
  12381. }
  12382. unsigned long TWebDAVFileSystem::AdjustToCPSLimit(unsigned long len)
  12383. {
  12384. return FCurrentOperationProgress ? FCurrentOperationProgress->AdjustToCPSLimit(len) : len;
  12385. }
  12386. bool TWebDAVFileSystem::GetIsCancelled()
  12387. {
  12388. TFileOperationProgressType * OperationProgress = FCurrentOperationProgress;
  12389. return (OperationProgress && OperationProgress->Cancel == csCancel);
  12390. }
  12391. //------------------------------------------------------------------------------